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