kernel - Refactor the vmspace locking code and several use cases
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 2 Dec 2011 00:54:19 +0000 (16:54 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 2 Dec 2011 00:54:19 +0000 (16:54 -0800)
* Reorder the vnode ref/rele sequence in the exec path so p_textvp is
  left in a more valid state while being initialized.

* Removing the vm_exitingcnt test in exec_new_vmspace().  Release
  various resources unconditionally on the last exiting thread regardless
  of the state of exitingcnt.  This just moves some of the resource
  releases out of the wait*() system call path and back into the exit*()
  path.

* Implement a hold/drop mechanic for vmspaces and use them in procfs_rwmem(),
  vmspace_anonymous_count(), and vmspace_swap_count(), and various other
  places.

  This does a better job protecting the vmspace from deletion while various
  unrelated third parties might be trying to access it.

* Implement vmspace_free() for other code to call instead of them trying
  to call sysref_put() directly.  Interlock with a vmspace_hold() so
  final termination processing always keys off the vm_holdcount.

* Implement vm_object_allocate_hold() and use it in a few places in order
  to allow OBJT_SWAP objects to be allocated atomically, so other third
  parties (like the swapcache cleaning code) can't wiggle their way in
  and access a partially initialized object.

* Reorder the vmspace_terminate() code and introduce some flags to ensure
  that resources are terminated at the proper time and in the proper order.

13 files changed:
sys/kern/imgact_resident.c
sys/kern/kern_exec.c
sys/vfs/procfs/procfs_mem.c
sys/vm/device_pager.c
sys/vm/swap_pager.c
sys/vm/vm_extern.h
sys/vm/vm_glue.c
sys/vm/vm_map.c
sys/vm/vm_map.h
sys/vm/vm_object.c
sys/vm/vm_object.h
sys/vm/vm_vmspace.c
sys/vm/vm_zone.c

index b573faf..1324790 100644 (file)
@@ -305,7 +305,7 @@ restart:
                vmres->vr_vnode = NULL;
            }
            if (vmres->vr_vmspace) {
-               sysref_put(&vmres->vr_vmspace->vm_sysref);
+               vmspace_free(vmres->vr_vmspace);
                vmres->vr_vmspace = NULL;
            }
            kfree(vmres, M_EXEC_RES);
index 1505cdc..26d4102 100644 (file)
@@ -192,6 +192,7 @@ kern_execve(struct nlookupdata *nd, struct image_args *args)
        struct thread *td = curthread;
        struct lwp *lp = td->td_lwp;
        struct proc *p = td->td_proc;
+       struct vnode *ovp;
        register_t *stack_base;
        struct pargs *pa;
        struct sigacts *ops;
@@ -478,12 +479,14 @@ interpret:
        }
 
        /*
-        * Store the vp for use in procfs
+        * Store the vp for use in procfs.  Be sure to keep p_textvp
+        * consistent if we block during the switch-over.
         */
-       if (p->p_textvp)                /* release old reference */
-               vrele(p->p_textvp);
+       ovp = p->p_textvp;
+       vref(imgp->vp);                 /* ref new vp */
        p->p_textvp = imgp->vp;
-       vref(p->p_textvp);
+       if (ovp)                        /* release old vp */
+               vrele(ovp);
 
        /* Release old namecache handle to text file */
        if (p->p_textnch.ncp)
@@ -513,7 +516,7 @@ interpret:
 
        /* Set values passed into the program in registers. */
        exec_setregs(imgp->entry_addr, (u_long)(uintptr_t)stack_base,
-           imgp->ps_strings);
+                    imgp->ps_strings);
 
        /* Set the access time on the vnode */
        vn_mark_atime(imgp->vp, td);
@@ -777,9 +780,6 @@ exec_new_vmspace(struct image_params *imgp, struct vmspace *vmcopy)
         * otherwise, create a new VM space so that other threads are
         * not disrupted.  If we are execing a resident vmspace we
         * create a duplicate of it and remap the stack.
-        *
-        * The exitingcnt test is not strictly necessary but has been
-        * included for code sanity (to make the code more deterministic).
         */
        map = &vmspace->vm_map;
        if (vmcopy) {
@@ -787,8 +787,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 &&
-                  vmspace->vm_exitingcnt == 0) {
+       } else if (vmspace->vm_sysref.refcnt == 1) {
                shmexit(vmspace);
                if (vmspace->vm_upcalls)
                        upc_release(vmspace, ONLY_LWP_IN_PROC(imgp->proc));
index 2232c20..2ac96fd 100644 (file)
@@ -99,6 +99,7 @@ procfs_rwmem(struct proc *curp, struct proc *p, struct uio *uio)
        /*
         * The map we want...
         */
+       vmspace_hold(vm);
        map = &vm->vm_map;
 
        writing = (uio->uio_rw == UIO_WRITE);
@@ -157,6 +158,7 @@ procfs_rwmem(struct proc *curp, struct proc *p, struct uio *uio)
                vm_page_unhold(m);
        } while (error == 0 && uio->uio_resid > 0);
 
