summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpi <mpi@openbsd.org>2021-03-01 09:13:33 +0000
committermpi <mpi@openbsd.org>2021-03-01 09:13:33 +0000
commit1c92e3af03b7e2f4288e77e83c65213588485773 (patch)
tree5e04a09c0a8caab35e5ecdf62300203d247a8d7e
parentMove the top part of uvm_fault_lower(), the lookup, in its own function. (diff)
downloadwireguard-openbsd-1c92e3af03b7e2f4288e77e83c65213588485773.tar.xz
wireguard-openbsd-1c92e3af03b7e2f4288e77e83c65213588485773.zip
If an anon is associated with a page, acquire its lock before any modification.
This change should have been part of the previous anon-locking diff and is necessary to run the top part of uvm_fault() unlocked. ok jmatthew@
-rw-r--r--sys/uvm/uvm_pdaemon.c37
1 files changed, 34 insertions, 3 deletions
diff --git a/sys/uvm/uvm_pdaemon.c b/sys/uvm/uvm_pdaemon.c
index ea0bd2e00cd..5892059354a 100644
--- a/sys/uvm/uvm_pdaemon.c
+++ b/sys/uvm/uvm_pdaemon.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_pdaemon.c,v 1.88 2020/11/24 13:49:09 mpi Exp $ */
+/* $OpenBSD: uvm_pdaemon.c,v 1.89 2021/03/01 09:13:33 mpi Exp $ */
/* $NetBSD: uvm_pdaemon.c,v 1.23 2000/08/20 10:24:14 bjh21 Exp $ */
/*
@@ -460,7 +460,13 @@ uvmpd_scan_inactive(struct pglist *pglst)
if (p->pg_flags & PQ_ANON) {
anon = p->uanon;
KASSERT(anon != NULL);
+ if (rw_enter(anon->an_lock,
+ RW_WRITE|RW_NOSLEEP)) {
+ /* lock failed, skip this page */
+ continue;
+ }
if (p->pg_flags & PG_BUSY) {
+ rw_exit(anon->an_lock);
uvmexp.pdbusy++;
/* someone else owns page, skip it */
continue;
@@ -504,6 +510,7 @@ uvmpd_scan_inactive(struct pglist *pglst)
/* remove from object */
anon->an_page = NULL;
+ rw_exit(anon->an_lock);
}
continue;
}
@@ -513,6 +520,9 @@ uvmpd_scan_inactive(struct pglist *pglst)
* free target when all the current pageouts complete.
*/
if (free + uvmexp.paging > uvmexp.freetarg << 2) {
+ if (anon) {
+ rw_exit(anon->an_lock);
+ }
continue;
}
@@ -525,6 +535,9 @@ uvmpd_scan_inactive(struct pglist *pglst)
if ((p->pg_flags & PQ_SWAPBACKED) && uvm_swapisfull()) {
dirtyreacts++;
uvm_pageactivate(p);
+ if (anon) {
+ rw_exit(anon->an_lock);
+ }
continue;
}
@@ -591,6 +604,8 @@ uvmpd_scan_inactive(struct pglist *pglst)
&p->pg_flags,
PG_BUSY);
UVM_PAGE_OWN(p, NULL);
+ if (anon)
+ rw_exit(anon->an_lock);
continue;
}
swcpages = 0; /* cluster is empty */
@@ -622,6 +637,9 @@ uvmpd_scan_inactive(struct pglist *pglst)
*/
if (swap_backed) {
if (p) { /* if we just added a page to cluster */
+ if (anon)
+ rw_exit(anon->an_lock);
+
/* cluster not full yet? */
if (swcpages < swnpages)
continue;
@@ -730,6 +748,12 @@ uvmpd_scan_inactive(struct pglist *pglst)
/* relock p's object: page queues not lock yet, so
* no need for "try" */
+ /* !swap_backed case: already locked... */
+ if (swap_backed) {
+ if (anon)
+ rw_enter(anon->an_lock, RW_WRITE);
+ }
+
#ifdef DIAGNOSTIC
if (result == VM_PAGER_UNLOCK)
panic("pagedaemon: pageout returned "
@@ -754,6 +778,7 @@ uvmpd_scan_inactive(struct pglist *pglst)
anon->an_page = NULL;
p->uanon = NULL;
+ rw_exit(anon->an_lock);
uvm_anfree(anon); /* kills anon */
pmap_page_protect(p, PROT_NONE);
anon = NULL;
@@ -787,6 +812,8 @@ uvmpd_scan_inactive(struct pglist *pglst)
* the inactive queue can't be re-queued [note: not
* true for active queue]).
*/
+ if (anon)
+ rw_exit(anon->an_lock);
if (nextpg && (nextpg->pg_flags & PQ_INACTIVE) == 0) {
nextpg = TAILQ_FIRST(pglst); /* reload! */
@@ -893,9 +920,11 @@ uvmpd_scan(void)
if (p->pg_flags & PG_BUSY)
continue;
- if (p->pg_flags & PQ_ANON)
+ if (p->pg_flags & PQ_ANON) {
KASSERT(p->uanon != NULL);
- else
+ if (rw_enter(p->uanon->an_lock, RW_WRITE|RW_NOSLEEP))
+ continue;
+ } else
KASSERT(p->uobject != NULL);
/*
@@ -932,6 +961,8 @@ uvmpd_scan(void)
uvmexp.pddeact++;
inactive_shortage--;
}
+ if (p->pg_flags & PQ_ANON)
+ rw_exit(p->uanon->an_lock);
}
}