From owner-svn-src-user@FreeBSD.ORG Mon Jan 4 04:26:03 2010 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3A9341065695; Mon, 4 Jan 2010 04:26:03 +0000 (UTC) (envelope-from kmacy@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 285018FC0A; Mon, 4 Jan 2010 04:26:03 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o044Q39L048987; Mon, 4 Jan 2010 04:26:03 GMT (envelope-from kmacy@svn.freebsd.org) Received: (from kmacy@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o044Q2dW048977; Mon, 4 Jan 2010 04:26:02 GMT (envelope-from kmacy@svn.freebsd.org) Message-Id: <201001040426.o044Q2dW048977@svn.freebsd.org> From: Kip Macy Date: Mon, 4 Jan 2010 04:26:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r201470 - user/kmacy/releng_8_rump/lib/libunet X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Jan 2010 04:26:03 -0000 Author: kmacy Date: Mon Jan 4 04:26:02 2010 New Revision: 201470 URL: http://svn.freebsd.org/changeset/base/201470 Log: import zone allocator and further whittle down missing symbols Added: user/kmacy/releng_8_rump/lib/libunet/opt_kdtrace.h (contents, props changed) user/kmacy/releng_8_rump/lib/libunet/opt_sched.h (contents, props changed) user/kmacy/releng_8_rump/lib/libunet/opt_vm.h (contents, props changed) user/kmacy/releng_8_rump/lib/libunet/unet_init_main.c (contents, props changed) user/kmacy/releng_8_rump/lib/libunet/unet_kern_synch.c (contents, props changed) user/kmacy/releng_8_rump/lib/libunet/unet_uma_core.c (contents, props changed) Modified: user/kmacy/releng_8_rump/lib/libunet/Makefile user/kmacy/releng_8_rump/lib/libunet/unet_compat.c user/kmacy/releng_8_rump/lib/libunet/unet_glue.c Modified: user/kmacy/releng_8_rump/lib/libunet/Makefile ============================================================================== --- user/kmacy/releng_8_rump/lib/libunet/Makefile Mon Jan 4 03:40:46 2010 (r201469) +++ user/kmacy/releng_8_rump/lib/libunet/Makefile Mon Jan 4 04:26:02 2010 (r201470) @@ -2,9 +2,9 @@ PREFIX= ${.CURDIR}/../../sys .PATH: ${PREFIX}/kern -.PATH: ${PREFIX}/libkern .PATH: ${PREFIX}/net .PATH: ${PREFIX}/netinet +.PATH: ${PREFIX}/libkern .PATH: ${PREFIX}/dev/random LIB= unet @@ -12,7 +12,9 @@ LIB= unet UNET_KERN_COMMON_OBJS += \ kern_environment.o \ kern_event.o \ + kern_malloc.o \ kern_mbuf.o \ + kern_module.o \ kern_subr.o \ kern_sysctl.o \ md5c.o \ @@ -95,7 +97,11 @@ UNET_RANDOM_COMMON_OBJS = \ UNET_GLUE_COMMON_OBJS = \ unet_compat.o \ - unet_glue.o + unet_glue.o \ + unet_init_main.c \ + unet_uma_core.c \ + unet_kern_synch.o + # unet_init.o \ # unet_uipc_syscalls.o # unet_sys_generic.o Added: user/kmacy/releng_8_rump/lib/libunet/opt_kdtrace.h ============================================================================== Added: user/kmacy/releng_8_rump/lib/libunet/opt_sched.h ============================================================================== Added: user/kmacy/releng_8_rump/lib/libunet/opt_vm.h ============================================================================== Modified: user/kmacy/releng_8_rump/lib/libunet/unet_compat.c ============================================================================== --- user/kmacy/releng_8_rump/lib/libunet/unet_compat.c Mon Jan 4 03:40:46 2010 (r201469) +++ user/kmacy/releng_8_rump/lib/libunet/unet_compat.c Mon Jan 4 04:26:02 2010 (r201470) @@ -6,7 +6,7 @@ #include struct malloc_type; - +#if 0 void * unet_malloc(unsigned long size, struct malloc_type *type, int flags) { @@ -20,7 +20,7 @@ unet_free(void *addr, struct malloc_type free(addr); } - +#endif /* * Claim another reference to a ucred structure. */ Modified: user/kmacy/releng_8_rump/lib/libunet/unet_glue.c ============================================================================== --- user/kmacy/releng_8_rump/lib/libunet/unet_glue.c Mon Jan 4 03:40:46 2010 (r201469) +++ user/kmacy/releng_8_rump/lib/libunet/unet_glue.c Mon Jan 4 04:26:02 2010 (r201470) @@ -3,16 +3,24 @@ #include #include #include +#include +#include +#include #include #include #include #include #include #include -#include #include #include +#include +#include +#include +#include +#include +#include SYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, "Sysctl internal magic"); @@ -23,9 +31,16 @@ SYSCTL_NODE(, CTL_KERN, kern, CTLFLA SYSCTL_NODE(, CTL_NET, net, CTLFLAG_RW, 0, "Network, (see socket.h)"); +SYSCTL_NODE(, CTL_VM, vm, CTLFLAG_RW, 0, + "Virtual memory"); + MALLOC_DEFINE(M_IOV, "iov", "large iov's"); -MALLOC_DEFINE(M_DEVBUF, "devbuf", "device driver memory"); -MALLOC_DEFINE(M_TEMP, "temp", "misc temporary data buffers"); + + +int ticks; + +time_t time_second = 1; +time_t time_uptime = 1; /* This is used in modules that need to work in both SMP and UP. */ cpumask_t all_cpus; @@ -37,6 +52,18 @@ int mp_maxcpus = MAXCPU; volatile int smp_started; u_int mp_maxid; +long first_page = 0; + +struct vmmeter cnt; +vm_map_t kernel_map=0; +vm_map_t kmem_map=0; + +struct vm_object kernel_object_store; +struct vm_object kmem_object_store; + +struct filterops fs_filtops; +struct filterops sig_filtops; + int cold; struct mtx Giant; @@ -103,6 +130,18 @@ prison_remote_ip4(struct ucred *cred, st return (0); } + +/* + * Return 1 if the passed credential is in a jail and that jail does not + * have its own virtual network stack, otherwise 0. + */ +int +jailed_without_vnet(struct ucred *cred) +{ + + return (0); +} + int priv_check(struct thread *td, int priv) { @@ -454,10 +493,124 @@ chgsbsize(uip, hiwat, to, max) return (1); } + +/* + * Return the current (soft) limit for a particular system resource. + * The which parameter which specifies the index into the rlimit array + */ +rlim_t +lim_cur(struct proc *p, int which) +{ + struct rlimit rl; + + lim_rlimit(p, which, &rl); + return (rl.rlim_cur); +} + +/* + * Return a copy of the entire rlimit structure for the system limit + * specified by 'which' in the rlimit structure pointed to by 'rlp'. + */ +void +lim_rlimit(struct proc *p, int which, struct rlimit *rlp) +{ + +#if 0 + PROC_LOCK_ASSERT(p, MA_OWNED); + KASSERT(which >= 0 && which < RLIM_NLIMITS, + ("request for invalid resource limit")); + *rlp = p->p_limit->pl_rlimit[which]; + if (p->p_sysent->sv_fixlimit != NULL) + p->p_sysent->sv_fixlimit(rlp, which); +#endif +} + int useracc(void *addr, int len, int rw) { return (1); } + +struct proc * +zpfind(pid_t pid) +{ + + return (NULL); +} + +int +p_cansee(struct thread *td, struct proc *p) +{ + + return (0); +} + +struct proc * +pfind(pid_t pid) +{ + + return (NULL); +} + +/* + * Fill in a struct xucred based on a struct ucred. + */ +void +cru2x(struct ucred *cr, struct xucred *xcr) +{ +#if 0 + int ngroups; + + bzero(xcr, sizeof(*xcr)); + xcr->cr_version = XUCRED_VERSION; + xcr->cr_uid = cr->cr_uid; + + ngroups = MIN(cr->cr_ngroups, XU_NGROUPS); + xcr->cr_ngroups = ngroups; + bcopy(cr->cr_groups, xcr->cr_groups, + ngroups * sizeof(*cr->cr_groups)); +#endif +} + +int +cr_cansee(struct ucred *u1, struct ucred *u2) +{ + + return (0); +} + +int +cr_canseeinpcb(struct ucred *cred, struct inpcb *inp) +{ + + return (0); +} + +int +securelevel_gt(struct ucred *cr, int level) +{ + + return (0); +} + + + + +/** + * @brief Send a 'notification' to userland, using standard ways + */ +void +devctl_notify(const char *system, const char *subsystem, const char *type, + const char *data) +{ + ; +} + +void +cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) +{ + ; +} + Added: user/kmacy/releng_8_rump/lib/libunet/unet_init_main.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/kmacy/releng_8_rump/lib/libunet/unet_init_main.c Mon Jan 4 04:26:02 2010 (r201470) @@ -0,0 +1,273 @@ +/*- + * Copyright (c) 1995 Terrence R. Lambert + * All rights reserved. + * + * Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)init_main.c 8.9 (Berkeley) 1/21/94 + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +void mi_startup(void); /* Should be elsewhere */ + +/* Components of the first process -- never freed. */ +static struct session session0; +static struct pgrp pgrp0; +struct proc proc0; +struct thread thread0 __aligned(16); +struct vmspace vmspace0; +struct proc *initproc; +#if 0 +int boothowto = 0; /* initialized so that it can be patched */ +SYSCTL_INT(_debug, OID_AUTO, boothowto, CTLFLAG_RD, &boothowto, 0, ""); +int bootverbose; +SYSCTL_INT(_debug, OID_AUTO, bootverbose, CTLFLAG_RW, &bootverbose, 0, ""); +#endif +/* + * This ensures that there is at least one entry so that the sysinit_set + * symbol is not undefined. A sybsystem ID of SI_SUB_DUMMY is never + * executed. + */ +SYSINIT(placeholder, SI_SUB_DUMMY, SI_ORDER_ANY, NULL, NULL); + +/* + * The sysinit table itself. Items are checked off as the are run. + * If we want to register new sysinit types, add them to newsysinit. + */ +SET_DECLARE(sysinit_set, struct sysinit); +struct sysinit **sysinit, **sysinit_end; +struct sysinit **newsysinit, **newsysinit_end; + +/* + * Merge a new sysinit set into the current set, reallocating it if + * necessary. This can only be called after malloc is running. + */ +void +sysinit_add(struct sysinit **set, struct sysinit **set_end) +{ + struct sysinit **newset; + struct sysinit **sipp; + struct sysinit **xipp; + int count; + + count = set_end - set; + if (newsysinit) + count += newsysinit_end - newsysinit; + else + count += sysinit_end - sysinit; + newset = malloc(count * sizeof(*sipp), M_TEMP, M_NOWAIT); + if (newset == NULL) + panic("cannot malloc for sysinit"); + xipp = newset; + if (newsysinit) + for (sipp = newsysinit; sipp < newsysinit_end; sipp++) + *xipp++ = *sipp; + else + for (sipp = sysinit; sipp < sysinit_end; sipp++) + *xipp++ = *sipp; + for (sipp = set; sipp < set_end; sipp++) + *xipp++ = *sipp; + if (newsysinit) + free(newsysinit, M_TEMP); + newsysinit = newset; + newsysinit_end = newset + count; +} + +/* + * System startup; initialize the world, create process 0, mount root + * filesystem, and fork to create init and pagedaemon. Most of the + * hard work is done in the lower-level initialization routines including + * startup(), which does memory initialization and autoconfiguration. + * + * This allows simple addition of new kernel subsystems that require + * boot time initialization. It also allows substitution of subsystem + * (for instance, a scheduler, kernel profiler, or VM system) by object + * module. Finally, it allows for optional "kernel threads". + */ +void +mi_startup(void) +{ + + register struct sysinit **sipp; /* system initialization*/ + register struct sysinit **xipp; /* interior loop of sort*/ + register struct sysinit *save; /* bubble*/ + +#if defined(VERBOSE_SYSINIT) + int last; + int verbose; +#endif + + if (sysinit == NULL) { + sysinit = SET_BEGIN(sysinit_set); + sysinit_end = SET_LIMIT(sysinit_set); + } + +restart: + /* + * Perform a bubble sort of the system initialization objects by + * their subsystem (primary key) and order (secondary key). + */ + for (sipp = sysinit; sipp < sysinit_end; sipp++) { + for (xipp = sipp + 1; xipp < sysinit_end; xipp++) { + if ((*sipp)->subsystem < (*xipp)->subsystem || + ((*sipp)->subsystem == (*xipp)->subsystem && + (*sipp)->order <= (*xipp)->order)) + continue; /* skip*/ + save = *sipp; + *sipp = *xipp; + *xipp = save; + } + } + +#if defined(VERBOSE_SYSINIT) + last = SI_SUB_COPYRIGHT; + verbose = 0; +#if !defined(DDB) + printf("VERBOSE_SYSINIT: DDB not enabled, symbol lookups disabled.\n"); +#endif +#endif + + /* + * Traverse the (now) ordered list of system initialization tasks. + * Perform each task, and continue on to the next task. + * + * The last item on the list is expected to be the scheduler, + * which will not return. + */ + for (sipp = sysinit; sipp < sysinit_end; sipp++) { + + if ((*sipp)->subsystem == SI_SUB_DUMMY) + continue; /* skip dummy task(s)*/ + + if ((*sipp)->subsystem == SI_SUB_DONE) + continue; + +#if defined(VERBOSE_SYSINIT) + if ((*sipp)->subsystem > last) { + verbose = 1; + last = (*sipp)->subsystem; + printf("subsystem %x\n", last); + } + if (verbose) { +#if defined(DDB) + const char *name; + c_db_sym_t sym; + db_expr_t offset; + + sym = db_search_symbol((vm_offset_t)(*sipp)->func, + DB_STGY_PROC, &offset); + db_symbol_values(sym, &name, NULL); + if (name != NULL) + printf(" %s(%p)... ", name, (*sipp)->udata); + else +#endif + printf(" %p(%p)... ", (*sipp)->func, + (*sipp)->udata); + } +#endif + + /* Call function */ + (*((*sipp)->func))((*sipp)->udata); + +#if defined(VERBOSE_SYSINIT) + if (verbose) + printf("done.\n"); +#endif + + /* Check off the one we're just done */ + (*sipp)->subsystem = SI_SUB_DONE; + + /* Check if we've installed more sysinit items via KLD */ + if (newsysinit != NULL) { + if (sysinit != SET_BEGIN(sysinit_set)) + free(sysinit, M_TEMP); + sysinit = newsysinit; + sysinit_end = newsysinit_end; + newsysinit = NULL; + newsysinit_end = NULL; + goto restart; + } + } + + panic("Shouldn't get here!"); + /* NOTREACHED*/ +} Added: user/kmacy/releng_8_rump/lib/libunet/unet_kern_synch.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/kmacy/releng_8_rump/lib/libunet/unet_kern_synch.c Mon Jan 4 04:26:02 2010 (r201470) @@ -0,0 +1,53 @@ +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ktrace.h" +#include "opt_sched.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef KTRACE +#include +#include +#endif + +int hogticks; + +/* + * General sleep call. Suspends the current thread until a wakeup is + * performed on the specified identifier. The thread will then be made + * runnable with the specified priority. Sleeps at most timo/hz seconds + * (0 means no timeout). If pri includes PCATCH flag, signals are checked + * before and after sleeping, else signals are not checked. Returns 0 if + * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a + * signal needs to be delivered, ERESTART is returned if the current system + * call should be restarted if possible, and EINTR is returned if the system + * call should be interrupted by the signal (return EINTR). + * + * The lock argument is unlocked before the caller is suspended, and + * re-locked before _sleep() returns. If priority includes the PDROP + * flag the lock is not re-locked before returning. + */ +int +_sleep(void *ident, struct lock_object *lock, int priority, + const char *wmesg, int timo) +{ + + panic(""); +} Added: user/kmacy/releng_8_rump/lib/libunet/unet_uma_core.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/kmacy/releng_8_rump/lib/libunet/unet_uma_core.c Mon Jan 4 04:26:02 2010 (r201470) @@ -0,0 +1,2809 @@ +/*- + * Copyright (c) 2002-2005, 2009 Jeffrey Roberson + * Copyright (c) 2004, 2005 Bosko Milekic + * Copyright (c) 2004-2006 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * uma_core.c Implementation of the Universal Memory allocator + * + * This allocator is intended to replace the multitude of similar object caches + * in the standard FreeBSD kernel. The intent is to be flexible as well as + * effecient. A primary design goal is to return unused memory to the rest of + * the system. This will make the system as a whole more flexible due to the + * ability to move memory to subsystems which most need it instead of leaving + * pools of reserved memory unused. + * + * The basic ideas stem from similar slab/zone based allocators whose algorithms + * are well known. + * + */ + +/* + * TODO: + * - Improve memory usage for large allocations + * - Investigate cache size adjustments + */ + +#include +__FBSDID("$FreeBSD$"); + +/* I should really use ktr.. */ +/* +#define UMA_DEBUG 1 +#define UMA_DEBUG_ALLOC 1 +#define UMA_DEBUG_ALLOC_1 1 +*/ + +#include "opt_ddb.h" +#include "opt_param.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#undef UMA_MD_SMALL_ALLOC + +/* + * This is the zone and keg from which all zones are spawned. The idea is that + * even the zone & keg heads are allocated from the allocator, so we use the + * bss section to bootstrap us. + */ +static struct uma_keg masterkeg; +static struct uma_zone masterzone_k; +static struct uma_zone masterzone_z; +static uma_zone_t kegs = &masterzone_k; +static uma_zone_t zones = &masterzone_z; + +/* This is the zone from which all of uma_slab_t's are allocated. */ +static uma_zone_t slabzone; +static uma_zone_t slabrefzone; /* With refcounters (for UMA_ZONE_REFCNT) */ + +/* + * The initial hash tables come out of this zone so they can be allocated + * prior to malloc coming up. + */ +static uma_zone_t hashzone; + +/* The boot-time adjusted value for cache line alignment. */ +static int uma_align_cache = 64 - 1; + +static MALLOC_DEFINE(M_UMAHASH, "UMAHash", "UMA Hash Buckets"); + +/* + * Are we allowed to allocate buckets? + */ +static int bucketdisable = 1; + +/* Linked list of all kegs in the system */ +static LIST_HEAD(,uma_keg) uma_kegs = LIST_HEAD_INITIALIZER(&uma_kegs); + +/* This mutex protects the keg list */ +static struct mtx uma_mtx; + +/* Linked list of boot time pages */ +static LIST_HEAD(,uma_slab) uma_boot_pages = + LIST_HEAD_INITIALIZER(&uma_boot_pages); + +/* This mutex protects the boot time pages list */ +static struct mtx uma_boot_pages_mtx; + +/* Is the VM done starting up? */ +static int booted = 0; + +/* Maximum number of allowed items-per-slab if the slab header is OFFPAGE */ +static u_int uma_max_ipers; +static u_int uma_max_ipers_ref; + +/* + * This is the handle used to schedule events that need to happen + * outside of the allocation fast path. + */ +static struct callout uma_callout; +#define UMA_TIMEOUT 20 /* Seconds for callout interval. */ + +/* + * This structure is passed as the zone ctor arg so that I don't have to create + * a special allocation function just for zones. + */ +struct uma_zctor_args { + char *name; + size_t size; + uma_ctor ctor; + uma_dtor dtor; + uma_init uminit; + uma_fini fini; + uma_keg_t keg; + int align; + u_int32_t flags; +}; + +struct uma_kctor_args { + uma_zone_t zone; + size_t size; + uma_init uminit; + uma_fini fini; + int align; + u_int32_t flags; +}; + +struct uma_bucket_zone { + uma_zone_t ubz_zone; + char *ubz_name; + int ubz_entries; +}; + +#define BUCKET_MAX 128 + +struct uma_bucket_zone bucket_zones[] = { + { NULL, "16 Bucket", 16 }, + { NULL, "32 Bucket", 32 }, + { NULL, "64 Bucket", 64 }, + { NULL, "128 Bucket", 128 }, + { NULL, NULL, 0} +}; + +#define BUCKET_SHIFT 4 +#define BUCKET_ZONES ((BUCKET_MAX >> BUCKET_SHIFT) + 1) + +/* + * bucket_size[] maps requested bucket sizes to zones that allocate a bucket + * of approximately the right size. + */ +static uint8_t bucket_size[BUCKET_ZONES]; + +/* + * Flags and enumerations to be passed to internal functions. + */ +enum zfreeskip { SKIP_NONE, SKIP_DTOR, SKIP_FINI }; + +#define ZFREE_STATFAIL 0x00000001 /* Update zone failure statistic. */ +#define ZFREE_STATFREE 0x00000002 /* Update zone free statistic. */ + +/* Prototypes.. */ + +static void *obj_alloc(uma_zone_t, int, u_int8_t *, int); +static void *page_alloc(uma_zone_t, int, u_int8_t *, int); +static void *startup_alloc(uma_zone_t, int, u_int8_t *, int); +static void page_free(void *, int, u_int8_t); +static uma_slab_t keg_alloc_slab(uma_keg_t, uma_zone_t, int); +static void cache_drain(uma_zone_t); +static void bucket_drain(uma_zone_t, uma_bucket_t); +static void bucket_cache_drain(uma_zone_t zone); +static int keg_ctor(void *, int, void *, int); +static void keg_dtor(void *, int, void *); +static int zone_ctor(void *, int, void *, int); +static void zone_dtor(void *, int, void *); +static int zero_init(void *, int, int); +static void keg_small_init(uma_keg_t keg); +static void keg_large_init(uma_keg_t keg); +static void zone_foreach(void (*zfunc)(uma_zone_t)); +static void zone_timeout(uma_zone_t zone); +static int hash_alloc(struct uma_hash *); +static int hash_expand(struct uma_hash *, struct uma_hash *); +static void hash_free(struct uma_hash *hash); +static void uma_timeout(void *); +static void uma_startup3(void); +static void *zone_alloc_item(uma_zone_t, void *, int); +static void zone_free_item(uma_zone_t, void *, void *, enum zfreeskip, + int); +static void bucket_enable(void); +static void bucket_init(void); +static uma_bucket_t bucket_alloc(int, int); +static void bucket_free(uma_bucket_t); +static void bucket_zone_drain(void); +static int zone_alloc_bucket(uma_zone_t zone, int flags); +static uma_slab_t zone_fetch_slab(uma_zone_t zone, uma_keg_t last, int flags); +static uma_slab_t zone_fetch_slab_multi(uma_zone_t zone, uma_keg_t last, int flags); +static void *slab_alloc_item(uma_zone_t zone, uma_slab_t slab); +static uma_keg_t uma_kcreate(uma_zone_t zone, size_t size, uma_init uminit, + uma_fini fini, int align, u_int32_t flags); +static inline void zone_relock(uma_zone_t zone, uma_keg_t keg); +static inline void keg_relock(uma_keg_t keg, uma_zone_t zone); + +void uma_print_zone(uma_zone_t); +void uma_print_stats(void); +static int sysctl_vm_zone_count(SYSCTL_HANDLER_ARGS); +static int sysctl_vm_zone_stats(SYSCTL_HANDLER_ARGS); + +SYSINIT(uma_startup3, SI_SUB_VM_CONF, SI_ORDER_SECOND, uma_startup3, NULL); + +SYSCTL_PROC(_vm, OID_AUTO, zone_count, CTLFLAG_RD|CTLTYPE_INT, + 0, 0, sysctl_vm_zone_count, "I", "Number of UMA zones"); + +SYSCTL_PROC(_vm, OID_AUTO, zone_stats, CTLFLAG_RD|CTLTYPE_STRUCT, + 0, 0, sysctl_vm_zone_stats, "s,struct uma_type_header", "Zone Stats"); + +/* + * This routine checks to see whether or not it's safe to enable buckets. + */ + +static void +bucket_enable(void) +{ + if (cnt.v_free_count < cnt.v_free_min) + bucketdisable = 1; + else + bucketdisable = 0; +} + +/* + * Initialize bucket_zones, the array of zones of buckets of various sizes. + * + * For each zone, calculate the memory required for each bucket, consisting + * of the header and an array of pointers. Initialize bucket_size[] to point + * the range of appropriate bucket sizes at the zone. + */ +static void +bucket_init(void) +{ + struct uma_bucket_zone *ubz; + int i; + int j; + + for (i = 0, j = 0; bucket_zones[j].ubz_entries != 0; j++) { + int size; + + ubz = &bucket_zones[j]; + size = roundup(sizeof(struct uma_bucket), sizeof(void *)); + size += sizeof(void *) * ubz->ubz_entries; + ubz->ubz_zone = uma_zcreate(ubz->ubz_name, size, + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, + UMA_ZFLAG_INTERNAL | UMA_ZFLAG_BUCKET); + for (; i <= ubz->ubz_entries; i += (1 << BUCKET_SHIFT)) + bucket_size[i >> BUCKET_SHIFT] = j; + } +} + +/* + * Given a desired number of entries for a bucket, return the zone from which + * to allocate the bucket. + */ +static struct uma_bucket_zone * +bucket_zone_lookup(int entries) +{ + int idx; + + idx = howmany(entries, 1 << BUCKET_SHIFT); + return (&bucket_zones[bucket_size[idx]]); +} + +static uma_bucket_t +bucket_alloc(int entries, int bflags) +{ + struct uma_bucket_zone *ubz; + uma_bucket_t bucket; + + /* + * This is to stop us from allocating per cpu buckets while we're + * running out of vm.boot_pages. Otherwise, we would exhaust the + * boot pages. This also prevents us from allocating buckets in + * low memory situations. + */ + if (bucketdisable) + return (NULL); + + ubz = bucket_zone_lookup(entries); + bucket = zone_alloc_item(ubz->ubz_zone, NULL, bflags); + if (bucket) { +#ifdef INVARIANTS + bzero(bucket->ub_bucket, sizeof(void *) * ubz->ubz_entries); +#endif + bucket->ub_cnt = 0; + bucket->ub_entries = ubz->ubz_entries; + } + + return (bucket); +} + +static void +bucket_free(uma_bucket_t bucket) +{ + struct uma_bucket_zone *ubz; + + ubz = bucket_zone_lookup(bucket->ub_entries); + zone_free_item(ubz->ubz_zone, bucket, NULL, SKIP_NONE, + ZFREE_STATFREE); +} + +static void +bucket_zone_drain(void) +{ + struct uma_bucket_zone *ubz; + + for (ubz = &bucket_zones[0]; ubz->ubz_entries != 0; ubz++) + zone_drain(ubz->ubz_zone); +} + +static inline uma_keg_t +zone_first_keg(uma_zone_t zone) +{ + + return (LIST_FIRST(&zone->uz_kegs)->kl_keg); +} + +static void +zone_foreach_keg(uma_zone_t zone, void (*kegfn)(uma_keg_t)) +{ + uma_klink_t klink; + + LIST_FOREACH(klink, &zone->uz_kegs, kl_link) + kegfn(klink->kl_keg); +} + +/* + * Routine called by timeout which is used to fire off some time interval + * based calculations. (stats, hash size, etc.) + * + * Arguments: + * arg Unused + * + * Returns: + * Nothing + */ +static void +uma_timeout(void *unused) +{ + bucket_enable(); + zone_foreach(zone_timeout); + + /* Reschedule this event */ + callout_reset(&uma_callout, UMA_TIMEOUT * hz, uma_timeout, NULL); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***