+       vmspace_drop(vm);
        kmem_free(&kernel_map, kva, PAGE_SIZE);
 
        return (error);
index bb64a1a..b9199c6 100644 (file)
@@ -127,11 +127,12 @@ dev_pager_alloc(void *handle, off_t size, vm_prot_t prot, off_t foff)
                /*
                 * Allocate object and associate it with the pager.
                 */
-               object = vm_object_allocate(OBJT_DEVICE,
-                                           OFF_TO_IDX(foff + size));
+               object = vm_object_allocate_hold(OBJT_DEVICE,
+                                                OFF_TO_IDX(foff + size));
                object->handle = handle;
                TAILQ_INIT(&object->un_pager.devp.devp_pglist);
                dev->si_object = object;
+               vm_object_drop(object);
        } else {
                /*
                 * Gain a reference to the object.
index e99b006..6ea12a8 100644 (file)
@@ -423,9 +423,8 @@ swap_pager_alloc(void *handle, off_t size, vm_prot_t prot, off_t offset)
        vm_object_t object;
 
        KKASSERT(handle == NULL);
-       object = vm_object_allocate(OBJT_DEFAULT,
-                                   OFF_TO_IDX(offset + PAGE_MASK + size));
-       vm_object_hold(object);
+       object = vm_object_allocate_hold(OBJT_DEFAULT,
+                                        OFF_TO_IDX(offset + PAGE_MASK + size));
        swp_pager_meta_convert(object);
        vm_object_drop(object);
 
index 42149f6..d235126 100644 (file)
@@ -105,6 +105,10 @@ int vm_mmap (vm_map_t, vm_offset_t *, vm_size_t, vm_prot_t, vm_prot_t, int, void
 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_hold (struct vmspace *);
+void vmspace_drop (struct vmspace *);
 struct vmspace *vmspace_fork (struct vmspace *);
 void vmspace_exec (struct proc *, struct vmspace *);
 void vmspace_unshare (struct proc *);
index 526cdbf..a0e5da9 100644 (file)
@@ -245,8 +245,8 @@ vm_fork(struct proc *p1, struct proc *p2, int flags)
        }
 
        if (flags & RFMEM) {
+               vmspace_ref(p1->p_vmspace);
                p2->p_vmspace = p1->p_vmspace;
-               sysref_get(&p1->p_vmspace->vm_sysref);
        }
 
        while (vm_page_count_severe()) {
index 08059cf..e3fd77e 100644 (file)
@@ -250,20 +250,69 @@ vmspace_alloc(vm_offset_t min, vm_offset_t max)
        vm = sysref_alloc(&vmspace_sysref_class);
        bzero(&vm->vm_startcopy,
              (char *)&vm->vm_endcopy - (char *)&vm->vm_startcopy);
-       vm_map_init(&vm->vm_map, min, max, NULL);
+       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.
+        */
+       KKASSERT(vm->vm_holdcount == 0);
+       KKASSERT(vm->vm_exitingcnt == 0);
+       vmspace_hold(vm);
        pmap_pinit(vmspace_pmap(vm));           /* (some fields reused) */
-       lwkt_gettoken(&vm->vm_map.token);
        vm->vm_map.pmap = vmspace_pmap(vm);             /* XXX */
        vm->vm_shm = NULL;
-       vm->vm_exitingcnt = 0;
+       vm->vm_flags = 0;
        cpu_vmspace_alloc(vm);
        sysref_activate(&vm->vm_sysref);
-       lwkt_reltoken(&vm->vm_map.token);
+       vmspace_drop(vm);
 
        return (vm);
 }
 
 /*
+ * Free a primary reference to a vmspace.  This can trigger a
+ * stage-1 termination.
+ */
+void
+vmspace_free(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);
+}
+
+void
+vmspace_ref(struct vmspace *vm)
+{
+       sysref_get(&vm->vm_sysref);
+}
+
+void
+vmspace_hold(struct vmspace *vm)
+{
+       refcount_acquire(&vm->vm_holdcount);
+       lwkt_gettoken(&vm->vm_map.token);
+}
+
+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);
+               }
+       }
+}
+
+/*
  * 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.
@@ -279,18 +328,21 @@ vmspace_dtor(void *obj, void *private)
 }
 
 /*
- * Called in two cases: 
+ * Called in three cases:
+ *
+ * (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)
  *
- * (1) When the last sysref is dropped, but exitingcnt might still be
- *     non-zero.
+ * (2) When exitingcount becomes 0 on the last reap
+ *     (holdcount will not be 0 because the vmspace is held through the op)
  *
- * (2) When there are no sysrefs (i.e. refcnt is negative) left and the
- *     exitingcnt becomes zero
+ * (3) When the holdcount becomes 0 in addition to the above two
  *
  * sysref will not scrap the object until we call sysref_put() once more
  * after the last ref has been dropped.
  *
- * Interlocked by the sysref API.
+ * VMSPACE_EXIT1 flags the primary deactivation
+ * VMSPACE_EXIT2 flags the last reap
  */
 static void
 vmspace_terminate(struct vmspace *vm)
