Module Name: src
Committed By: ad
Date: Sun May 17 19:38:17 UTC 2020
Modified Files:
src/sys/miscfs/genfs: genfs_io.c
src/sys/nfs: nfs_bio.c
src/sys/uvm: uvm_aobj.c uvm_fault.c uvm_loan.c uvm_page.h uvm_pager.h
uvm_pdpolicy.h uvm_pdpolicy_clock.c uvm_pdpolicy_clockpro.c
Log Message:
Start trying to reduce cache misses on vm_page during fault processing.
- Make PGO_LOCKED getpages imply PGO_NOBUSY and remove the latter. Mark
pages busy only when there's actually I/O to do.
- When doing COW on a uvm_object, don't mess with neighbouring pages. In
all likelyhood they're already entered.
- Don't mess with neighbouring VAs that have existing mappings as replacing
those mappings with same can be quite costly.
- Don't enqueue pages for neighbour faults unless not enqueued already, and
don't activate centre pages unless uvmpdpol says its useful.
Also:
- Make PGO_LOCKED getpages on UAOs work more like vnodes: do gang lookup in
the radix tree, and don't allocate new pages.
- Fix many assertion failures around faults/loans with tmpfs.
To generate a diff of this commit:
cvs rdiff -u -r1.95 -r1.96 src/sys/miscfs/genfs/genfs_io.c
cvs rdiff -u -r1.196 -r1.197 src/sys/nfs/nfs_bio.c
cvs rdiff -u -r1.140 -r1.141 src/sys/uvm/uvm_aobj.c
cvs rdiff -u -r1.226 -r1.227 src/sys/uvm/uvm_fault.c
cvs rdiff -u -r1.100 -r1.101 src/sys/uvm/uvm_loan.c
cvs rdiff -u -r1.102 -r1.103 src/sys/uvm/uvm_page.h
cvs rdiff -u -r1.47 -r1.48 src/sys/uvm/uvm_pager.h
cvs rdiff -u -r1.7 -r1.8 src/sys/uvm/uvm_pdpolicy.h
cvs rdiff -u -r1.36 -r1.37 src/sys/uvm/uvm_pdpolicy_clock.c
cvs rdiff -u -r1.25 -r1.26 src/sys/uvm/uvm_pdpolicy_clockpro.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/miscfs/genfs/genfs_io.c
diff -u src/sys/miscfs/genfs/genfs_io.c:1.95 src/sys/miscfs/genfs/genfs_io.c:1.96
--- src/sys/miscfs/genfs/genfs_io.c:1.95 Sun Mar 22 18:32:41 2020
+++ src/sys/miscfs/genfs/genfs_io.c Sun May 17 19:38:16 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: genfs_io.c,v 1.95 2020/03/22 18:32:41 ad Exp $ */
+/* $NetBSD: genfs_io.c,v 1.96 2020/05/17 19:38:16 ad Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: genfs_io.c,v 1.95 2020/03/22 18:32:41 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: genfs_io.c,v 1.96 2020/05/17 19:38:16 ad Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -128,12 +128,12 @@ genfs_getpages(void *v)
/*
* the object must be locked. it can only be a read lock when
- * processing a read fault with PGO_LOCKED | PGO_NOBUSY.
+ * processing a read fault with PGO_LOCKED.
*/
KASSERT(rw_lock_held(uobj->vmobjlock));
KASSERT(rw_write_held(uobj->vmobjlock) ||
- ((~flags & (PGO_LOCKED | PGO_NOBUSY)) == 0 && !memwrite));
+ ((flags & PGO_LOCKED) != 0 && !memwrite));
#ifdef DIAGNOSTIC
if ((flags & PGO_JOURNALLOCKED) && vp->v_mount->mnt_wapbl)
@@ -237,9 +237,8 @@ startover:
#endif /* defined(DEBUG) */
nfound = uvn_findpages(uobj, origoffset, &npages,
ap->a_m, NULL,
- UFP_NOWAIT | UFP_NOALLOC |
- (memwrite ? UFP_NORDONLY : 0) |
- ((flags & PGO_NOBUSY) != 0 ? UFP_NOBUSY : 0));
+ UFP_NOWAIT | UFP_NOALLOC | UFP_NOBUSY |
+ (memwrite ? UFP_NORDONLY : 0));
KASSERT(npages == *ap->a_count);
if (nfound == 0) {
error = EBUSY;
@@ -250,10 +249,6 @@ startover:
* the file behind us.
*/
if (!genfs_node_rdtrylock(vp)) {
- if ((flags & PGO_NOBUSY) == 0) {
- genfs_rel_pages(ap->a_m, npages);
- }
-
/*
* restore the array.
*/
Index: src/sys/nfs/nfs_bio.c
diff -u src/sys/nfs/nfs_bio.c:1.196 src/sys/nfs/nfs_bio.c:1.197
--- src/sys/nfs/nfs_bio.c:1.196 Thu Apr 23 21:47:08 2020
+++ src/sys/nfs/nfs_bio.c Sun May 17 19:38:16 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: nfs_bio.c,v 1.196 2020/04/23 21:47:08 ad Exp $ */
+/* $NetBSD: nfs_bio.c,v 1.197 2020/05/17 19:38:16 ad Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.196 2020/04/23 21:47:08 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.197 2020/05/17 19:38:16 ad Exp $");
#ifdef _KERNEL_OPT
#include "opt_nfs.h"
@@ -1260,7 +1260,6 @@ nfs_getpages(void *v)
bool v3 = NFS_ISV3(vp);
bool write = (ap->a_access_type & VM_PROT_WRITE) != 0;
bool locked = (ap->a_flags & PGO_LOCKED) != 0;
- bool nobusy = (ap->a_flags & PGO_NOBUSY);
/*
* XXX NFS wants to modify the pages below and that can't be done
@@ -1348,14 +1347,10 @@ nfs_getpages(void *v)
if (!mutex_tryenter(&np->n_commitlock)) {
/*
- * Since PGO_LOCKED is set, we need to unbusy
- * all pages fetched by genfs_getpages() above,
* tell the caller that there are no pages
* available and put back original pgs array.
*/
- if (nobusy == false)
- uvm_page_unbusy(pgs, npages);
*ap->a_count = 0;
memcpy(pgs, opgs,
npages * sizeof(struct vm_pages *));
Index: src/sys/uvm/uvm_aobj.c
diff -u src/sys/uvm/uvm_aobj.c:1.140 src/sys/uvm/uvm_aobj.c:1.141
--- src/sys/uvm/uvm_aobj.c:1.140 Fri May 15 22:27:04 2020
+++ src/sys/uvm/uvm_aobj.c Sun May 17 19:38:17 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_aobj.c,v 1.140 2020/05/15 22:27:04 ad Exp $ */
+/* $NetBSD: uvm_aobj.c,v 1.141 2020/05/17 19:38:17 ad Exp $ */
/*
* Copyright (c) 1998 Chuck Silvers, Charles D. Cranor and
@@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_aobj.c,v 1.140 2020/05/15 22:27:04 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_aobj.c,v 1.141 2020/05/17 19:38:17 ad Exp $");
#ifdef _KERNEL_OPT
#include "opt_uvmhist.h"
@@ -250,6 +250,8 @@ uao_find_swslot(struct uvm_object *uobj,
struct uvm_aobj *aobj = (struct uvm_aobj *)uobj;
struct uao_swhash_elt *elt;
+ KASSERT(UVM_OBJ_IS_AOBJ(uobj));
+
/*
* if noswap flag is set, then we never return a slot
*/
@@ -293,6 +295,7 @@ uao_set_swslot(struct uvm_object *uobj,
(uintptr_t)aobj, pageidx, slot, 0);
KASSERT(rw_write_held(uobj->vmobjlock) || uobj->uo_refs == 0);
+ KASSERT(UVM_OBJ_IS_AOBJ(uobj));
/*
* if noswap flag is set, then we can't set a non-zero slot.
@@ -365,6 +368,7 @@ uao_free(struct uvm_aobj *aobj)
{
struct uvm_object *uobj = &aobj->u_obj;
+ KASSERT(UVM_OBJ_IS_AOBJ(uobj));
KASSERT(rw_write_held(uobj->vmobjlock));
uao_dropswap_range(uobj, 0, 0);
rw_exit(uobj->vmobjlock);
@@ -665,6 +669,7 @@ uao_put(struct uvm_object *uobj, voff_t
voff_t curoff;
UVMHIST_FUNC("uao_put"); UVMHIST_CALLED(maphist);
+ KASSERT(UVM_OBJ_IS_AOBJ(uobj));
KASSERT(rw_write_held(uobj->vmobjlock));
if (flags & PGO_ALLPAGES) {
@@ -808,13 +813,13 @@ uao_get(struct uvm_object *uobj, voff_t
/*
* the object must be locked. it can only be a read lock when
- * processing a read fault with PGO_LOCKED | PGO_NOBUSY.
+ * processing a read fault with PGO_LOCKED.
*/
+ KASSERT(UVM_OBJ_IS_AOBJ(uobj));
KASSERT(rw_lock_held(uobj->vmobjlock));
KASSERT(rw_write_held(uobj->vmobjlock) ||
- ((~flags & (PGO_LOCKED | PGO_NOBUSY)) == 0 &&
- (access_type & VM_PROT_WRITE) == 0));
+ ((flags & PGO_LOCKED) != 0 && (access_type & VM_PROT_WRITE) == 0));
/*
* get number of pages
@@ -827,7 +832,7 @@ uao_get(struct uvm_object *uobj, voff_t
*/
if (flags & PGO_LOCKED) {
- krw_t lktype = rw_lock_op(uobj->vmobjlock);
+ struct uvm_page_array a;
/*
* step 1a: get pages that are already resident. only do
@@ -835,77 +840,56 @@ uao_get(struct uvm_object *uobj, voff_t
* time through).
*/
+ uvm_page_array_init(&a);
done = true; /* be optimistic */
gotpages = 0; /* # of pages we got so far */
- for (lcv = 0, current_offset = offset ; lcv < maxpages ;
- lcv++, current_offset += PAGE_SIZE) {
- /* do we care about this page? if not, skip it */
- if (pps[lcv] == PGO_DONTCARE)
- continue;
- ptmp = uvm_pagelookup(uobj, current_offset);
-
- /*
- * if page is new, attempt to allocate the page,
- * zero-fill'd. we can only do this if the caller
- * holds a write lock.
- */
-
- if (ptmp == NULL && lktype == RW_WRITER &&
- uao_find_swslot(uobj,
- current_offset >> PAGE_SHIFT) == 0) {
- ptmp = uao_pagealloc(uobj, current_offset,
- UVM_FLAG_COLORMATCH|UVM_PGA_ZERO);
- if (ptmp) {
- /* new page */
- ptmp->flags &= ~(PG_FAKE);
- uvm_pagemarkdirty(ptmp,
- UVM_PAGE_STATUS_UNKNOWN);
- if ((flags & PGO_NOBUSY) != 0)
- ptmp->flags &= ~PG_BUSY;
- goto gotpage;
- }
+ for (lcv = 0; lcv < maxpages; lcv++) {
+ ptmp = uvm_page_array_fill_and_peek(&a, uobj,
+ offset + (lcv << PAGE_SHIFT), maxpages, 0);
+ if (ptmp == NULL) {
+ break;
}
+ KASSERT(ptmp->offset >= offset);
+ lcv = (ptmp->offset - offset) >> PAGE_SHIFT;
+ if (lcv >= maxpages) {
+ break;
+ }
+ uvm_page_array_advance(&a);
/*
* to be useful must get a non-busy page
*/
- if (ptmp == NULL || (ptmp->flags & PG_BUSY) != 0) {
- if (lcv == centeridx ||
- (flags & PGO_ALLPAGES) != 0)
- /* need to do a wait or I/O! */
- done = false;
+ if ((ptmp->flags & PG_BUSY) != 0) {
continue;
}
/*
- * useful page: busy/lock it and plug it in our
- * result array
+ * useful page: plug it in our result array
*/
+
KASSERT(uvm_pagegetdirty(ptmp) !=
UVM_PAGE_STATUS_CLEAN);
-
- if ((flags & PGO_NOBUSY) == 0) {
- /* caller must un-busy this page */
- ptmp->flags |= PG_BUSY;
- UVM_PAGE_OWN(ptmp, "uao_get1");
- }
-gotpage:
pps[lcv] = ptmp;
gotpages++;
}
+ uvm_page_array_fini(&a);
/*
* step 1b: now we've either done everything needed or we
* to unlock and do some waiting or I/O.
*/
+ if ((flags & PGO_ALLPAGES) != 0) {
+ for (int i = 0; i < maxpages; i++) {
+ done &= (pps[i] != NULL);
+ }
+ } else {
+ done = (pps[centeridx] != NULL);
+ }
UVMHIST_LOG(pdhist, "<- done (done=%jd)", done, 0,0,0);
*npagesp = gotpages;
- if (done)
- return 0;
- else
- return EBUSY;
+ return done ? 0 : EBUSY;
}
/*
@@ -1117,6 +1101,8 @@ uao_dropswap(struct uvm_object *uobj, in
{
int slot;
+ KASSERT(UVM_OBJ_IS_AOBJ(uobj));
+
slot = uao_set_swslot(uobj, pageidx, 0);
if (slot) {
uvm_swap_free(slot, 1);
@@ -1340,6 +1326,7 @@ uao_dropswap_range(struct uvm_object *uo
struct uvm_aobj *aobj = (struct uvm_aobj *)uobj;
int swpgonlydelta = 0;
+ KASSERT(UVM_OBJ_IS_AOBJ(uobj));
KASSERT(rw_write_held(uobj->vmobjlock));
if (end == 0) {
Index: src/sys/uvm/uvm_fault.c
diff -u src/sys/uvm/uvm_fault.c:1.226 src/sys/uvm/uvm_fault.c:1.227
--- src/sys/uvm/uvm_fault.c:1.226 Fri May 15 22:35:05 2020
+++ src/sys/uvm/uvm_fault.c Sun May 17 19:38:17 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_fault.c,v 1.226 2020/05/15 22:35:05 ad Exp $ */
+/* $NetBSD: uvm_fault.c,v 1.227 2020/05/17 19:38:17 ad Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,v 1.226 2020/05/15 22:35:05 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,v 1.227 2020/05/17 19:38:17 ad Exp $");
#include "opt_uvmhist.h"
@@ -43,6 +43,7 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,
#include <sys/mman.h>
#include <uvm/uvm.h>
+#include <uvm/uvm_pdpolicy.h>
/*
*
@@ -569,11 +570,7 @@ uvmfault_promote(struct uvm_faultinfo *u
} else if (uobjpage != PGO_DONTCARE) {
/* object-backed COW */
opg = uobjpage;
- if ((uobjpage->flags & PG_BUSY) != 0) {
- KASSERT(rw_write_held(opg->uobject->vmobjlock));
- } else {
- KASSERT(rw_read_held(opg->uobject->vmobjlock));
- }
+ KASSERT(rw_lock_held(opg->uobject->vmobjlock));
} else {
/* ZFOD */
opg = NULL;
@@ -627,10 +624,6 @@ uvmfault_promote(struct uvm_faultinfo *u
}
/* unlock and fail ... */
- if (uobjpage != PGO_DONTCARE &&
- (uobjpage->flags & PG_BUSY) != 0) {
- uvm_page_unbusy(&uobjpage, 1);
- }
uvmfault_unlockall(ufi, amap, uobj);
if (!uvm_reclaimable()) {
UVMHIST_LOG(maphist, "out of VM", 0,0,0,0);
@@ -655,6 +648,17 @@ uvmfault_promote(struct uvm_faultinfo *u
amap_add(&ufi->entry->aref, ufi->orig_rvaddr - ufi->entry->start, anon,
oanon != NULL);
+ /*
+ * from this point on am_lock won't be dropped until the page is
+ * entered, so it's safe to unbusy the page up front.
+ *
+ * uvm_fault_{upper,lower}_done will activate or enqueue the page.
+ */
+
+ pg = anon->an_page;
+ pg->flags &= ~(PG_BUSY|PG_FAKE);
+ UVM_PAGE_OWN(pg, NULL);
+
*nanon = anon;
error = 0;
done:
@@ -1089,6 +1093,17 @@ uvm_fault_check(
}
/*
+ * for a case 2B fault waste no time on adjacent pages because
+ * they are likely already entered.
+ */
+
+ if (uobj != NULL && amap != NULL &&
+ (flt->access_type & VM_PROT_WRITE) != 0) {
+ /* wide fault (!narrow) */
+ flt->narrow = true;
+ }
+
+ /*
* establish range of interest based on advice from mapper
* and then clip to fit map entry. note that we only want
* to do this the first time through the fault. if we
@@ -1338,14 +1353,6 @@ uvm_fault_upper_lookup(
UVMHIST_LOG(maphist, " shadowed=%jd, will_get=%jd", shadowed,
(ufi->entry->object.uvm_obj && shadowed != false),0,0);
- /*
- * note that if we are really short of RAM we could sleep in the above
- * call to pmap_enter with everything locked. bad?
- *
- * XXX Actually, that is bad; pmap_enter() should just fail in that
- * XXX case. --thorpej
- */
-
return 0;
}
@@ -1370,17 +1377,16 @@ uvm_fault_upper_neighbor(
KASSERT(uvm_pagegetdirty(pg) != UVM_PAGE_STATUS_CLEAN);
/*
- * in the read-locked case, it's not possible for this to be a new
- * page, therefore it's enqueued already. there wasn't a direct
- * fault on the page, so avoid the cost of re-enqueuing it unless
- * write-locked.
+ * there wasn't a direct fault on the page, so avoid the cost of
+ * activating it.
*/
- if (flt->upper_lock_type == RW_WRITER) {
+ if (!uvmpdpol_pageisqueued_p(pg) && pg->wire_count == 0) {
uvm_pagelock(pg);
uvm_pageenqueue(pg);
uvm_pageunlock(pg);
}
+
UVMHIST_LOG(maphist,
" MAPPING: n anon: pm=%#jx, va=%#jx, pg=%#jx",
(uintptr_t)ufi->orig_map->pmap, currva, (uintptr_t)pg, 0);
@@ -1615,13 +1621,10 @@ uvm_fault_upper_promote(
default:
return error;
}
+ pg = anon->an_page;
KASSERT(anon->an_lock == oanon->an_lock);
-
- /* uvm_fault_upper_done will activate or enqueue the page */
- pg = anon->an_page;
- pg->flags &= ~(PG_BUSY|PG_FAKE);
- UVM_PAGE_OWN(pg, NULL);
+ KASSERT((pg->flags & (PG_BUSY | PG_FAKE)) == 0);
/* deref: can not drop to zero here by defn! */
KASSERT(oanon->an_ref > 1);
@@ -1714,11 +1717,9 @@ uvm_fault_upper_enter(
* we just promoted.
*/
- if (flt->upper_lock_type == RW_WRITER) {
- uvm_pagelock(pg);
- uvm_pageenqueue(pg);
- uvm_pageunlock(pg);
- }
+ uvm_pagelock(pg);
+ uvm_pageenqueue(pg);
+ uvm_pageunlock(pg);
/*
* No need to undo what we did; we can simply think of
@@ -1768,15 +1769,11 @@ uvm_fault_upper_done(
* ... update the page queues.
*/
- uvm_pagelock(pg);
if (wire_paging) {
+ uvm_pagelock(pg);
uvm_pagewire(pg);
- } else {
- uvm_pageactivate(pg);
- }
- uvm_pageunlock(pg);
+ uvm_pageunlock(pg);
- if (wire_paging) {
/*
* since the now-wired page cannot be paged out,
* release its swap resources for others to use.
@@ -1786,6 +1783,15 @@ uvm_fault_upper_done(
uvm_pagemarkdirty(pg, UVM_PAGE_STATUS_DIRTY);
uvm_anon_dropswap(anon);
+ } else if (uvmpdpol_pageactivate_p(pg)) {
+ /*
+ * avoid re-activating the page unless needed,
+ * to avoid false sharing on multiprocessor.
+ */
+
+ uvm_pagelock(pg);
+ uvm_pageactivate(pg);
+ uvm_pageunlock(pg);
}
}
@@ -1808,7 +1814,6 @@ uvm_fault_lower_upgrade(struct uvm_fault
*/
if (__predict_true(flt->lower_lock_type == RW_WRITER)) {
- KASSERT(uobjpage == NULL || (uobjpage->flags & PG_BUSY) != 0);
return 0;
}
@@ -1827,18 +1832,6 @@ uvm_fault_lower_upgrade(struct uvm_fault
}
cpu_count(CPU_COUNT_FLTUP, 1);
KASSERT(flt->lower_lock_type == rw_lock_op(uobj->vmobjlock));
-
- /*
- * finally, if a page was supplied, assert that it's not busy
- * (can't be with a reader lock) and then mark it busy now that
- * we have a writer lock.
- */
-
- if (uobjpage != NULL) {
- KASSERT((uobjpage->flags & PG_BUSY) == 0);
- uobjpage->flags |= PG_BUSY;
- UVM_PAGE_OWN(uobjpage, "upgrdlwr");
- }
return 0;
}
@@ -1899,17 +1892,8 @@ uvm_fault_lower(
*/
KASSERT(amap == NULL ||
rw_lock_op(amap->am_lock) == flt->upper_lock_type);
- if (flt->lower_lock_type == RW_WRITER) {
- KASSERT(uobj == NULL || rw_write_held(uobj->vmobjlock));
- KASSERTMSG(uobjpage == NULL ||
- (uobjpage->flags & PG_BUSY) != 0,
- "page %p should be busy", uobjpage);
- } else {
- KASSERT(uobj == NULL || rw_read_held(uobj->vmobjlock));
- KASSERTMSG(uobjpage == NULL ||
- (uobjpage->flags & PG_BUSY) == 0,
- "page %p should not be busy", uobjpage);
- }
+ KASSERT(uobj == NULL ||
+ rw_lock_op(uobj->vmobjlock) == flt->lower_lock_type);
/*
* note that uobjpage can not be PGO_DONTCARE at this point. we now
@@ -1952,13 +1936,8 @@ uvm_fault_lower(
*/
KASSERT(amap == NULL ||
rw_lock_op(amap->am_lock) == flt->upper_lock_type);
- if (flt->lower_lock_type == RW_WRITER) {
- KASSERT(uobj == NULL || rw_write_held(uobj->vmobjlock));
- KASSERT(uobj == NULL || (uobjpage->flags & PG_BUSY) != 0);
- } else {
- KASSERT(uobj == NULL || rw_read_held(uobj->vmobjlock));
- KASSERT(uobj == NULL || (uobjpage->flags & PG_BUSY) == 0);
- }
+ KASSERT(uobj == NULL ||
+ rw_lock_op(uobj->vmobjlock) == flt->lower_lock_type);
/*
* notes:
@@ -1966,10 +1945,12 @@ uvm_fault_lower(
* - at this point uobjpage can not be PG_RELEASED (since we checked
* for it above)
* - at this point uobjpage could be waited on (handle later)
+ * - uobjpage can be from a different object if tmpfs (vnode vs UAO)
*/
KASSERT(uobjpage != NULL);
- KASSERT(uobj == NULL || uobj == uobjpage->uobject);
+ KASSERT(uobj == NULL ||
+ uobjpage->uobject->vmobjlock == uobj->vmobjlock);
KASSERT(uobj == NULL || !UVM_OBJ_IS_CLEAN(uobjpage->uobject) ||
uvm_pagegetdirty(uobjpage) == UVM_PAGE_STATUS_CLEAN);
@@ -1997,16 +1978,13 @@ uvm_fault_lower_lookup(
struct uvm_object *uobj = ufi->entry->object.uvm_obj;
int lcv, gotpages;
vaddr_t currva;
+ bool entered;
UVMHIST_FUNC("uvm_fault_lower_lookup"); UVMHIST_CALLED(maphist);
rw_enter(uobj->vmobjlock, flt->lower_lock_type);
/*
* Locked: maps(read), amap(if there), uobj
- *
- * if we have a read lock on the object, do a PGO_NOBUSY get, which
- * will return us pages with PG_BUSY clear. if a write lock is held
- * pages will be returned with PG_BUSY set.
*/
cpu_count(CPU_COUNT_FLTLGET, 1);
@@ -2015,7 +1993,7 @@ uvm_fault_lower_lookup(
ufi->entry->offset + flt->startva - ufi->entry->start,
pages, &gotpages, flt->centeridx,
flt->access_type & MASK(ufi->entry), ufi->entry->advice,
- PGO_LOCKED | (flt->lower_lock_type == RW_WRITER ? 0 : PGO_NOBUSY));
+ PGO_LOCKED);
KASSERT(rw_lock_op(uobj->vmobjlock) == flt->lower_lock_type);
@@ -2028,6 +2006,7 @@ uvm_fault_lower_lookup(
return;
}
+ entered = false;
currva = flt->startva;
for (lcv = 0; lcv < flt->npages; lcv++, currva += PAGE_SIZE) {
struct vm_page *curpg;
@@ -2036,32 +2015,31 @@ uvm_fault_lower_lookup(
if (curpg == NULL || curpg == PGO_DONTCARE) {
continue;
}
- KASSERT(curpg->uobject == uobj);
- if (flt->lower_lock_type == RW_WRITER) {
- KASSERT(rw_write_held(uobj->vmobjlock));
- KASSERTMSG((curpg->flags & PG_BUSY) != 0,
- "page %p should be busy", curpg);
- } else {
- KASSERT(rw_read_held(uobj->vmobjlock));
- KASSERTMSG((curpg->flags & PG_BUSY) == 0,
- "page %p should not be busy", curpg);
- }
+ /*
+ * in the case of tmpfs, the pages might be from a different
+ * uvm_object. just make sure that they have the same lock.
+ */
+
+ KASSERT(curpg->uobject->vmobjlock == uobj->vmobjlock);
+ KASSERT((curpg->flags & PG_BUSY) == 0);
/*
- * if center page is resident and not PG_BUSY|PG_RELEASED
- * and !PGO_NOBUSY, then pgo_get made it PG_BUSY for us and
- * gave us a handle to it.
+ * leave the centre page for later. don't screw with
+ * existing mappings (needless & expensive).
*/
if (lcv == flt->centeridx) {
UVMHIST_LOG(maphist, " got uobjpage (%#jx) "
"with locked get", (uintptr_t)curpg, 0, 0, 0);
- } else {
+ } else if (!pmap_extract(ufi->orig_map->pmap, currva, NULL)) {
uvm_fault_lower_neighbor(ufi, flt, currva, curpg);
+ entered = true;
}
}
- pmap_update(ufi->orig_map->pmap);
+ if (entered) {
+ pmap_update(ufi->orig_map->pmap);
+ }
}
/*
@@ -2082,20 +2060,17 @@ uvm_fault_lower_neighbor(
* calling pgo_get with PGO_LOCKED returns us pages which
* are neither busy nor released, so we don't need to check
* for this. we can just directly enter the pages.
- */
-
- /*
- * in the read-locked case, it's not possible for this to be a new
- * page. it must be cached with the object and enqueued already.
+ *
* there wasn't a direct fault on the page, so avoid the cost of
- * re-enqueuing it.
+ * activating it.
*/
- if (flt->lower_lock_type == RW_WRITER) {
+ if (!uvmpdpol_pageisqueued_p(pg) && pg->wire_count == 0) {
uvm_pagelock(pg);
uvm_pageenqueue(pg);
uvm_pageunlock(pg);
}
+
UVMHIST_LOG(maphist,
" MAPPING: n obj: pm=%#jx, va=%#jx, pg=%#jx",
(uintptr_t)ufi->orig_map->pmap, currva, (uintptr_t)pg, 0);
@@ -2112,20 +2087,7 @@ uvm_fault_lower_neighbor(
KASSERT((pg->flags & PG_RELEASED) == 0);
KASSERT(!UVM_OBJ_IS_CLEAN(pg->uobject) ||
uvm_pagegetdirty(pg) == UVM_PAGE_STATUS_CLEAN);
-
- /*
- * if a write lock was held on the object, the pages have been
- * busied. unbusy them now, as we are about to enter and then
- * forget about them.
- */
-
- if (flt->lower_lock_type == RW_WRITER) {
- KASSERT((pg->flags & PG_BUSY) != 0);
- pg->flags &= ~(PG_BUSY);
- UVM_PAGE_OWN(pg, NULL);
- } else {
- KASSERT((pg->flags & PG_BUSY) == 0);
- }
+ KASSERT((pg->flags & PG_BUSY) == 0);
KASSERT(rw_lock_op(pg->uobject->vmobjlock) == flt->lower_lock_type);
const vm_prot_t mapprot =
@@ -2253,34 +2215,38 @@ uvm_fault_lower_io(
}
/*
- * didn't get the lock? release the page and retry.
+ * unbusy/release the page.
+ */
+
+ if ((pg->flags & PG_RELEASED) == 0) {
+ pg->flags &= ~PG_BUSY;
+ uvm_pagelock(pg);
+ uvm_pagewakeup(pg);
+ uvm_pageunlock(pg);
+ UVM_PAGE_OWN(pg, NULL);
+ } else {
+ cpu_count(CPU_COUNT_FLTPGRELE, 1);
+ uvm_pagefree(pg);
+ }
+
+ /*
+ * didn't get the lock? retry.
*/
if (locked == false) {
UVMHIST_LOG(maphist,
" wasn't able to relock after fault: retry",
0,0,0,0);
- if ((pg->flags & PG_RELEASED) == 0) {
- pg->flags &= ~PG_BUSY;
- uvm_pagelock(pg);
- uvm_pagewakeup(pg);
- uvm_pageunlock(pg);
- UVM_PAGE_OWN(pg, NULL);
- } else {
- cpu_count(CPU_COUNT_FLTPGRELE, 1);
- uvm_pagefree(pg);
- }
rw_exit(uobj->vmobjlock);
return ERESTART;
}
/*
- * we have the data in pg which is busy and
- * not released. we are holding object lock (so the page
+ * we have the data in pg. we are holding object lock (so the page
* can't be released on us).
*/
- /* locked: maps(read), amap(if !null), uobj, pg */
+ /* locked: maps(read), amap(if !null), uobj */
*ruobj = uobj;
*ruobjpage = pg;
@@ -2328,12 +2294,7 @@ uvm_fault_lower_direct(
uvm_fault_lower_direct_loan(ufi, flt, uobj, &pg, &uobjpage);
}
KASSERT(pg == uobjpage);
-
- if (flt->lower_lock_type == RW_READER) {
- KASSERT(uobj == NULL || (uobjpage->flags & PG_BUSY) == 0);
- } else {
- KASSERT(uobj == NULL || (uobjpage->flags & PG_BUSY) != 0);
- }
+ KASSERT((pg->flags & PG_BUSY) == 0);
return uvm_fault_lower_enter(ufi, flt, uobj, NULL, pg);
}
@@ -2375,16 +2336,6 @@ uvm_fault_lower_direct_loan(
pg = uvm_loanbreak(uobjpage);
if (pg == NULL) {
- /*
- * drop ownership of page, it can't be released
- */
-
- uvm_pagelock(uobjpage);
- uvm_pagewakeup(uobjpage);
- uvm_pageunlock(uobjpage);
- uobjpage->flags &= ~PG_BUSY;
- UVM_PAGE_OWN(uobjpage, NULL);
-
uvmfault_unlockall(ufi, amap, uobj);
UVMHIST_LOG(maphist,
" out of RAM breaking loan, waiting",
@@ -2395,6 +2346,17 @@ uvm_fault_lower_direct_loan(
}
*rpg = pg;
*ruobjpage = pg;
+
+ /*
+ * drop ownership of page while still holding object lock,
+ * which won't be dropped until the page is entered.
+ */
+
+ uvm_pagelock(pg);
+ uvm_pagewakeup(pg);
+ uvm_pageunlock(pg);
+ pg->flags &= ~PG_BUSY;
+ UVM_PAGE_OWN(pg, NULL);
}
return 0;
}
@@ -2426,6 +2388,8 @@ uvm_fault_lower_promote(
return error;
}
KASSERT(rw_write_held(amap->am_lock));
+ KASSERT(uobj == NULL ||
+ rw_lock_op(uobj->vmobjlock) == flt->lower_lock_type);
/*
* If we are going to promote the data to an anon we
@@ -2446,11 +2410,6 @@ uvm_fault_lower_promote(
/*
* Fill in the data.
*/
- if (flt->lower_lock_type == RW_READER) {
- KASSERT(uobj == NULL || (uobjpage->flags & PG_BUSY) == 0);
- } else {
- KASSERT(uobj == NULL || (uobjpage->flags & PG_BUSY) != 0);
- }
if (uobjpage != PGO_DONTCARE) {
cpu_count(CPU_COUNT_FLT_PRCOPY, 1);
@@ -2467,19 +2426,6 @@ uvm_fault_lower_promote(
*/
}
- /*
- * dispose of uobjpage. it can't be PG_RELEASED
- * since we still hold the object lock.
- */
-
- if ((uobjpage->flags & PG_BUSY) != 0) {
- uobjpage->flags &= ~PG_BUSY;
- uvm_pagelock(uobjpage);
- uvm_pagewakeup(uobjpage);
- uvm_pageunlock(uobjpage);
- UVM_PAGE_OWN(uobjpage, NULL);
- }
-
UVMHIST_LOG(maphist,
" promote uobjpage %#jx to anon/page %#jx/%#jx",
(uintptr_t)uobjpage, (uintptr_t)anon, (uintptr_t)pg, 0);
@@ -2525,18 +2471,20 @@ uvm_fault_lower_enter(
*
* Note: pg is either the uobjpage or the new page in the new anon.
*/
+
KASSERT(amap == NULL ||
rw_lock_op(amap->am_lock) == flt->upper_lock_type);
+ KASSERT(uobj == NULL ||
+ rw_lock_op(uobj->vmobjlock) == flt->lower_lock_type);
KASSERT(anon == NULL || anon->an_lock == amap->am_lock);
- if (flt->lower_lock_type == RW_WRITER) {
- KASSERT(uobj == NULL || rw_write_held(uobj->vmobjlock));
- KASSERTMSG((pg->flags & PG_BUSY) != 0,
- "page %p should be busy", pg);
- } else {
- KASSERT(uobj == NULL || rw_read_held(uobj->vmobjlock));
- KASSERTMSG(anon != NULL || (pg->flags & PG_BUSY) == 0,
- "page %p should not be busy", pg);
- }
+
+ /*
+ * note that pg can't be PG_RELEASED or PG_BUSY since we did
+ * not drop the object lock since the last time we checked.
+ */
+
+ KASSERT((pg->flags & PG_RELEASED) == 0);
+ KASSERT((pg->flags & PG_BUSY) == 0);
/*
* all resources are present. we can now map it in and free our
@@ -2573,23 +2521,11 @@ uvm_fault_lower_enter(
* we just promoted the page.
*/
- if (anon != NULL || flt->lower_lock_type == RW_WRITER) {
+ if (anon != NULL) {
uvm_pagelock(pg);
uvm_pageenqueue(pg);
uvm_pagewakeup(pg);
uvm_pageunlock(pg);
- } else {
- KASSERT((pg->flags & PG_BUSY) == 0);
- }
-
- /*
- * note that pg can't be PG_RELEASED since we did not drop
- * the object lock since the last time we checked.
- */
- KASSERT((pg->flags & PG_RELEASED) == 0);
- if ((pg->flags & PG_BUSY) != 0) {
- pg->flags &= ~(PG_BUSY|PG_FAKE);
- UVM_PAGE_OWN(pg, NULL);
}
uvmfault_unlockall(ufi, amap, uobj);
@@ -2606,20 +2542,6 @@ uvm_fault_lower_enter(
}
uvm_fault_lower_done(ufi, flt, uobj, pg);
-
- /*
- * note that pg can't be PG_RELEASED since we did not drop the object
- * lock since the last time we checked.
- */
- KASSERT((pg->flags & PG_RELEASED) == 0);
- if ((pg->flags & PG_BUSY) != 0) {
- uvm_pagelock(pg);
- uvm_pagewakeup(pg);
- uvm_pageunlock(pg);
- pg->flags &= ~(PG_BUSY|PG_FAKE);
- UVM_PAGE_OWN(pg, NULL);
- }
-
pmap_update(ufi->orig_map->pmap);
uvmfault_unlockall(ufi, amap, uobj);
@@ -2636,13 +2558,13 @@ uvm_fault_lower_done(
struct uvm_faultinfo *ufi, const struct uvm_faultctx *flt,
struct uvm_object *uobj, struct vm_page *pg)
{
- bool dropswap = false;
UVMHIST_FUNC("uvm_fault_lower_done"); UVMHIST_CALLED(maphist);
- uvm_pagelock(pg);
if (flt->wire_paging) {
+ uvm_pagelock(pg);
uvm_pagewire(pg);
+ uvm_pageunlock(pg);
if (pg->flags & PG_AOBJ) {
/*
@@ -2650,19 +2572,26 @@ uvm_fault_lower_done(
* release its swap resources for others to use.
* since an aobj page with no swap cannot be clean,
* mark it dirty now.
+ *
+ * use pg->uobject here. if the page is from a
+ * tmpfs vnode, the pages are backed by its UAO and
+ * not the vnode.
*/
KASSERT(uobj != NULL);
+ KASSERT(uobj->vmobjlock == pg->uobject->vmobjlock);
uvm_pagemarkdirty(pg, UVM_PAGE_STATUS_DIRTY);
- dropswap = true;
+ uao_dropswap(pg->uobject, pg->offset >> PAGE_SHIFT);
}
- } else {
- uvm_pageactivate(pg);
- }
- uvm_pageunlock(pg);
+ } else if (uvmpdpol_pageactivate_p(pg)) {
+ /*
+ * avoid re-activating the page unless needed,
+ * to avoid false sharing on multiprocessor.
+ */
- if (dropswap) {
- uao_dropswap(uobj, pg->offset >> PAGE_SHIFT);
+ uvm_pagelock(pg);
+ uvm_pageactivate(pg);
+ uvm_pageunlock(pg);
}
}
Index: src/sys/uvm/uvm_loan.c
diff -u src/sys/uvm/uvm_loan.c:1.100 src/sys/uvm/uvm_loan.c:1.101
--- src/sys/uvm/uvm_loan.c:1.100 Sun Mar 22 18:32:42 2020
+++ src/sys/uvm/uvm_loan.c Sun May 17 19:38:17 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_loan.c,v 1.100 2020/03/22 18:32:42 ad Exp $ */
+/* $NetBSD: uvm_loan.c,v 1.101 2020/05/17 19:38:17 ad Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_loan.c,v 1.100 2020/03/22 18:32:42 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_loan.c,v 1.101 2020/05/17 19:38:17 ad Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -109,7 +109,7 @@ static int uvm_loanuobj(struct uvm_fault
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 int uvm_loanpage(struct vm_page **, int);
+static int uvm_loanpage(struct vm_page **, int, bool);
/*
@@ -442,12 +442,11 @@ uvm_loananon(struct uvm_faultinfo *ufi,
*
* => 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.
+ * => pages will be unbusied (if busied is true).
* => fail with EBUSY if meet a wired page.
*/
static int
-uvm_loanpage(struct vm_page **pgpp, int npages)
+uvm_loanpage(struct vm_page **pgpp, int npages, bool busied)
{
int i;
int error = 0;
@@ -461,7 +460,7 @@ uvm_loanpage(struct vm_page **pgpp, int
KASSERT(pg->uobject == pgpp[0]->uobject);
KASSERT(!(pg->flags & (PG_RELEASED|PG_PAGEOUT)));
KASSERT(rw_write_held(pg->uobject->vmobjlock));
- KASSERT(pg->flags & PG_BUSY);
+ KASSERT(busied == ((pg->flags & PG_BUSY) != 0));
if (pg->wire_count > 0) {
UVMHIST_LOG(loanhist, "wired %#jx", (uintptr_t)pg,
@@ -479,7 +478,9 @@ uvm_loanpage(struct vm_page **pgpp, int
uvm_pageunlock(pg);
}
- uvm_page_unbusy(pgpp, npages);
+ if (busied) {
+ uvm_page_unbusy(pgpp, npages);
+ }
if (error) {
/*
@@ -553,7 +554,7 @@ reget:
if (slock) {
KASSERT(npendloan > 0);
error = uvm_loanpage(pgpp - npendloan,
- npendloan);
+ npendloan, true);
rw_exit(slock);
if (error)
goto fail;
@@ -587,7 +588,7 @@ reget:
}
KASSERT(slock != NULL);
KASSERT(npendloan > 0);
- error = uvm_loanpage(pgpp - npendloan, npendloan);
+ error = uvm_loanpage(pgpp - npendloan, npendloan, true);
rw_exit(slock);
if (error)
goto fail;
@@ -702,36 +703,45 @@ uvm_loanuobj(struct uvm_faultinfo *ufi,
}
/*
- * didn't get the lock? release the page and retry.
+ * unbusy the page.
*/
- if (locked == false) {
- if (pg->flags & PG_RELEASED) {
- uvm_pagefree(pg);
- rw_exit(uobj->vmobjlock);
- return (0);
- }
+ if ((pg->flags & PG_RELEASED) == 0) {
uvm_pagelock(pg);
- uvm_pageactivate(pg);
uvm_pagewakeup(pg);
uvm_pageunlock(pg);
pg->flags &= ~PG_BUSY;
UVM_PAGE_OWN(pg, NULL);
+ }
+
+ /*
+ * didn't get the lock? release the page and retry.
+ */
+
+ if (locked == false) {
+ if (pg->flags & PG_RELEASED) {
+ uvm_pagefree(pg);
+ }
rw_exit(uobj->vmobjlock);
return (0);
}
}
- KASSERT(uobj == pg->uobject);
+ /*
+ * for tmpfs vnodes, the page will be from a UAO rather than
+ * the vnode. just check the locks match.
+ */
+
+ KASSERT(uobj->vmobjlock == pg->uobject->vmobjlock);
/*
- * at this point we have the page we want ("pg") marked PG_BUSY for us
- * and we have all data structures locked. do the loanout. page can
- * not be PG_RELEASED (we caught this above).
+ * at this point we have the page we want ("pg") and we have
+ * all data structures locked. do the loanout. page can not
+ * be PG_RELEASED (we caught this above).
*/
if ((flags & UVM_LOAN_TOANON) == 0) {
- if (uvm_loanpage(&pg, 1)) {
+ if (uvm_loanpage(&pg, 1, false)) {
uvmfault_unlockall(ufi, amap, uobj);
return (-1);
}
@@ -1099,7 +1109,7 @@ uvm_loan_init(void)
* uvm_loanbreak: break loan on a uobj page
*
* => called with uobj locked
- * => the page should be busy
+ * => the page may be busy; if it's busy, it will be unbusied
* => return value:
* newly allocated page if succeeded
*/
@@ -1111,7 +1121,6 @@ uvm_loanbreak(struct vm_page *uobjpage)
KASSERT(uobj != NULL);
KASSERT(rw_write_held(uobj->vmobjlock));
- KASSERT(uobjpage->flags & PG_BUSY);
/* alloc new un-owned page */
pg = uvm_pagealloc(NULL, 0, NULL, 0);
@@ -1131,8 +1140,10 @@ uvm_loanbreak(struct vm_page *uobjpage)
KASSERT(uvm_pagegetdirty(pg) == UVM_PAGE_STATUS_DIRTY);
pmap_page_protect(uobjpage, VM_PROT_NONE);
/* uobj still locked */
- uobjpage->flags &= ~PG_BUSY;
- UVM_PAGE_OWN(uobjpage, NULL);
+ if ((uobjpage->flags & PG_BUSY) != 0) {
+ uobjpage->flags &= ~PG_BUSY;
+ UVM_PAGE_OWN(uobjpage, NULL);
+ }
/*
* if the page is no longer referenced by
Index: src/sys/uvm/uvm_page.h
diff -u src/sys/uvm/uvm_page.h:1.102 src/sys/uvm/uvm_page.h:1.103
--- src/sys/uvm/uvm_page.h:1.102 Tue Mar 17 18:31:39 2020
+++ src/sys/uvm/uvm_page.h Sun May 17 19:38:17 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_page.h,v 1.102 2020/03/17 18:31:39 ad Exp $ */
+/* $NetBSD: uvm_page.h,v 1.103 2020/05/17 19:38:17 ad Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -151,20 +151,18 @@
*
* On the ordering of fields:
*
- * The fields most heavily used by the page allocator and uvmpdpol are
- * clustered together at the start of the structure, so that while under
- * global lock it's more likely that only one cache line for each page need
- * be touched.
+ * The fields most heavily used during fault processing are clustered
+ * together at the start of the structure to reduce cache misses.
+ * XXX This entire thing should be shrunk to fit in one cache line.
*/
struct vm_page {
+ /* _LP64: first cache line */
union {
TAILQ_ENTRY(vm_page) queue; /* w: wired page queue
* or uvm_pglistalloc output */
LIST_ENTRY(vm_page) list; /* f: global free page queue */
} pageq;
- TAILQ_ENTRY(vm_page) pdqueue; /* p: pagedaemon queue */
- kmutex_t interlock; /* s: lock on identity */
uint32_t pqflags; /* i: pagedaemon flags */
uint32_t flags; /* o: object flags */
paddr_t phys_addr; /* o: physical address of pg */
@@ -174,6 +172,10 @@ struct vm_page {
struct uvm_object *uobject; /* o,i: object */
voff_t offset; /* o: offset into object */
+ /* _LP64: second cache line */
+ kmutex_t interlock; /* s: lock on identity */
+ TAILQ_ENTRY(vm_page) pdqueue; /* p: pagedaemon queue */
+
#ifdef __HAVE_VM_PAGE_MD
struct vm_page_md mdpage; /* ?: pmap-specific data */
#endif
Index: src/sys/uvm/uvm_pager.h
diff -u src/sys/uvm/uvm_pager.h:1.47 src/sys/uvm/uvm_pager.h:1.48
--- src/sys/uvm/uvm_pager.h:1.47 Sun Mar 22 18:32:42 2020
+++ src/sys/uvm/uvm_pager.h Sun May 17 19:38:17 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_pager.h,v 1.47 2020/03/22 18:32:42 ad Exp $ */
+/* $NetBSD: uvm_pager.h,v 1.48 2020/05/17 19:38:17 ad Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -152,7 +152,6 @@ struct uvm_pagerops {
#define PGO_JOURNALLOCKED 0x020 /* journal is already locked [get/put] */
#define PGO_LOCKED 0x040 /* fault data structures are locked [get] */
#define PGO_BUSYFAIL 0x080 /* fail if a page is busy [put] */
-#define PGO_NOBUSY 0x100 /* don't busy returned pages (read locked) */
#define PGO_OVERWRITE 0x200 /* pages will be overwritten before unlocked */
#define PGO_PASTEOF 0x400 /* allow allocation of pages past EOF */
#define PGO_NOBLOCKALLOC 0x800 /* backing block allocation is not needed */
Index: src/sys/uvm/uvm_pdpolicy.h
diff -u src/sys/uvm/uvm_pdpolicy.h:1.7 src/sys/uvm/uvm_pdpolicy.h:1.8
--- src/sys/uvm/uvm_pdpolicy.h:1.7 Sun Feb 23 15:46:43 2020
+++ src/sys/uvm/uvm_pdpolicy.h Sun May 17 19:38:17 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_pdpolicy.h,v 1.7 2020/02/23 15:46:43 ad Exp $ */
+/* $NetBSD: uvm_pdpolicy.h,v 1.8 2020/05/17 19:38:17 ad Exp $ */
/*-
* Copyright (c)2005, 2006 YAMAMOTO Takashi,
@@ -48,6 +48,7 @@ void uvmpdpol_pageactivate(struct vm_pag
void uvmpdpol_pagedeactivate(struct vm_page *);
void uvmpdpol_pagedequeue(struct vm_page *);
void uvmpdpol_pageenqueue(struct vm_page *);
+bool uvmpdpol_pageactivate_p(struct vm_page *);
bool uvmpdpol_pageisqueued_p(struct vm_page *);
void uvmpdpol_pagerealize(struct vm_page *);
void uvmpdpol_anfree(struct vm_anon *);
Index: src/sys/uvm/uvm_pdpolicy_clock.c
diff -u src/sys/uvm/uvm_pdpolicy_clock.c:1.36 src/sys/uvm/uvm_pdpolicy_clock.c:1.37
--- src/sys/uvm/uvm_pdpolicy_clock.c:1.36 Thu Apr 2 16:29:30 2020
+++ src/sys/uvm/uvm_pdpolicy_clock.c Sun May 17 19:38:17 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_pdpolicy_clock.c,v 1.36 2020/04/02 16:29:30 maxv Exp $ */
+/* $NetBSD: uvm_pdpolicy_clock.c,v 1.37 2020/05/17 19:38:17 ad Exp $ */
/* NetBSD: uvm_pdaemon.c,v 1.72 2006/01/05 10:47:33 yamt Exp $ */
/*-
@@ -98,7 +98,7 @@
#else /* defined(PDSIM) */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_pdpolicy_clock.c,v 1.36 2020/04/02 16:29:30 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_pdpolicy_clock.c,v 1.37 2020/05/17 19:38:17 ad Exp $");
#include <sys/param.h>
#include <sys/proc.h>
@@ -565,6 +565,29 @@ uvmpdpol_pageisqueued_p(struct vm_page *
}
}
+bool
+uvmpdpol_pageactivate_p(struct vm_page *pg)
+{
+ uint32_t pqflags;
+
+ /* consider intent in preference to actual state. */
+ pqflags = atomic_load_relaxed(&pg->pqflags);
+ if ((pqflags & PQ_INTENT_SET) != 0) {
+ pqflags &= PQ_INTENT_MASK;
+ return pqflags != PQ_INTENT_A && pqflags != PQ_INTENT_E;
+ } else {
+ /*
+ * TODO: Enabling this may be too much of a big hammer,
+ * since we do get useful information from activations.
+ * Think about it more and maybe come up with a heuristic
+ * or something.
+ *
+ * return (pqflags & PQ_ACTIVE) == 0;
+ */
+ return true;
+ }
+}
+
void
uvmpdpol_estimatepageable(int *active, int *inactive)
{
Index: src/sys/uvm/uvm_pdpolicy_clockpro.c
diff -u src/sys/uvm/uvm_pdpolicy_clockpro.c:1.25 src/sys/uvm/uvm_pdpolicy_clockpro.c:1.26
--- src/sys/uvm/uvm_pdpolicy_clockpro.c:1.25 Fri Apr 10 18:17:56 2020
+++ src/sys/uvm/uvm_pdpolicy_clockpro.c Sun May 17 19:38:17 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_pdpolicy_clockpro.c,v 1.25 2020/04/10 18:17:56 tsutsui Exp $ */
+/* $NetBSD: uvm_pdpolicy_clockpro.c,v 1.26 2020/05/17 19:38:17 ad Exp $ */
/*-
* Copyright (c)2005, 2006 YAMAMOTO Takashi,
@@ -43,7 +43,7 @@
#else /* defined(PDSIM) */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_pdpolicy_clockpro.c,v 1.25 2020/04/10 18:17:56 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_pdpolicy_clockpro.c,v 1.26 2020/05/17 19:38:17 ad Exp $");
#include "opt_ddb.h"
@@ -1307,6 +1307,14 @@ uvmpdpol_pageisqueued_p(struct vm_page *
return clockpro_getq(pg) != CLOCKPRO_NOQUEUE;
}
+bool
+uvmpdpol_pageactivate_p(struct vm_page *pg)
+{
+
+ /* For now, no heuristic, always receive activations. */
+ return true;
+}
+
void
uvmpdpol_scaninit(void)
{