Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/uvm re-apply uvm_fault.c 1.104. fixes will follow.
details: https://anonhg.NetBSD.org/src/rev/2d03e1aafeaa
branches: trunk
changeset: 587622:2d03e1aafeaa
user: yamt <yamt%NetBSD.org@localhost>
date: Tue Jan 31 14:05:47 2006 +0000
description:
re-apply uvm_fault.c 1.104. fixes will follow.
diffstat:
sys/uvm/uvm_fault.c | 289 +++++++++++++++++++++++++++++++++------------------
1 files changed, 187 insertions(+), 102 deletions(-)
diffs (truncated from 434 to 300 lines):
diff -r 7d9f7d81fb01 -r 2d03e1aafeaa sys/uvm/uvm_fault.c
--- a/sys/uvm/uvm_fault.c Tue Jan 31 14:03:53 2006 +0000
+++ b/sys/uvm/uvm_fault.c Tue Jan 31 14:05:47 2006 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_fault.c,v 1.105 2006/01/30 11:50:17 yamt Exp $ */
+/* $NetBSD: uvm_fault.c,v 1.106 2006/01/31 14:05:47 yamt Exp $ */
/*
*
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,v 1.105 2006/01/30 11:50:17 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,v 1.106 2006/01/31 14:05:47 yamt Exp $");
#include "opt_uvmhist.h"
@@ -536,6 +536,143 @@
}
/*
+ * uvmfault_promote: promote data to a new anon. used for 1B and 2B.
+ *
+ * 1. allocate an anon and a page.
+ * 2. fill its contents.
+ * 3. put it into amap.
+ *
+ * => if we fail (result != 0) we unlock everything.
+ * => on success, return a new locked anon via 'nanon'.
+ * (*nanon)->an_page will be a resident, locked, dirty page.
+ */
+
+static int
+uvmfault_promote(struct uvm_faultinfo *ufi,
+ struct vm_anon *oanon,
+ struct vm_page *uobjpage,
+ struct vm_anon **nanon, /* OUT: allocated anon */
+ struct vm_anon **spare)
+{
+ struct vm_amap *amap = ufi->entry->aref.ar_amap;
+ struct uvm_object *uobj;
+ struct vm_anon *anon;
+ struct vm_page *pg;
+ struct vm_page *opg;
+ int error;
+ UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist);
+
+ if (oanon) {
+ /* anon COW */
+ opg = oanon->an_page;
+ KASSERT(opg != NULL);
+ KASSERT(opg->uobject == NULL || opg->loan_count > 0);
+ } else if (uobjpage != PGO_DONTCARE) {
+ /* object-backed COW */
+ opg = uobjpage;
+ KASSERT(opg->uobject == ufi->entry->object.uvm_obj);
+ } else {
+ /* ZFOD */
+ opg = NULL;
+ }
+ if (opg != NULL) {
+ uobj = opg->uobject;
+ } else {
+ uobj = NULL;
+ }
+
+ KASSERT(amap != NULL);
+ KASSERT(uobjpage != NULL);
+ KASSERT(uobjpage == PGO_DONTCARE || (uobjpage->flags & PG_BUSY) != 0);
+ LOCK_ASSERT(simple_lock_held(&amap->am_l));
+ LOCK_ASSERT(oanon == NULL || simple_lock_held(&oanon->an_lock));
+ LOCK_ASSERT(uobj == NULL || simple_lock_held(&uobj->vmobjlock));
+ LOCK_ASSERT(*spare == NULL || !simple_lock_held(&(*spare)->an_lock));
+
+ if (*spare != NULL) {
+ anon = *spare;
+ *spare = NULL;
+ simple_lock(&anon->an_lock);
+ } else if (ufi->map != kernel_map) {
+ anon = uvm_analloc();
+ } else {
+ UVMHIST_LOG(maphist, "kernel_map, unlock and retry", 0,0,0,0);
+
+ /*
+ * we can't allocate anons with kernel_map locked.
+ */
+
+ uvm_page_unbusy(&uobjpage, 1);
+ uvmfault_unlockall(ufi, amap, uobj, oanon);
+
+ *spare = uvm_analloc();
+ if (*spare == NULL) {
+ goto nomem;
+ }
+ simple_unlock(&(*spare)->an_lock);
+ error = ERESTART;
+ goto done;
+ }
+ if (anon) {
+
+ /*
+ * The new anon is locked.
+ *
+ * if opg == NULL, we want a zero'd, dirty page,
+ * so have uvm_pagealloc() do that for us.
+ */
+
+ pg = uvm_pagealloc(NULL, 0, anon,
+ (opg == NULL) ? UVM_PGA_ZERO : 0);
+ } else {
+ pg = NULL;
+ }
+
+ /*
+ * out of memory resources?
+ */
+
+ if (pg == NULL) {
+ /* save anon for the next try. */
+ if (anon != NULL) {
+ simple_unlock(&anon->an_lock);
+ *spare = anon;
+ }
+
+ /* unlock and fail ... */
+ uvm_page_unbusy(&uobjpage, 1);
+ uvmfault_unlockall(ufi, amap, uobj, oanon);
+nomem:
+ if (!uvm_reclaimable()) {
+ UVMHIST_LOG(maphist, "out of VM", 0,0,0,0);
+ uvmexp.fltnoanon++;
+ error = ENOMEM;
+ goto done;
+ }
+
+ UVMHIST_LOG(maphist, "out of RAM, waiting for more", 0,0,0,0);
+ uvmexp.fltnoram++;
+ uvm_wait("flt_noram5");
+ error = ERESTART;
+ goto done;
+ }
+
+ /* copy page [pg now dirty] */
+ if (opg) {
+ uvm_pagecopy(opg, pg);
+ }
+
+ amap_add(&ufi->entry->aref, ufi->orig_rvaddr - ufi->entry->start, anon,
+ oanon != NULL);
+
+ *nanon = anon;
+ error = 0;
+done:
+ return error;
+}
+
+
+/*
* F A U L T - m a i n e n t r y p o i n t
*/
@@ -567,13 +704,14 @@
struct vm_amap *amap;
struct uvm_object *uobj;
struct vm_anon *anons_store[UVM_MAXRANGE], **anons, *anon, *oanon;
+ struct vm_anon *anon_spare;
struct vm_page *pages[UVM_MAXRANGE], *pg, *uobjpage;
UVMHIST_FUNC("uvm_fault"); UVMHIST_CALLED(maphist);
UVMHIST_LOG(maphist, "(map=0x%x, vaddr=0x%x, ft=%d, at=%d)",
orig_map, vaddr, fault_type, access_type);
- anon = NULL;
+ anon = anon_spare = NULL;
pg = NULL;
uvmexp.faults++; /* XXX: locking? */
@@ -604,7 +742,8 @@
if (uvmfault_lookup(&ufi, FALSE) == FALSE) {
UVMHIST_LOG(maphist, "<- no mapping @ 0x%x", vaddr, 0,0,0);
- return (EFAULT);
+ error = EFAULT;
+ goto done;
}
/* locked: maps(read) */
@@ -629,7 +768,8 @@
"<- protection failure (prot=0x%x, access=0x%x)",
ufi.entry->protection, access_type, 0, 0);
uvmfault_unlockmaps(&ufi, FALSE);
- return EACCES;
+ error = EACCES;
+ goto done;
}
/*
@@ -692,7 +832,8 @@
if (amap == NULL && uobj == NULL) {
uvmfault_unlockmaps(&ufi, FALSE);
UVMHIST_LOG(maphist,"<- no backing store, no overlay",0,0,0,0);
- return (EFAULT);
+ error = EFAULT;
+ goto done;
}
/*
@@ -886,7 +1027,7 @@
/*
* object fault routine responsible for pmap_update().
*/
- return error;
+ goto done;
}
/*
@@ -1064,7 +1205,7 @@
goto ReFault;
default:
- return error;
+ goto done;
}
/*
@@ -1180,41 +1321,24 @@
UVMHIST_LOG(maphist, " case 1B: COW fault",0,0,0,0);
uvmexp.flt_acow++;
oanon = anon; /* oanon = old, locked anon */
- anon = uvm_analloc();
- if (anon) {
- /* new anon is locked! */
- pg = uvm_pagealloc(NULL, 0, anon, 0);
+
+ error = uvmfault_promote(&ufi, oanon, PGO_DONTCARE,
+ &anon, &anon_spare);
+ switch (error) {
+ case 0:
+ break;
+ case ERESTART:
+ goto ReFault;
+ default:
+ goto done;
}
- /* check for out of RAM */
- if (anon == NULL || pg == NULL) {
- if (anon) {
- anon->an_ref--;
- simple_unlock(&anon->an_lock);
- uvm_anfree(anon);
- }
- uvmfault_unlockall(&ufi, amap, uobj, oanon);
- if (!uvm_reclaimable()) {
- UVMHIST_LOG(maphist,
- "<- failed. out of VM",0,0,0,0);
- uvmexp.fltnoanon++;
- return ENOMEM;
- }
-
- uvmexp.fltnoram++;
- uvm_wait("flt_noram3"); /* out of RAM, wait for more */
- goto ReFault;
- }
-
- /* got all resources, replace anon with nanon */
- uvm_pagecopy(oanon->an_page, pg);
+ pg = anon->an_page;
uvm_lock_pageq();
uvm_pageactivate(pg);
+ uvm_unlock_pageq();
pg->flags &= ~(PG_BUSY|PG_FAKE);
- uvm_unlock_pageq();
UVM_PAGE_OWN(pg, NULL);
- amap_add(&ufi.entry->aref, ufi.orig_rvaddr - ufi.entry->start,
- anon, TRUE);
/* deref: can not drop to zero here by defn! */
oanon->an_ref--;
@@ -1262,7 +1386,8 @@
UVMHIST_LOG(maphist,
"<- failed. out of VM",0,0,0,0);
/* XXX instrumentation */
- return ENOMEM;
+ error = ENOMEM;
+ goto done;
}
/* XXX instrumentation */
uvm_wait("flt_pmfail1");
@@ -1299,7 +1424,8 @@
simple_unlock(&anon->an_lock);
uvmfault_unlockall(&ufi, amap, uobj, oanon);
pmap_update(ufi.orig_map->pmap);
- return 0;
+ error = 0;
+ goto done;
Case2:
/*
Home |
Main Index |
Thread Index |
Old Index