@@ -298,46 +350,46 @@ vmspace_terminate(struct vmspace *vm)
        int count;
 
        /*
-        * If exitingcnt is non-zero we can't get rid of the entire vmspace
-        * yet, but we can scrap user memory.
+        *
         */
        lwkt_gettoken(&vm->vm_map.token);
-       if (vm->vm_exitingcnt) {
+       if ((vm->vm_flags & VMSPACE_EXIT1) == 0) {
+               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);
-               lwkt_reltoken(&vm->vm_map.token);
-               return;
        }
-       cpu_vmspace_free(vm);
-
-       /*
-        * Make sure any SysV shm is freed, it might not have in
-        * exit1()
-        */
-       shmexit(vm);
+       if ((vm->vm_flags & VMSPACE_EXIT2) == 0 && vm->vm_exitingcnt == 0) {
+               vm->vm_flags |= VMSPACE_EXIT2;
+               cpu_vmspace_free(vm);
+               shmexit(vm);
+               KKASSERT(vm->vm_upcalls == NULL);
 
-       KKASSERT(vm->vm_upcalls == NULL);
+               /*
+                * Lock the map, to wait out all other references to it.
+                * Delete all of the mappings and pages they hold, then call
+                * the pmap module to reclaim anything left.
+                */
+               count = vm_map_entry_reserve(MAP_RESERVE_COUNT);
+               vm_map_lock(&vm->vm_map);
+               vm_map_delete(&vm->vm_map, vm->vm_map.min_offset,
+                             vm->vm_map.max_offset, &count);
+               vm_map_unlock(&vm->vm_map);
+               vm_map_entry_release(count);
 
-       /*
-        * Lock the map, to wait out all other references to it.
-        * Delete all of the mappings and pages they hold, then call
-        * the pmap module to reclaim anything left.
-        */
-       count = vm_map_entry_reserve(MAP_RESERVE_COUNT);
-       vm_map_lock(&vm->vm_map);
-       vm_map_delete(&vm->vm_map, vm->vm_map.min_offset,
-               vm->vm_map.max_offset, &count);
-       vm_map_unlock(&vm->vm_map);
-       vm_map_entry_release(count);
+               lwkt_gettoken(&vmspace_pmap(vm)->pm_token);
+               pmap_release(vmspace_pmap(vm));
+               lwkt_reltoken(&vmspace_pmap(vm)->pm_token);
+       }
 
-       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);
-       sysref_put(&vm->vm_sysref);
+       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);
+       }
 }
 
 /*
@@ -356,21 +408,21 @@ 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 cleaned up.
+ * been reaped.
  *
  * No requirements.
  */
 void
 vmspace_exitbump(struct vmspace *vm)
 {
-       lwkt_gettoken(&vm->vm_map.token);
+       vmspace_hold(vm);
        ++vm->vm_exitingcnt;
-       lwkt_reltoken(&vm->vm_map.token);
+       vmspace_drop(vm);       /* handles termination sequencing */
 }
 
 /*
- * This is called in the wait*() handling code.  The vmspace can be terminated
- * after the last wait is finished using it.
+ * Decrement the exitingcnt and issue the stage-2 termination if it becomes
+ * zero and the stage1 termination has already occured.
  *
  * No requirements.
  */
@@ -380,15 +432,12 @@ vmspace_exitfree(struct proc *p)
        struct vmspace *vm;
 
        vm = p->p_vmspace;
-       lwkt_gettoken(&vm->vm_map.token);
        p->p_vmspace = NULL;
