summaryrefslogtreecommitdiffstats
path: root/sys/kern/sys_process.c
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2003-08-09 18:01:19 +0000
committeralc <alc@FreeBSD.org>2003-08-09 18:01:19 +0000
commitc37c941215a68987b1783af2e3055b2bc4d90001 (patch)
treed76920681e1bfb05727d99eb00e90710046dae04 /sys/kern/sys_process.c
parent32aa925e1158e18c577347cd6a7596b26c565c8a (diff)
downloadFreeBSD-src-c37c941215a68987b1783af2e3055b2bc4d90001.zip
FreeBSD-src-c37c941215a68987b1783af2e3055b2bc4d90001.tar.gz
Background: When proc_rwmem() wired and mapped a page, it also added
a reference to the containing object. The purpose of the reference being to prevent the destruction of the object and an attempt to free the wired page. (Wired pages can't be freed.) Unfortunately, this approach does not work. Some operations, like fork(2) that call vm_object_split(), can move the wired page to a difference object, thereby making the reference pointless and opening the possibility of the wired page being freed. A solution is to use vm_page_hold() in place of vm_page_wire(). Held pages can be freed. They are moved to a special hold queue until the hold is released. Submitted by: tegge
Diffstat (limited to 'sys/kern/sys_process.c')
-rw-r--r--sys/kern/sys_process.c35
1 files changed, 5 insertions, 30 deletions
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index aa79103..3e38319 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -227,16 +227,8 @@ proc_rwmem(struct proc *p, struct uio *uio)
tmap = map;
error = vm_map_lookup(&tmap, pageno, reqprot, &out_entry,
&object, &pindex, &out_prot, &wired);
-
if (error) {
error = EFAULT;
-
- /*
- * Make sure that there is no residue in 'object' from
- * an error return on vm_map_lookup.
- */
- object = NULL;
-
break;
}
VM_OBJECT_LOCK(object);
@@ -253,32 +245,21 @@ proc_rwmem(struct proc *p, struct uio *uio)
}
VM_OBJECT_UNLOCK(object);
if (m == NULL) {
- error = EFAULT;
-
- /*
- * Make sure that there is no residue in 'object' from
- * an error return on vm_map_lookup.
- */
- object = NULL;
-
vm_map_lookup_done(tmap, out_entry);
-
+ error = EFAULT;
break;
}
/*
- * Wire the page into memory
+ * Hold the page in memory.
*/
vm_page_lock_queues();
- vm_page_wire(m);
+ vm_page_hold(m);
vm_page_unlock_queues();
/*
* We're done with tmap now.
- * But reference the object first, so that we won't loose
- * it.
*/
- vm_object_reference(object);
vm_map_lookup_done(tmap, out_entry);
pmap_qenter(kva, &m, 1);
@@ -291,20 +272,14 @@ proc_rwmem(struct proc *p, struct uio *uio)
pmap_qremove(kva, 1);
/*
- * release the page and the object
+ * Release the page.
*/
vm_page_lock_queues();
- vm_page_unwire(m, 1);
+ vm_page_unhold(m);
vm_page_unlock_queues();
- vm_object_deallocate(object);
-
- object = NULL;
} while (error == 0 && uio->uio_resid > 0);
- if (object)
- vm_object_deallocate(object);
-
kmem_free(kernel_map, kva, PAGE_SIZE);
vmspace_free(vm);
return (error);
OpenPOWER on IntegriCloud