summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_exit.c7
-rw-r--r--sys/vm/vm_extern.h1
-rw-r--r--sys/vm/vm_glue.c2
-rw-r--r--sys/vm/vm_map.c45
-rw-r--r--sys/vm/vm_map.h2
5 files changed, 37 insertions, 20 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 51b77c4..e8c5558 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -217,13 +217,14 @@ exit1(td, rv)
* Can't free the entire vmspace as the kernel stack
* may be mapped within that space also.
*/
- if (vm->vm_refcnt == 1) {
+ if (--vm->vm_refcnt == 0) {
if (vm->vm_shm)
shmexit(p);
pmap_remove_pages(vmspace_pmap(vm), VM_MIN_ADDRESS,
VM_MAXUSER_ADDRESS);
(void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS,
VM_MAXUSER_ADDRESS);
+ vm->vm_freer = p;
}
PROC_LOCK(p);
@@ -400,8 +401,8 @@ exit1(td, rv)
/*
* Finally, call machine-dependent code to release the remaining
* resources including address space, the kernel stack and pcb.
- * The address space is released by "vmspace_free(p->p_vmspace)"
- * in vm_waitproc();
+ * The address space is released by "vmspace_exitfree(p)" in
+ * vm_waitproc().
*/
cpu_exit(td);
diff --git a/sys/vm/vm_extern.h b/sys/vm/vm_extern.h
index 7f24e11..728b5b6 100644
--- a/sys/vm/vm_extern.h
+++ b/sys/vm/vm_extern.h
@@ -90,6 +90,7 @@ struct vmspace *vmspace_fork __P((struct vmspace *));
void vmspace_exec __P((struct proc *));
void vmspace_unshare __P((struct proc *));
void vmspace_free __P((struct vmspace *));
+void vmspace_exitfree __P((struct proc *));
void vnode_pager_setsize __P((struct vnode *, vm_ooffset_t));
void vslock __P((caddr_t, u_int));
void vsunlock __P((caddr_t, u_int));
diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c
index f9fb68c..d2ad1e2 100644
--- a/sys/vm/vm_glue.c
+++ b/sys/vm/vm_glue.c
@@ -305,7 +305,7 @@ vm_waitproc(p)
pmap_dispose_proc(p); /* drop per-process resources */
FOREACH_THREAD_IN_PROC(p, td)
pmap_dispose_thread(td);
- vmspace_free(p->p_vmspace); /* and clean-out the vmspace */
+ vmspace_exitfree(p); /* and clean-out the vmspace */
}
/*
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index 8dc3550..8b7a230 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -172,6 +172,7 @@ vmspace_alloc(min, max)
vm->vm_map.pmap = vmspace_pmap(vm); /* XXX */
vm->vm_refcnt = 1;
vm->vm_shm = NULL;
+ vm->vm_freer = NULL;
return (vm);
}
@@ -189,6 +190,24 @@ vm_init2(void)
vm_object_init2();
}
+static __inline void
+vmspace_dofree( struct vmspace *vm)
+{
+ CTR1(KTR_VM, "vmspace_free: %p", vm);
+ /*
+ * 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.
+ */
+ vm_map_lock(&vm->vm_map);
+ (void) vm_map_delete(&vm->vm_map, vm->vm_map.min_offset,
+ vm->vm_map.max_offset);
+ vm_map_unlock(&vm->vm_map);
+ pmap_release(vmspace_pmap(vm));
+ vm_map_destroy(&vm->vm_map);
+ zfree(vmspace_zone, vm);
+}
+
void
vmspace_free(struct vmspace *vm)
{
@@ -197,23 +216,17 @@ vmspace_free(struct vmspace *vm)
if (vm->vm_refcnt == 0)
panic("vmspace_free: attempt to free already freed vmspace");
- if (--vm->vm_refcnt == 0) {
+ if (--vm->vm_refcnt == 0)
+ vmspace_dofree(vm);
+}
- CTR1(KTR_VM, "vmspace_free: %p", vm);
- /*
- * 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.
- */
- vm_map_lock(&vm->vm_map);
- (void) vm_map_delete(&vm->vm_map, vm->vm_map.min_offset,
- vm->vm_map.max_offset);
- vm_map_unlock(&vm->vm_map);
+void
+vmspace_exitfree(struct proc *p)
+{
+ GIANT_REQUIRED;
- pmap_release(vmspace_pmap(vm));
- vm_map_destroy(&vm->vm_map);
- zfree(vmspace_zone, vm);
- }
+ if (p == p->p_vmspace->vm_freer)
+ vmspace_dofree(p->p_vmspace);
}
/*
@@ -2317,7 +2330,7 @@ vmspace_fork(struct vmspace *vm1)
vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset);
bcopy(&vm1->vm_startcopy, &vm2->vm_startcopy,
- (caddr_t) (vm1 + 1) - (caddr_t) &vm1->vm_startcopy);
+ (caddr_t) &vm1->vm_endcopy - (caddr_t) &vm1->vm_startcopy);
new_map = &vm2->vm_map; /* XXX */
new_map->timestamp = 1;
diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h
index c9831d5..b376cc1 100644
--- a/sys/vm/vm_map.h
+++ b/sys/vm/vm_map.h
@@ -188,6 +188,8 @@ 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_freer
+ struct proc *vm_freer; /* vm freed on whose behalf */
};
#ifdef _KERNEL
OpenPOWER on IntegriCloud