diff options
author | tegge <tegge@FreeBSD.org> | 2006-05-29 21:28:56 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2006-05-29 21:28:56 +0000 |
commit | 0d5f19116220da1e7a0df73c804bebeb5efdf862 (patch) | |
tree | 2227714d6a33f215f9677debe94c947b9e3fc437 /sys/kern/kern_exit.c | |
parent | ff05f5f32b9783ffa4f05a2b79b7e54056d2f947 (diff) | |
download | FreeBSD-src-0d5f19116220da1e7a0df73c804bebeb5efdf862.zip FreeBSD-src-0d5f19116220da1e7a0df73c804bebeb5efdf862.tar.gz |
Close race between vmspace_exitfree() and exit1() and races between
vmspace_exitfree() and vmspace_free() which could result in the same
vmspace being freed twice.
Factor out part of exit1() into new function vmspace_exit(). Attach
to vmspace0 to allow old vmspace to be freed earlier.
Add new function, vmspace_acquire_ref(), for obtaining a vmspace
reference for a vmspace belonging to another process. Avoid changing
vmspace refcount from 0 to 1 since that could also lead to the same
vmspace being freed twice.
Change vmtotal() and swapout_procs() to use vmspace_acquire_ref().
Reviewed by: alc
Diffstat (limited to 'sys/kern/kern_exit.c')
-rw-r--r-- | sys/kern/kern_exit.c | 31 |
1 files changed, 2 insertions, 29 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index bd44b48..a13c6f3 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -113,14 +113,13 @@ exit1(struct thread *td, int rv) struct proc *p, *nq, *q; struct tty *tp; struct vnode *ttyvp; - struct vmspace *vm; struct vnode *vtmp; #ifdef KTRACE struct vnode *tracevp; struct ucred *tracecred; #endif struct plimit *plim; - int locked, refcnt; + int locked; /* * Drop Giant if caller has it. Eventually we should warn about @@ -300,33 +299,7 @@ retry: } mtx_unlock(&ppeers_lock); - /* The next two chunks should probably be moved to vmspace_exit. */ - vm = p->p_vmspace; - /* - * 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. - * - * Processes sharing the same vmspace may exit in one order, and - * get cleaned up by vmspace_exit() in a different order. The - * last exiting process to reach this point releases as much of - * the environment as it can, and the last process cleaned up - * by vmspace_exit() (which decrements exitingcnt) cleans up the - * remainder. - */ - atomic_add_int(&vm->vm_exitingcnt, 1); - do - refcnt = vm->vm_refcnt; - while (!atomic_cmpset_int(&vm->vm_refcnt, refcnt, refcnt - 1)); - if (refcnt == 1) { - shmexit(vm); - pmap_remove_pages(vmspace_pmap(vm)); - (void) vm_map_remove(&vm->vm_map, vm_map_min(&vm->vm_map), - vm_map_max(&vm->vm_map)); - } + vmspace_exit(td); sx_xlock(&proctree_lock); if (SESS_LEADER(p)) { |