summaryrefslogtreecommitdiffstats
path: root/sys/vm/vm_map.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vm/vm_map.c')
-rw-r--r--sys/vm/vm_map.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index b7f6ac0..d51bd2d 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -258,7 +258,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;
+ vm->vm_exitingcnt = 0;
return (vm);
}
@@ -304,7 +304,7 @@ 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 && vm->vm_exitingcnt == 0)
vmspace_dofree(vm);
}
@@ -314,11 +314,22 @@ vmspace_exitfree(struct proc *p)
struct vmspace *vm;
GIANT_REQUIRED;
- if (p == p->p_vmspace->vm_freer) {
- vm = p->p_vmspace;
- p->p_vmspace = NULL;
+ vm = p->p_vmspace;
+ p->p_vmspace = NULL;
+
+ /*
+ * cleanup by parent process wait()ing on exiting child. vm_refcnt
+ * may not be 0 (e.g. fork() and child exits without exec()ing).
+ * exitingcnt may increment above 0 and drop back down to zero
+ * several times while vm_refcnt is held non-zero. vm_refcnt
+ * may also increment above 0 and drop back down to zero several
+ * times while vm_exitingcnt is held non-zero.
+ *
+ * The last wait on the exiting child's vmspace will clean up
+ * the remainder of the vmspace.
+ */
+ if (--vm->vm_exitingcnt == 0 && vm->vm_refcnt == 0)
vmspace_dofree(vm);
- }
}
/*
OpenPOWER on IntegriCloud