-
-       if (--vm->vm_exitingcnt == 0 && sysref_isinactive(&vm->vm_sysref)) {
-               lwkt_reltoken(&vm->vm_map.token);
+       vmspace_hold(vm);
+       KKASSERT(vm->vm_exitingcnt > 0);
+       if (--vm->vm_exitingcnt == 0 && sysref_isinactive(&vm->vm_sysref))
                vmspace_terminate(vm);
-       } else {
-               lwkt_reltoken(&vm->vm_map.token);
-       }
+       vmspace_drop(vm);       /* handles termination sequencing */
 }
 
 /*
@@ -408,7 +457,7 @@ vmspace_swap_count(struct vmspace *vm)
        int count = 0;
        int n;
 
-       lwkt_gettoken(&vm->vm_map.token);
+       vmspace_hold(vm);
        for (cur = map->header.next; cur != &map->header; cur = cur->next) {
                switch(cur->maptype) {
                case VM_MAPTYPE_NORMAL:
@@ -425,7 +474,8 @@ vmspace_swap_count(struct vmspace *vm)
                        break;
                }
        }
-       lwkt_reltoken(&vm->vm_map.token);
+       vmspace_drop(vm);
+
        return(count);
 }
 
@@ -444,7 +494,7 @@ vmspace_anonymous_count(struct vmspace *vm)
        vm_object_t object;
        int count = 0;
 
-       lwkt_gettoken(&vm->vm_map.token);
+       vmspace_hold(vm);
        for (cur = map->header.next; cur != &map->header; cur = cur->next) {
                switch(cur->maptype) {
                case VM_MAPTYPE_NORMAL:
@@ -461,7 +511,8 @@ vmspace_anonymous_count(struct vmspace *vm)
                        break;
                }
        }
-       lwkt_reltoken(&vm->vm_map.token);
+       vmspace_drop(vm);
+
        return(count);
 }
 
@@ -3153,6 +3204,13 @@ vm_map_copy_entry(vm_map_t src_map, vm_map_t dst_map,
                 * We cannot use *_hold() here because the split code will
                 * probably try to destroy the object.  The lock is a pool
                 * token and doesn't care.
+                *
+                * We must bump src_map->timestamp when setting
+                * MAP_ENTRY_NEEDS_COPY to force any concurrent fault
+                * to retry, otherwise the concurrent fault might improperly
+                * install a RW pte when its supposed to be a RO(COW) pte.
+                * This race can occur because a vnode-backed fault may have
+                * to temporarily release the map lock.
                 */
                if (src_entry->object.vm_object != NULL) {
                        vm_map_split(src_entry);
@@ -3163,6 +3221,7 @@ vm_map_copy_entry(vm_map_t src_map, vm_map_t dst_map,
                        dst_entry->eflags |= (MAP_ENTRY_COW |
                                              MAP_ENTRY_NEEDS_COPY);
                        dst_entry->offset = src_entry->offset;
+                       ++src_map->timestamp;
                } else {
                        dst_entry->object.vm_object = NULL;
                        dst_entry->offset = 0;
@@ -3640,15 +3699,12 @@ 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);
-       sysref_put(&oldvmspace->vm_sysref);
+       vmspace_free(oldvmspace);
 }
 
 /*
  * Unshare the specified VM space for forcing COW.  This
  * is called by rfork, for the (RFMEM|RFPROC) == 0 case.
- *
- * The exitingcnt test is not strictly necessary but has been
- * included for code sanity (to make the code a bit more deterministic).
  */
 void
 vmspace_unshare(struct proc *p) 
@@ -3657,7 +3713,7 @@ vmspace_unshare(struct proc *p)
        struct vmspace *newvmspace;
 
        lwkt_gettoken(&oldvmspace->vm_map.token);
-       if (oldvmspace->vm_sysref.refcnt == 1 && oldvmspace->vm_exitingcnt == 0) {
+       if (oldvmspace->vm_sysref.refcnt == 1) {
                lwkt_reltoken(&oldvmspace->vm_map.token);
                return;
        }
@@ -3667,7 +3723,7 @@ vmspace_unshare(struct proc *p)
        pmap_replacevm(p, newvmspace, 0);
        lwkt_reltoken(&newvmspace->vm_map.token);
        lwkt_reltoken(&oldvmspace->vm_map.token);
-       sysref_put(&oldvmspace->vm_sysref);
+       vmspace_free(oldvmspace);
 }
 
 /*
index ee4c546..e1780a6 100644 (file)
@@ -268,7 +268,7 @@ struct vmupcall {
 struct vmspace {
        struct vm_map vm_map;   /* VM address map */
        struct pmap vm_pmap;    /* private physical map */
