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) {