Diff below adds anon locking to the page daemon. It will become
necessary to guarantee exclusive access to an anon as soon as the
KERNEL_LOCK() is removed from the fault handler.
Comments? Oks?
Index: uvm/uvm_pdaemon.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_pdaemon.c,v
retrieving revision 1.88
diff -u -p -r1.88 uvm_pdaemon.c
--- uvm/uvm_pdaemon.c 24 Nov 2020 13:49:09 -0000 1.88
+++ uvm/uvm_pdaemon.c 17 Feb 2021 10:05:43 -0000
@@ -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);
}
}