kernel - Redo struct vmspace allocator and ref-count handling. master
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 23 Jul 2014 01:52:47 +0000 (18:52 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 23 Jul 2014 01:52:47 +0000 (18:52 -0700)
* Get rid of the sysref-based allocator and ref-count handler and
  replace with objcache.  Replace all sysref API calls in other kernel
  modules with vmspace_*() API calls (adding new API calls as needed).

* Roll-our-own hopefully safer ref-count handling.  We get rid of exitingcnt
  and instead just leave holdcnt bumped during the exit/reap sequence.  We
  add vm_refcnt and redo vm_holdcnt.

  Now a formal reference (vm_refcnt) is ALSO covered by a holdcnt.  Stage-1
  termination occurs when vm_refcnt transitions from 1->0.  Stage-2 termination
  occurs when vm_holdcnt transitions from 1->0.

* Should fix rare reported panic under heavy load.

18 files changed:
sys/kern/imgact_resident.c
sys/kern/init_main.c
sys/kern/kern_exec.c
sys/kern/kern_exit.c
sys/kern/kern_kinfo.c
sys/kern/tty.c
sys/platform/pc32/i386/pmap.c
sys/platform/pc64/vmm/vmx.c
sys/platform/pc64/x86_64/pmap.c
sys/platform/vkernel/platform/pmap.c
sys/platform/vkernel64/platform/pmap.c
sys/vfs/procfs/procfs_mem.c
sys/vm/vm_extern.h
sys/vm/vm_glue.c
sys/vm/vm_map.c
sys/vm/vm_map.h
sys/vm/vm_mmap.c
sys/vm/vm_vmspace.c

index 1324790..88ae048 100644 (file)
@@ -305,7 +305,7 @@ restart:
                vmres->vr_vnode = NULL;
            }
            if (vmres->vr_vmspace) {
-               vmspace_free(vmres->vr_vmspace);
+               vmspace_rel(vmres->vr_vmspace);
                vmres->vr_vmspace = NULL;
            }
            kfree(vmres, M_EXEC_RES);
index 5a485a4..742c391 100644 (file)
@@ -436,12 +436,11 @@ proc0_init(void *dummy __unused)
        pmap_pinit0(vmspace_pmap(&vmspace0));
        p->p_vmspace = &vmspace0;
        lp->lwp_vmspace = p->p_vmspace;
-       sysref_init(&vmspace0.vm_sysref, &vmspace_sysref_class);
+       vmspace_initrefs(&vmspace0);
        vm_map_init(&vmspace0.vm_map,
                    round_page(VM_MIN_USER_ADDRESS),
                    trunc_page(VM_MAX_USER_ADDRESS),
                    vmspace_pmap(&vmspace0));
-       sysref_activate(&vmspace0.vm_sysref);
 
        kqueue_init(&lwp0.lwp_kqueue, &filedesc0);
 
index 2029678..83219f6 100644 (file)
@@ -828,7 +828,7 @@ exec_new_vmspace(struct image_params *imgp, struct vmspace *vmcopy)
                vmspace = imgp->proc->p_vmspace;
                pmap_remove_pages(vmspace_pmap(vmspace), stack_addr, USRSTACK);
                map = &vmspace->vm_map;
-       } else if (vmspace->vm_sysref.refcnt == 1) {
+       } else if (vmspace_getrefs(vmspace) == 1) {
                shmexit(vmspace);
                pmap_remove_pages(vmspace_pmap(vmspace),
                                  0, VM_MAX_USER_ADDRESS);
index 7bae31f..85290fb 100644 (file)
@@ -382,12 +382,14 @@ exit1(int rv)
        }
 
        /*
-        * Release user portion of address space.
-        * This releases references to vnodes,
-        * which could cause I/O if the file has been unlinked.
-        * Need to do this early enough that we can still sleep.
-        * Can't free the entire vmspace as the kernel stack
-        * may be mapped within that space also.
+        * Release the user portion of address space.  The exitbump prevents
+        * the vmspace from being completely eradicated (using holdcnt).
+        * This releases references to vnodes, which could cause I/O if the
+        * file has been unlinked.  We need to do this early enough that
+        * we can still sleep.
+        *
+        * We can't free the entire vmspace as the kernel stack may be mapped
+        * within that space also.
         *
         * Processes sharing the same vmspace may exit in one order, and
         * get cleaned up by vmspace_exit() in a different order.  The
@@ -396,8 +398,7 @@ exit1(int rv)
         * by vmspace_exit() (which decrements exitingcnt) cleans up the
         * remainder.
         */