-       int vm_unused01;
+       int vm_flags;
        caddr_t vm_shm;         /* SYS5 shared memory private data XXX */
 /* we copy from vm_startcopy to the end of the structure on fork */
 #define vm_startcopy vm_rssize
@@ -282,13 +282,17 @@ struct vmspace {
        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;  /* several procsses zombied in exit1 */
+       int     vm_exitingcnt;  /* exit/wait context reaping */
        int     vm_upccount;    /* number of registered upcalls */
        int     vm_pagesupply;
+       u_int   vm_holdcount;
        struct vmupcall *vm_upcalls;    /* registered upcalls */
        struct sysref vm_sysref;        /* sysref, refcnt, etc */
 };
 
+#define VMSPACE_EXIT1  0x0001  /* partial exit */
+#define VMSPACE_EXIT2  0x0002  /* full exit */
+
 /*
  * Resident executable holding structure.  A user program can take a snapshot
  * of just its VM address space (typically done just after dynamic link
index 93a46f3..68167b9 100644 (file)
@@ -385,7 +385,7 @@ vm_object_drop(vm_object_t obj)
 }
 
 /*
- * Initialize a freshly allocated object
+ * Initialize a freshly allocated object, returning a held object.
  *
  * Used only by vm_object_allocate() and zinitna().
  *
@@ -431,6 +431,7 @@ _vm_object_allocate(objtype_t type, vm_pindex_t size, vm_object_t object)
        RB_INIT(&object->swblock_root);
        vm_object_lock_init(object);
 
+       vm_object_hold(object);
        lwkt_gettoken(&vmobj_token);
        TAILQ_INSERT_TAIL(&vm_object_list, object, object_list);
        vm_object_count++;
@@ -449,6 +450,7 @@ vm_object_init(void)
        
        _vm_object_allocate(OBJT_DEFAULT, OFF_TO_IDX(KvaEnd),
                            &kernel_object);
+       vm_object_drop(&kernel_object);
 
        obj_zone = &obj_zone_store;
        zbootinit(obj_zone, "VM OBJECT", sizeof (struct vm_object),
@@ -474,6 +476,23 @@ vm_object_allocate(objtype_t type, vm_pindex_t size)
        result = (vm_object_t) zalloc(obj_zone);
 
        _vm_object_allocate(type, size, result);
+       vm_object_drop(result);
+
+       return (result);
+}
+
+/*
+ * This version returns a held object, allowing further atomic initialization
+ * of the object.
+ */
+vm_object_t
+vm_object_allocate_hold(objtype_t type, vm_pindex_t size)
+{
+       vm_object_t result;
+
+       result = (vm_object_t) zalloc(obj_zone);
+
+       _vm_object_allocate(type, size, result);
 
        return (result);
 }
index 63e9f9e..4ae6fad 100644 (file)
@@ -276,6 +276,7 @@ vm_object_token(vm_object_t obj)
 }
 
 vm_object_t vm_object_allocate (objtype_t, vm_pindex_t);
+vm_object_t vm_object_allocate_hold (objtype_t, vm_pindex_t);
 void _vm_object_allocate (objtype_t, vm_pindex_t, vm_object_t);
 boolean_t vm_object_coalesce (vm_object_t, vm_pindex_t, vm_size_t, vm_size_t);
 void vm_object_collapse (vm_object_t, struct vm_object_dealloc_list **);
index 7002b17..9f8d7bb 100644 (file)
@@ -119,7 +119,8 @@ sys_vmspace_create(struct vmspace_create_args *uap)
 
        lwkt_gettoken(&vkp->token);
        if (RB_INSERT(vmspace_rb_tree, &vkp->root, ve)) {
-               sysref_put(&ve->vmspace->vm_sysref);
+               vmspace_free(ve->vmspace);
+               ve->vmspace = NULL; /* safety */
                kfree(ve, M_VKERNEL);
                error = EEXIST;
        } else {
@@ -575,7 +576,8 @@ 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);
-       sysref_put(&ve->vmspace->vm_sysref);
+       vmspace_free(ve->vmspace);
+       ve->vmspace = NULL; /* safety */
        kfree(ve, M_VKERNEL);
 }
 
index 163ad8e..842dd26 100644 (file)
@@ -280,6 +280,7 @@ zinitna(vm_zone_t z, vm_object_t obj, char *name, int size,
                } else {
                        z->zobj = obj;
                        _vm_object_allocate(OBJT_DEFAULT, z->zpagemax, obj);
+                       vm_object_drop(obj);
                }
                z->zallocflag = VM_ALLOC_SYSTEM | VM_ALLOC_INTERRUPT |
                                VM_ALLOC_NORMAL | VM_ALLOC_RETRY;