revert uvm_fault.c 1.104 for now. see PR/28372, PR/32665.

This commit is contained in:
yamt 2006-01-30 11:50:17 +00:00
parent ed1116428c
commit 7fcddedf0b

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_fault.c,v 1.104 2006/01/21 13:13:07 yamt Exp $ */
/* $NetBSD: uvm_fault.c,v 1.105 2006/01/30 11:50:17 yamt Exp $ */
/*
*
@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,v 1.104 2006/01/21 13:13:07 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,v 1.105 2006/01/30 11:50:17 yamt Exp $");
#include "opt_uvmhist.h"
@ -535,143 +535,6 @@ released:
/*NOTREACHED*/
}
/*
* 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
*/
@ -704,14 +567,13 @@ uvm_fault(struct vm_map *orig_map, vaddr_t vaddr, vm_fault_t fault_type,
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 = anon_spare = NULL;
anon = NULL;
pg = NULL;
uvmexp.faults++; /* XXX: locking? */
@ -742,8 +604,7 @@ ReFault:
if (uvmfault_lookup(&ufi, FALSE) == FALSE) {
UVMHIST_LOG(maphist, "<- no mapping @ 0x%x", vaddr, 0,0,0);
error = EFAULT;
goto done;
return (EFAULT);
}
/* locked: maps(read) */
@ -768,8 +629,7 @@ ReFault:
"<- protection failure (prot=0x%x, access=0x%x)",
ufi.entry->protection, access_type, 0, 0);
uvmfault_unlockmaps(&ufi, FALSE);
error = EACCES;
goto done;
return EACCES;
}
/*
@ -832,8 +692,7 @@ ReFault:
if (amap == NULL && uobj == NULL) {
uvmfault_unlockmaps(&ufi, FALSE);
UVMHIST_LOG(maphist,"<- no backing store, no overlay",0,0,0,0);
error = EFAULT;
goto done;
return (EFAULT);
}
/*
@ -1027,7 +886,7 @@ ReFault:
/*
* object fault routine responsible for pmap_update().
*/
goto done;
return error;
}
/*
@ -1205,7 +1064,7 @@ ReFault:
goto ReFault;
default:
goto done;
return error;
}
/*
@ -1321,24 +1180,41 @@ ReFault:
UVMHIST_LOG(maphist, " case 1B: COW fault",0,0,0,0);
uvmexp.flt_acow++;
oanon = anon; /* oanon = old, locked anon */
error = uvmfault_promote(&ufi, oanon, PGO_DONTCARE,
&anon, &anon_spare);
switch (error) {
case 0:
break;
case ERESTART:
goto ReFault;
default:
goto done;
anon = uvm_analloc();
if (anon) {
/* new anon is locked! */
pg = uvm_pagealloc(NULL, 0, anon, 0);
}
pg = anon->an_page;
/* 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);
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--;
@ -1386,8 +1262,7 @@ ReFault:
UVMHIST_LOG(maphist,
"<- failed. out of VM",0,0,0,0);
/* XXX instrumentation */
error = ENOMEM;
goto done;
return ENOMEM;
}
/* XXX instrumentation */
uvm_wait("flt_pmfail1");
@ -1424,8 +1299,7 @@ ReFault:
simple_unlock(&anon->an_lock);
uvmfault_unlockall(&ufi, amap, uobj, oanon);
pmap_update(ufi.orig_map->pmap);
error = 0;
goto done;
return 0;
Case2:
/*
@ -1496,7 +1370,7 @@ Case2:
UVMHIST_LOG(maphist, "<- pgo_get failed (code %d)",
error, 0,0,0);
goto done;
return error;
}
/* locked: uobjpage */
@ -1648,18 +1522,62 @@ Case2:
if (amap == NULL)
panic("uvm_fault: want to promote data, but no anon");
#endif
error = uvmfault_promote(&ufi, NULL, uobjpage,
&anon, &anon_spare);
switch (error) {
case 0:
break;
case ERESTART:
goto ReFault;
default:
goto done;
anon = uvm_analloc();
if (anon) {
/*
* The new anon is locked.
*
* In `Fill in data...' below, if
* uobjpage == PGO_DONTCARE, we want
* a zero'd, dirty page, so have
* uvm_pagealloc() do that for us.
*/
pg = uvm_pagealloc(NULL, 0, anon,
(uobjpage == PGO_DONTCARE) ? UVM_PGA_ZERO : 0);
}
pg = anon->an_page;
/*
* out of memory resources?
*/
if (anon == NULL || pg == NULL) {
if (anon != NULL) {
anon->an_ref--;
simple_unlock(&anon->an_lock);
uvm_anfree(anon);
}
/*
* arg! must unbusy our page and fail or sleep.
*/
if (uobjpage != PGO_DONTCARE) {
if (uobjpage->flags & PG_WANTED)
/* still holding object lock */
wakeup(uobjpage);
uobjpage->flags &= ~(PG_BUSY|PG_WANTED);
UVM_PAGE_OWN(uobjpage, NULL);
}
/* unlock and fail ... */
uvmfault_unlockall(&ufi, amap, uobj, NULL);
if (!uvm_reclaimable()) {
UVMHIST_LOG(maphist, " promote: out of VM",
0,0,0,0);
uvmexp.fltnoanon++;
return ENOMEM;
}
UVMHIST_LOG(maphist, " out of RAM, waiting for more",
0,0,0,0);
uvmexp.fltnoram++;
uvm_wait("flt_noram5");
goto ReFault;
}
/*
* fill in the data
@ -1667,6 +1585,8 @@ Case2:
if (uobjpage != PGO_DONTCARE) {
uvmexp.flt_prcopy++;
/* copy page [pg now dirty] */
uvm_pagecopy(uobjpage, pg);
/*
* promote to shared amap? make sure all sharing
@ -1702,13 +1622,15 @@ Case2:
uvmexp.flt_przero++;
/*
* Page is zero'd and marked dirty by
* uvmfault_promote().
* Page is zero'd and marked dirty by uvm_pagealloc()
* above.
*/
UVMHIST_LOG(maphist," zero fill anon/page 0x%x/0%x",
anon, pg, 0, 0);
}
amap_add(&ufi.entry->aref, ufi.orig_rvaddr - ufi.entry->start,
anon, FALSE);
}
/*
@ -1756,8 +1678,7 @@ Case2:
UVMHIST_LOG(maphist,
"<- failed. out of VM",0,0,0,0);
/* XXX instrumentation */
error = ENOMEM;
goto done;
return ENOMEM;
}
/* XXX instrumentation */
uvm_wait("flt_pmfail2");
@ -1796,13 +1717,7 @@ Case2:
uvmfault_unlockall(&ufi, amap, uobj, anon);
pmap_update(ufi.orig_map->pmap);
UVMHIST_LOG(maphist, "<- done (SUCCESS!)",0,0,0,0);
error = 0;
done:
if (anon_spare != NULL) {
anon_spare->an_ref--;
uvm_anfree(anon_spare);
}
return error;
return 0;
}
/*