-       vmspace_exitbump(vm);
-       sysref_put(&vm->vm_sysref);
+       vmspace_relexit(vm);
 
        if (SESS_LEADER(p)) {
                struct session *sp = p->p_session;
index 876f197..303ce1f 100644 (file)
@@ -149,10 +149,6 @@ fill_kinfo_proc(struct proc *p, struct kinfo_proc *kp)
        kp->kp_swtime = p->p_swtime;
 
        if ((vm = p->p_vmspace) != NULL) {
-#ifdef _KERNEL
-               /*sysref_get(&vm->vm_sysref);*/
-               /*lwkt_gettoken(&vm->vm_map.token);*/
-#endif
                kp->kp_vm_map_size = vm->vm_map.size;
                kp->kp_vm_rssize = vmspace_resident_count(vm);
 #ifdef _KERNEL
@@ -163,10 +159,6 @@ fill_kinfo_proc(struct proc *p, struct kinfo_proc *kp)
                kp->kp_vm_tsize = vm->vm_tsize;
                kp->kp_vm_dsize = vm->vm_dsize;
                kp->kp_vm_ssize = vm->vm_ssize;
-#ifdef _KERNEL
-               /*lwkt_reltoken(&vm->vm_map.token);*/
-               /*sysref_put(&vm->vm_sysref);*/
-#endif
        }
 
        if (p->p_ucred && jailed(p->p_ucred))
index 676449b..27c4b1d 100644 (file)
@@ -2657,6 +2657,11 @@ ttyinfo(struct tty *tp)
 
        LWPRELE(lp);
 
+       /*
+        * NOTE: vmspace should be protected from destruction by the
+        *       combination of pg_token and the fact that we are not
+        *       flagged as a zombie.
+        */
        if (pick->p_stat == SIDL || pick->p_stat == SZOMB) {
                vmsz = 0;
        } else if ((vm = pick->p_vmspace) == NULL) {
index 704d54e..bee854a 100644 (file)
@@ -3743,13 +3743,13 @@ pmap_replacevm(struct proc *p, struct vmspace *newvm, int adjrefs)
        oldvm = p->p_vmspace;
        if (oldvm != newvm) {
                if (adjrefs)
-                       sysref_get(&newvm->vm_sysref);
+                       vmspace_ref(newvm);
                p->p_vmspace = newvm;
                KKASSERT(p->p_nthreads == 1);
                lp = RB_ROOT(&p->p_lwp_tree);
                pmap_setlwpvm(lp, newvm);
                if (adjrefs) 
-                       sysref_put(&oldvm->vm_sysref);
+                       vmspace_rel(oldvm);
        }
 }
 
index 662d1d8..9446913 100644 (file)
@@ -742,7 +742,7 @@ vmx_vminit_master(struct vmm_guest_options *options)
        lwkt_reltoken(&newvmspace->vm_map.token);
        lwkt_reltoken(&oldvmspace->vm_map.token);
 
-       vmspace_free(oldvmspace);
+       vmspace_rel(oldvmspace);
 
        options->vmm_cr3 = vtophys(vmspace_pmap(newvmspace)->pm_pml4);
 
index 28a6ded..45b3a29 100644 (file)
@@ -5194,13 +5194,13 @@ pmap_replacevm(struct proc *p, struct vmspace *newvm, int adjrefs)
        oldvm = p->p_vmspace;
        if (oldvm != newvm) {
                if (adjrefs)
-                       sysref_get(&newvm->vm_sysref);
+                       vmspace_ref(newvm);
                p->p_vmspace = newvm;
                KKASSERT(p->p_nthreads == 1);
                lp = RB_ROOT(&p->p_lwp_tree);
                pmap_setlwpvm(lp, newvm);
                if (adjrefs)
-                       sysref_put(&oldvm->vm_sysref);
+                       vmspace_rel(oldvm);
        }
 }
 
