Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/uvm - prevent wired pages from being loaned, rather than...
details: https://anonhg.NetBSD.org/src/rev/a0945e0bb1e8
branches: trunk
changeset: 571377:a0945e0bb1e8
user: yamt <yamt%NetBSD.org@localhost>
date: Sun Nov 21 06:45:49 2004 +0000
description:
- prevent wired pages from being loaned, rather than just panicking.
caller should take care of failure by eg. falling back to dumb copy.
PR/23285.
- add some related assertions.
diffstat:
sys/uvm/uvm_loan.c | 128 ++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 97 insertions(+), 31 deletions(-)
diffs (281 lines):
diff -r eb2b42e39c8c -r a0945e0bb1e8 sys/uvm/uvm_loan.c
--- a/sys/uvm/uvm_loan.c Sun Nov 21 04:30:33 2004 +0000
+++ b/sys/uvm/uvm_loan.c Sun Nov 21 06:45:49 2004 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_loan.c,v 1.50 2004/03/24 07:50:48 junyoung Exp $ */
+/* $NetBSD: uvm_loan.c,v 1.51 2004/11/21 06:45:49 yamt Exp $ */
/*
*
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_loan.c,v 1.50 2004/03/24 07:50:48 junyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_loan.c,v 1.51 2004/11/21 06:45:49 yamt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -115,7 +115,7 @@
static int uvm_loanzero(struct uvm_faultinfo *, void ***, int);
static void uvm_unloananon(struct vm_anon **, int);
static void uvm_unloanpage(struct vm_page **, int);
-static void uvm_loanpage(struct vm_page **, int);
+static int uvm_loanpage(struct vm_page **, int);
/*
@@ -184,6 +184,10 @@
rv = -1;
}
/* locked: if (rv > 0) => map, amap, uobj [o.w. unlocked] */
+ LOCK_ASSERT(rv > 0 || aref->ar_amap == NULL ||
+ !simple_lock_held(&aref->ar_amap->am_l));
+ LOCK_ASSERT(rv > 0 || uobj == NULL ||
+ !simple_lock_held(&uobj->vmobjlock));
/* total failure */
if (rv < 0)
@@ -357,6 +361,12 @@
simple_lock(&anon->an_lock);
pg = anon->u.an_page;
if (pg && (pg->pqflags & PQ_ANON) != 0 && anon->an_ref == 1) {
+ if (pg->wire_count > 0) {
+ uvmfault_unlockall(ufi,
+ ufi->entry->aref.ar_amap,
+ ufi->entry->object.uvm_obj, anon);
+ return (-1);
+ }
pmap_page_protect(pg, VM_PROT_READ);
}
anon->an_ref++;
@@ -403,7 +413,13 @@
pg = anon->u.an_page;
uvm_lock_pageq();
- KASSERT(pg->wire_count == 0);
+ if (pg->wire_count > 0) {
+ uvm_unlock_pageq();
+ KASSERT(pg->uobject == NULL);
+ uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap,
+ ufi->entry->object.uvm_obj, anon);
+ return (-1);
+ }
if (pg->loan_count == 0) {
pmap_page_protect(pg, VM_PROT_READ);
}
@@ -423,37 +439,57 @@
/*
* uvm_loanpage: loan out pages to kernel (->K)
*
- * => page's owner should be locked.
- * => caller should own the pages.
+ * => pages should be object-owned and the object should be locked.
+ * => in the case of error, the object might be unlocked and relocked.
+ * => caller should busy the pages beforehand.
+ * => pages will be unbusied.
+ * => fail with EBUSY if meet a wired page.
*/
-static void
+static int
uvm_loanpage(pgpp, npages)
struct vm_page **pgpp;
int npages;
{
int i;
+ int error = 0;
for (i = 0; i < npages; i++) {
struct vm_page *pg = pgpp[i];
KASSERT(pg->uobject != NULL);
+ KASSERT(pg->uobject == pgpp[0]->uobject);
KASSERT(!(pg->flags & (PG_RELEASED|PG_PAGEOUT)));
LOCK_ASSERT(simple_lock_held(&pg->uobject->vmobjlock));
KASSERT(pg->flags & PG_BUSY);
uvm_lock_pageq();
+ if (pg->wire_count > 0) {
+ uvm_unlock_pageq();
+ error = EBUSY;
+ break;
+ }
if (pg->loan_count == 0) {
pmap_page_protect(pg, VM_PROT_READ);
}
pg->loan_count++;
uvm_pagedequeue(pg);
uvm_unlock_pageq();
- if (pg->flags & PG_WANTED) {
- wakeup(pg);
- }
- pg->flags &= ~(PG_WANTED|PG_BUSY);
- UVM_PAGE_OWN(pg, NULL);
}
+
+ uvm_page_unbusy(pgpp, npages);
+
+ if (error) {
+ /*
+ * backout what we've done
+ */
+ struct simplelock *slock = &pgpp[0]->uobject->vmobjlock;
+
+ simple_unlock(slock);
+ uvm_unloan(pgpp, i, UVM_LOAN_TOPAGE);
+ simple_lock(slock);
+ }
+
+ return error;
}
/*
@@ -467,6 +503,7 @@
* uvm_loanuobjpages: loan pages from a uobj out (O->K)
*
* => uobj shouldn't be locked. (we'll lock it)
+ * => fail with EBUSY if we meet a wired page.
*/
int
uvm_loanuobjpages(uobj, pgoff, orignpages, origpgpp)
@@ -475,7 +512,7 @@
int orignpages;
struct vm_page **origpgpp;
{
- int ndone;
+ int ndone; /* # of pages loaned out */
struct vm_page **pgpp;
int error;
int i;
@@ -484,6 +521,7 @@
pgpp = origpgpp;
for (ndone = 0; ndone < orignpages; ) {
int npages;
+ /* npendloan: # of pages busied but not loand out yet. */
int npendloan = 0xdead; /* XXX gcc */
reget:
npages = MIN(UVM_LOAN_GET_CHUNK, orignpages - ndone);
@@ -495,10 +533,8 @@
tsleep(&lbolt, PVM, "nfsread", 0);
continue;
}
- if (error) {
- uvm_unloan(origpgpp, ndone, UVM_LOAN_TOPAGE);
- return error;
- }
+ if (error)
+ goto fail;
KASSERT(npages > 0);
@@ -515,16 +551,20 @@
if (slock != nextslock) {
if (slock) {
KASSERT(npendloan > 0);
- uvm_loanpage(pgpp - npendloan,
+ error = uvm_loanpage(pgpp - npendloan,
npendloan);
simple_unlock(slock);
+ if (error)
+ goto fail;
+ ndone += npendloan;
+ KASSERT(origpgpp + ndone == pgpp);
}
slock = nextslock;
+ npendloan = 0;
simple_lock(slock);
- npendloan = 0;
}
- if (pg->flags & PG_RELEASED) {
+ if ((pg->flags & PG_RELEASED) != 0) {
/*
* release pages and try again.
*/
@@ -544,16 +584,24 @@
npendloan++;
pgpp++;
- ndone++;
- KASSERT(pgpp - origpgpp == ndone);
+ KASSERT(origpgpp + ndone + npendloan == pgpp);
}
KASSERT(slock != NULL);
KASSERT(npendloan > 0);
- uvm_loanpage(pgpp - npendloan, npendloan);
+ error = uvm_loanpage(pgpp - npendloan, npendloan);
simple_unlock(slock);
+ if (error)
+ goto fail;
+ ndone += npendloan;
+ KASSERT(origpgpp + ndone == pgpp);
}
return 0;
+
+fail:
+ uvm_unloan(origpgpp, ndone, UVM_LOAN_TOPAGE);
+
+ return error;
}
/*
@@ -683,7 +731,10 @@
*/
if ((flags & UVM_LOAN_TOANON) == 0) {
- uvm_loanpage(&pg, 1);
+ if (uvm_loanpage(&pg, 1)) {
+ uvmfault_unlockall(ufi, amap, uobj, NULL);
+ return (-1);
+ }
**output = pg;
(*output)++;
return (1);
@@ -717,17 +768,20 @@
anon = uvm_analloc();
if (anon == NULL) {
- if (pg->flags & PG_WANTED) {
- wakeup(pg);
- }
- pg->flags &= ~(PG_WANTED|PG_BUSY);
- UVM_PAGE_OWN(pg, NULL);
- uvmfault_unlockall(ufi, amap, uobj, NULL);
- return (-1);
+ goto fail;
}
anon->u.an_page = pg;
pg->uanon = anon;
uvm_lock_pageq();
+ if (pg->wire_count > 0) {
+ uvm_unlock_pageq();
+ pg->uanon = NULL;
+ anon->u.an_page = NULL;
+ anon->an_ref--;
+ simple_unlock(&anon->an_lock);
+ uvm_anfree(anon);
+ goto fail;
+ }
if (pg->loan_count == 0) {
pmap_page_protect(pg, VM_PROT_READ);
}
@@ -743,6 +797,18 @@
**output = anon;
(*output)++;
return (1);
+
+fail:
+ /*
+ * unlock everything and bail out.
+ */
+ if (pg->flags & PG_WANTED) {
+ wakeup(pg);
+ }
+ pg->flags &= ~(PG_WANTED|PG_BUSY);
+ UVM_PAGE_OWN(pg, NULL);
+ uvmfault_unlockall(ufi, amap, uobj, NULL);
+ return (-1);
}
/*
Home |
Main Index |
Thread Index |
Old Index