index 356a2ed..cc85121 100644 (file)
@@ -3057,8 +3057,8 @@ pmap_replacevm(struct proc *p, struct vmspace *newvm, int adjrefs)
                lp = RB_ROOT(&p->p_lwp_tree);
                pmap_setlwpvm(lp, newvm);
                if (adjrefs) {
-                       sysref_get(&newvm->vm_sysref);
-                       sysref_put(&oldvm->vm_sysref);
+                       vmspace_ref(newvm);
+                       vmspace_rel(oldvm);
                }
        }
        crit_exit();
index 7e1e15d..3b9493f 100644 (file)
@@ -3331,8 +3331,8 @@ pmap_replacevm(struct proc *p, struct vmspace *newvm, int adjrefs)
                lp = RB_ROOT(&p->p_lwp_tree);
                pmap_setlwpvm(lp, newvm);
                if (adjrefs) {
-                       sysref_get(&newvm->vm_sysref);
-                       sysref_put(&oldvm->vm_sysref);
+                       vmspace_ref(newvm);
+                       vmspace_rel(oldvm);
                }
        }
        crit_exit();
index a0714b4..1b155a6 100644 (file)
@@ -90,8 +90,7 @@ procfs_rwmem(struct proc *curp, struct proc *p, struct uio *uio)
        vm = p->p_vmspace;
        if (p->p_stat == SIDL || p->p_stat == SZOMB)
                return EFAULT;
-       if ((p->p_flags & (P_WEXIT | P_INEXEC)) ||
-           sysref_isinactive(&vm->vm_sysref))
+       if ((p->p_flags & (P_WEXIT | P_INEXEC)) || vmspace_getrefs(vm) < 0)
                return EFAULT;
 
        /*
index 507a5c1..4b6ebf5 100644 (file)
@@ -110,15 +110,18 @@ int vm_mmap_to_errno(int rv);
 vm_offset_t kmem_alloc_contig (vm_offset_t, vm_paddr_t, vm_paddr_t, vm_offset_t);
 void vm_set_page_size (void);
 struct vmspace *vmspace_alloc (vm_offset_t, vm_offset_t);
-void vmspace_ref (struct vmspace *);
-void vmspace_free (struct vmspace *);
+void vmspace_initrefs (struct vmspace *);
+int vmspace_getrefs (struct vmspace *);
 void vmspace_hold (struct vmspace *);
 void vmspace_drop (struct vmspace *);
+void vmspace_ref (struct vmspace *);
+void vmspace_rel (struct vmspace *);
+void vmspace_relexit (struct vmspace *);
+void vmspace_exitfree (struct proc *);
+
 struct vmspace *vmspace_fork (struct vmspace *);
 void vmspace_exec (struct proc *, struct vmspace *);
 void vmspace_unshare (struct proc *);
-void vmspace_exitfree (struct proc *);
-void vmspace_exitbump (struct vmspace *);
 void vslock (caddr_t, u_int);
 void vsunlock (caddr_t, u_int);
 void vm_object_print (/* db_expr_t */ long, boolean_t, /* db_expr_t */ long,
index 4ff06ea..cc7b8fb 100644 (file)
@@ -240,7 +240,7 @@ vm_fork(struct proc *p1, struct proc *p2, int flags)
                 * COW locally.
                 */
                if ((flags & RFMEM) == 0) {
-                       if (p1->p_vmspace->vm_sysref.refcnt > 1) {
+                       if (vmspace_getrefs(p1->p_vmspace) > 1) {
                                vmspace_unshare(p1);
                        }
                }
index b488606..851a7b9 100644 (file)
@@ -79,6 +79,7 @@
 #include <sys/shm.h>
 #include <sys/tree.h>
 #include <sys/malloc.h>
+#include <sys/objcache.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -93,7 +94,6 @@
 #include <vm/vm_zone.h>
 
 #include <sys/thread2.h>
-#include <sys/sysref2.h>
 #include <sys/random.h>
 #include <sys/sysctl.h>
 
  * Virtual copy operations are performed by copying VM object references
  * from one map to another, and then marking both regions as copy-on-write.
  */
-static void vmspace_terminate(struct vmspace *vm);
-static void vmspace_lock(struct vmspace *vm);
-static void vmspace_unlock(struct vmspace *vm);
-static void vmspace_dtor(void *obj, void *private);
+static __boolean_t vmspace_ctor(void *obj, void *privdata, int ocflags);
+static void vmspace_dtor(void *obj, void *privdata);
+static void vmspace_terminate(struct vmspace *vm, int final);
 
 MALLOC_DEFINE(M_VMSPACE, "vmspace", "vmspace objcache backingstore");
-
-struct sysref_class vmspace_sysref_class = {
-       .name =         "vmspace",
-       .mtype =        M_VMSPACE,
-       .proto =        SYSREF_PROTO_VMSPACE,
-       .offset =       offsetof(struct vmspace, vm_sysref),
-       .objsize =      sizeof(struct vmspace),
-       .nom_cache =    32,
-       .flags = SRC_MANAGEDINIT,
-       .dtor = vmspace_dtor,
-       .ops = {
-               .terminate = (sysref_terminate_func_t)vmspace_terminate,
-               .lock = (sysref_lock_func_t)vmspace_lock,
-               .unlock = (sysref_lock_func_t)vmspace_unlock
-       }
-};
+static struct objcache *vmspace_cache;
 
 /*
  * per-cpu page table cross mappings are initialized in early boot
@@ -208,6 +192,11 @@ vm_map_startup(void)
 void
 vm_init2(void) 
 {
+       vmspace_cache = objcache_create_mbacked(M_VMSPACE,
+                                               sizeof(struct vmspace),
+                                               0, ncpus * 4,
+                                               vmspace_ctor, vmspace_dtor,
+                                               NULL);
        zinitna(mapentzone, &mapentobj, NULL, 0, 0, 
                ZONE_USE_RESERVE | ZONE_SPECIAL, 1);
        zinitna(mapzone, &mapobj, NULL, 0, 0, 0, 1);
@@ -215,6 +204,31 @@ vm_init2(void)
        vm_object_init2();
 }
 
+/*
+ * objcache support.  We leave the pmap root cached as long as possible
+ * for performance reasons.
+ */
+static
+__boolean_t
+vmspace_ctor(void *obj, void *privdata, int ocflags)
+{
+       struct vmspace *vm = obj;
+
+       bzero(vm, sizeof(*vm));
+       vm->vm_refcnt = (u_int)-1;
+
+       return 1;
+}
+
+static
+void
+vmspace_dtor(void *obj, void *privdata)
+{
+       struct vmspace *vm = obj;
+
+       KKASSERT(vm->vm_refcnt == (u_int)-1);
+       pmap_puninit(vmspace_pmap(vm));
+}
 
 /*
  * Red black tree functions
@@ -236,12 +250,23 @@ rb_vm_map_compare(vm_map_entry_t a, vm_map_entry_t b)
 }
 
 /*
+ * Initialize vmspace ref/hold counts vmspace0.  There is a holdcnt for
+ * every refcnt.
+ */
+void
+vmspace_initrefs(struct vmspace *vm)
+{
+       vm->vm_refcnt = 1;
+       vm->vm_holdcnt = 1;
+}
+
+/*
  * Allocate a vmspace structure, including a vm_map and pmap.
  * Initialize numerous fields.  While the initial allocation is zerod,
  * subsequence reuse from the objcache leaves elements of the structure
  * intact (particularly the pmap), so portions must be zerod.
  *
- * The structure is not considered activated until we call sysref_activate().
+ * Returns a referenced vmspace.
  *
  * No requirements.
  */
@@ -250,56 +275,68 @@ vmspace_alloc(vm_offset_t min, vm_offset_t max)
 {
        struct vmspace *vm;
 
-       vm = sysref_alloc(&vmspace_sysref_class);
+       vm = objcache_get(vmspace_cache, M_WAITOK);
+
        bzero(&vm->vm_startcopy,
              (char *)&vm->vm_endcopy - (char *)&vm->vm_startcopy);
        vm_map_init(&vm->vm_map, min, max, NULL);       /* initializes token */
 
        /*
-        * Use a hold to prevent any additional racing hold from terminating
-        * the vmspace before we manage to activate it.  This also acquires
-        * the token for safety.
+        * NOTE: hold to acquires token for safety.
+        *
+        * On return vmspace is referenced (refs=1, hold=1).  That is,
+        * each refcnt also has a holdcnt.  There can be additional holds
+        * (holdcnt) above and beyond the refcnt.  Finalization is handled in
+        * two stages, one on refs 1->0, and the the second on hold 1->0.
         */
-       KKASSERT(vm->vm_holdcount == 0);
-       KKASSERT(vm->vm_exitingcnt == 0);
+       KKASSERT(vm->vm_holdcnt == 0);
+       KKASSERT(vm->vm_refcnt == (u_int)-1);
+       vmspace_initrefs(vm);
        vmspace_hold(vm);
        pmap_pinit(vmspace_pmap(vm));           /* (some fields reused) */
-       vm->vm_map.pmap = vmspace_pmap(vm);             /* XXX */
+       vm->vm_map.pmap = vmspace_pmap(vm);     /* XXX */
        vm->vm_shm = NULL;
        vm->vm_flags = 0;
        cpu_vmspace_alloc(vm);
-       sysref_activate(&vm->vm_sysref);
        vmspace_drop(vm);
 
        return (vm);
 }
 
 /*
- * Free a primary reference to a vmspace.  This can trigger a
- * stage-1 termination.
+ * NOTE: Can return -1 if the vmspace is exiting.
  */
-void
-vmspace_free(struct vmspace *vm)
+int
+vmspace_getrefs(struct vmspace *vm)
 {
-       /*
-        * We want all finalization to occur via vmspace_drop() so we
-        * need to hold the vm around the put.
-        */
-       vmspace_hold(vm);
-       sysref_put(&vm->vm_sysref);
-       vmspace_drop(vm);
+       return ((int)vm->vm_refcnt);
 }
 
-void
-vmspace_ref(struct vmspace *vm)
+/*
+ * A vmspace object must already have a non-zero hold to be able to gain
+ * further holds on it.
+ */
+static void
+vmspace_hold_notoken(struct vmspace *vm)
 {
-       sysref_get(&vm->vm_sysref);
+       KKASSERT(vm->vm_holdcnt != 0);
+       refcount_acquire(&vm->vm_holdcnt);
+}
+
+static void
+vmspace_drop_notoken(struct vmspace *vm)
+{
+       if (refcount_release(&vm->vm_holdcnt)) {
+               if (vm->vm_refcnt == (u_int)-1) {
+                       vmspace_terminate(vm, 1);
+               }
+       }
 }
 
 void
 vmspace_hold(struct vmspace *vm)
 {
-       refcount_acquire(&vm->vm_holdcount);
+       vmspace_hold_notoken(vm);
        lwkt_gettoken(&vm->vm_map.token);
 }
 
@@ -307,64 +344,112 @@ void
 vmspace_drop(struct vmspace *vm)
 {
        lwkt_reltoken(&vm->vm_map.token);
-       if (refcount_release(&vm->vm_holdcount)) {
-               if (vm->vm_exitingcnt == 0 &&
-                   sysref_isinactive(&vm->vm_sysref)) {
-                       vmspace_terminate(vm);
-               }
-       }
+       vmspace_drop_notoken(vm);
 }
 
 /*
- * dtor function - Some elements of the pmap are retained in the
- * free-cached vmspaces to improve performance.  We have to clean them up
- * here before returning the vmspace to the memory pool.
+ * A vmspace object must not be in a terminated state to be able to obtain
+ * additional refs on it.
  *
- * No requirements.
+ * Ref'ing a vmspace object also increments its hold count.
  */
-static void
-vmspace_dtor(void *obj, void *private)
+void
+vmspace_ref(struct vmspace *vm)
 {
-       struct vmspace *vm = obj;
+       KKASSERT((int)vm->vm_refcnt >= 0);
+       vmspace_hold_notoken(vm);
+       refcount_acquire(&vm->vm_refcnt);
+}
 
-       pmap_puninit(vmspace_pmap(vm));
+/*
+ * Release a ref on the vmspace.  On the 1->0 transition we do stage-1
+ * termination of the vmspace.  Then, on the final drop of the hold we
+ * will do stage-2 final termination.
+ */
+void
+vmspace_rel(struct vmspace *vm)
+{
+       if (refcount_release(&vm->vm_refcnt)) {
+               vm->vm_refcnt = (u_int)-1;      /* no other refs possible */
+               vmspace_terminate(vm, 0);
+       }
+       vmspace_drop_notoken(vm);
 }
 
 /*
- * Called in three cases:
+ * This is called during exit indicating that the vmspace is no
+ * longer in used by an exiting process, but the process has not yet
+ * been reaped.
  *
- * (1) When the last sysref is dropped and the vmspace becomes inactive.
- *     (holdcount will not be 0 because the vmspace is held through the op)
+ * We release the refcnt but not the associated holdcnt.
  *
- * (2) When exitingcount becomes 0 on the last reap
- *     (holdcount will not be 0 because the vmspace is held through the op)
+ * No requirements.
+ */
+void
+vmspace_relexit(struct vmspace *vm)
+{
+       if (refcount_release(&vm->vm_refcnt)) {
+               vm->vm_refcnt = (u_int)-1;      /* no other refs possible */
+               vmspace_terminate(vm, 0);
+       }
+}
+
+/*
+ * Called during reap to disconnect the remainder of the vmspace from
+ * the process.  On the hold drop the vmspace termination is finalized.
  *
- * (3) When the holdcount becomes 0 in addition to the above two
+ * No requirements.
+ */
+void
+vmspace_exitfree(struct proc *p)
+{
+       struct vmspace *vm;
+
+       vm = p->p_vmspace;
+       p->p_vmspace = NULL;
+       vmspace_drop_notoken(vm);
+}
+
+/*
+ * Called in two cases:
+ *
+ * (1) When the last refcnt is dropped and the vmspace becomes inactive,
+ *     called with final == 0.  refcnt will be (u_int)-1 at this point,
+ *     and holdcnt will still be non-zero.
  *
- * sysref will not scrap the object until we call sysref_put() once more
- * after the last ref has been dropped.
+ * (2) When holdcnt becomes 0, called with final == 1.  There should no
+ *     longer be anyone with access to the vmspace.
  *
  * VMSPACE_EXIT1 flags the primary deactivation
  * VMSPACE_EXIT2 flags the last reap
  */
 static void
-vmspace_terminate(struct vmspace *vm)
+vmspace_terminate(struct vmspace *vm, int final)
 {
        int count;
 
-       /*
-        *
-        */
        lwkt_gettoken(&vm->vm_map.token);
-       if ((vm->vm_flags & VMSPACE_EXIT1) == 0) {
+       if (final == 0) {
+               KKASSERT((vm->vm_flags & VMSPACE_EXIT1) == 0);
+
+               /*
+                * Get rid of most of the resources.  Leave the kernel pmap
+                * intact.
+                */
                vm->vm_flags |= VMSPACE_EXIT1;
                shmexit(vm);
                pmap_remove_pages(vmspace_pmap(vm), VM_MIN_USER_ADDRESS,
                                  VM_MAX_USER_ADDRESS);
                vm_map_remove(&vm->vm_map, VM_MIN_USER_ADDRESS,
                              VM_MAX_USER_ADDRESS);
-       }
-       if ((vm->vm_flags & VMSPACE_EXIT2) == 0 && vm->vm_exitingcnt == 0) {
+               lwkt_reltoken(&vm->vm_map.token);
+       } else {
+               KKASSERT((vm->vm_flags & VMSPACE_EXIT1) != 0);
+               KKASSERT((vm->vm_flags & VMSPACE_EXIT2) == 0);
+
+               /*
+                * Get rid of remaining basic resources.
+                */
                vm->vm_flags |= VMSPACE_EXIT2;
                cpu_vmspace_free(vm);
                shmexit(vm);
@@ -384,62 +469,9 @@ vmspace_terminate(struct vmspace *vm)
                lwkt_gettoken(&vmspace_pmap(vm)->pm_token);
                pmap_release(vmspace_pmap(vm));
                lwkt_reltoken(&vmspace_pmap(vm)->pm_token);
+               lwkt_reltoken(&vm->vm_map.token);
+               objcache_put(vmspace_cache, vm);
        }
-
-       lwkt_reltoken(&vm->vm_map.token);
-       if (vm->vm_exitingcnt == 0 && vm->vm_holdcount == 0) {
-               KKASSERT(vm->vm_flags & VMSPACE_EXIT1);
-               KKASSERT(vm->vm_flags & VMSPACE_EXIT2);
-               sysref_put(&vm->vm_sysref);
-       }
-}
-
-/*
- * vmspaces are not currently locked.
- */
-static void
-vmspace_lock(struct vmspace *vm __unused)
-{
-}
-
-static void
-vmspace_unlock(struct vmspace *vm __unused)
-{
-}
-
-/*
- * This is called during exit indicating that the vmspace is no
- * longer in used by an exiting process, but the process has not yet
- * been reaped.
- *
- * No requirements.
- */
-void
-vmspace_exitbump(struct vmspace *vm)
-{
-       vmspace_hold(vm);
-       ++vm->vm_exitingcnt;
-       vmspace_drop(vm);       /* handles termination sequencing */
-}
-
-/*
- * Decrement the exitingcnt and issue the stage-2 termination if it becomes
- * zero and the stage1 termination has already occured.
- *
- * No requirements.
- */
-void
-vmspace_exitfree(struct proc *p)
-{
-       struct vmspace *vm;
-
-       vm = p->p_vmspace;
-       p->p_vmspace = NULL;
-       vmspace_hold(vm);
-       KKASSERT(vm->vm_exitingcnt > 0);
-       if (--vm->vm_exitingcnt == 0 && sysref_isinactive(&vm->vm_sysref))
-               vmspace_terminate(vm);
-       vmspace_drop(vm);       /* handles termination sequencing */
 }
 
 /*
@@ -556,7 +588,6 @@ vm_map_init(struct vm_map *map, vm_offset_t min, vm_offset_t max, pmap_t pmap)
        map->flags = 0;
        lwkt_token_init(&map->token, "vm_map");
        lockinit(&map->lock, "vm_maplk", (hz + 9) / 10, 0);
-       TUNABLE_INT("vm.cache_vmspaces", &vmspace_sysref_class.nom_cache);
 }
 
 /*
@@ -3755,7 +3786,7 @@ vmspace_exec(struct proc *p, struct vmspace *vmcopy)
        pmap_replacevm(p, newvmspace, 0);
        lwkt_reltoken(&newvmspace->vm_map.token);
        lwkt_reltoken(&oldvmspace->vm_map.token);
-       vmspace_free(oldvmspace);
+       vmspace_rel(oldvmspace);
 }
 
 /*
@@ -3769,7 +3800,7 @@ vmspace_unshare(struct proc *p)
        struct vmspace *newvmspace;
 
        lwkt_gettoken(&oldvmspace->vm_map.token);
-       if (oldvmspace->vm_sysref.refcnt == 1) {
+       if (vmspace_getrefs(oldvmspace) == 1) {
                lwkt_reltoken(&oldvmspace->vm_map.token);
                return;
        }
@@ -3779,7 +3810,7 @@ vmspace_unshare(struct proc *p)
        pmap_replacevm(p, newvmspace, 0);
        lwkt_reltoken(&newvmspace->vm_map.token);
        lwkt_reltoken(&oldvmspace->vm_map.token);
-       vmspace_free(oldvmspace);
+       vmspace_rel(oldvmspace);
 }
 
 /*
index 7f4789e..b85c3ae 100644 (file)
@@ -265,17 +265,18 @@ struct vmspace {
        caddr_t vm_daddr;       /* user virtual address of data XXX */
        caddr_t vm_maxsaddr;    /* user VA at max stack growth */
        caddr_t vm_minsaddr;    /* user VA at max stack growth */
-#define vm_endcopy     vm_exitingcnt
-       int     vm_exitingcnt;  /* exit/wait context reaping */
-       int     vm_unused01;    /* for future fields */
+#define vm_endcopy     vm_unused01
+       int     vm_unused01;
+       int     vm_unused02;
        int     vm_pagesupply;
-       u_int   vm_holdcount;
-       void    *vm_unused02;   /* for future fields */
-       struct sysref vm_sysref;        /* sysref, refcnt, etc */
+       u_int   vm_holdcnt;     /* temporary hold count and exit sequencing */
+       u_int   vm_refcnt;      /* normal ref count */
 };
 
-#define VMSPACE_EXIT1  0x0001  /* partial exit */
-#define VMSPACE_EXIT2  0x0002  /* full exit */
+#define VMSPACE_EXIT1          0x0001  /* partial exit */
+#define VMSPACE_EXIT2          0x0002  /* full exit */
+
+#define VMSPACE_HOLDEXIT       0x80000000
 
 /*
  * Resident executable holding structure.  A user program can take a snapshot
@@ -521,8 +522,6 @@ vmspace_president_count(struct vmspace *vmspace)
 
 #ifdef _KERNEL
 
-extern struct sysref_class vmspace_sysref_class;
-
 boolean_t vm_map_check_protection (vm_map_t, vm_offset_t, vm_offset_t,
                vm_prot_t, boolean_t);
 struct pmap;
index c52a9c3..ff56bf1 100644 (file)
@@ -390,7 +390,7 @@ kern_mmap(struct vmspace *vms, caddr_t uaddr, size_t ulen,
         * to make the limit reasonable for threads.
         */
        if (max_proc_mmap && 
-           vms->vm_map.nentries >= max_proc_mmap * vms->vm_sysref.refcnt) {
+           vms->vm_map.nentries >= max_proc_mmap * vmspace_getrefs(vms)) {
                error = ENOMEM;
                lwkt_reltoken(&vms->vm_map.token);
                goto done;
index 5e97e23..d4718da 100644 (file)
@@ -120,7 +120,7 @@ sys_vmspace_create(struct vmspace_create_args *uap)
 
        lwkt_gettoken(&vkp->token);
        if (RB_INSERT(vmspace_rb_tree, &vkp->root, ve)) {
-               vmspace_free(ve->vmspace);
+               vmspace_rel(ve->vmspace);
                ve->vmspace = NULL; /* safety */
                kfree(ve, M_VKERNEL);
                error = EEXIST;
@@ -583,7 +583,7 @@ vmspace_entry_delete(struct vmspace_entry *ve, struct vkernel_proc *vkp)
                          VM_MIN_USER_ADDRESS, VM_MAX_USER_ADDRESS);
        vm_map_remove(&ve->vmspace->vm_map,
                      VM_MIN_USER_ADDRESS, VM_MAX_USER_ADDRESS);
-       vmspace_free(ve->vmspace);
+       vmspace_rel(ve->vmspace);
        ve->vmspace = NULL; /* safety */
        kfree(ve, M_VKERNEL);
 }