Module Name: src Committed By: yamt Date: Sun Nov 20 10:52:35 UTC 2011
Modified Files: src/sys/kern [yamt-pagecache]: init_main.c src/sys/uvm [yamt-pagecache]: uvm.h uvm_extern.h uvm_init.c uvm_loan.c uvm_meter.c uvm_page.c uvm_page.h uvm_page_status.c Log Message: - fix page loaning XXX make O->A loaning further - add some statistics To generate a diff of this commit: cvs rdiff -u -r1.436.2.1 -r1.436.2.2 src/sys/kern/init_main.c cvs rdiff -u -r1.62.4.2 -r1.62.4.3 src/sys/uvm/uvm.h cvs rdiff -u -r1.176.2.3 -r1.176.2.4 src/sys/uvm/uvm_extern.h cvs rdiff -u -r1.41 -r1.41.4.1 src/sys/uvm/uvm_init.c cvs rdiff -u -r1.81.2.3 -r1.81.2.4 src/sys/uvm/uvm_loan.c cvs rdiff -u -r1.56.4.4 -r1.56.4.5 src/sys/uvm/uvm_meter.c cvs rdiff -u -r1.178.2.6 -r1.178.2.7 src/sys/uvm/uvm_page.c cvs rdiff -u -r1.73.2.6 -r1.73.2.7 src/sys/uvm/uvm_page.h cvs rdiff -u -r1.1.2.4 -r1.1.2.5 src/sys/uvm/uvm_page_status.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/kern/init_main.c diff -u src/sys/kern/init_main.c:1.436.2.1 src/sys/kern/init_main.c:1.436.2.2 --- src/sys/kern/init_main.c:1.436.2.1 Wed Nov 2 21:53:59 2011 +++ src/sys/kern/init_main.c Sun Nov 20 10:52:33 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: init_main.c,v 1.436.2.1 2011/11/02 21:53:59 yamt Exp $ */ +/* $NetBSD: init_main.c,v 1.436.2.2 2011/11/20 10:52:33 yamt Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -97,7 +97,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.436.2.1 2011/11/02 21:53:59 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.436.2.2 2011/11/20 10:52:33 yamt Exp $"); #include "opt_ddb.h" #include "opt_ipsec.h" @@ -324,10 +324,6 @@ main(void) percpu_init(); - /* Initialize lock caches. */ - mutex_obj_init(); - rw_obj_init(); - /* Passive serialization. */ pserialize_init(); Index: src/sys/uvm/uvm.h diff -u src/sys/uvm/uvm.h:1.62.4.2 src/sys/uvm/uvm.h:1.62.4.3 --- src/sys/uvm/uvm.h:1.62.4.2 Sat Nov 12 02:54:04 2011 +++ src/sys/uvm/uvm.h Sun Nov 20 10:52:33 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm.h,v 1.62.4.2 2011/11/12 02:54:04 yamt Exp $ */ +/* $NetBSD: uvm.h,v 1.62.4.3 2011/11/20 10:52:33 yamt Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -88,6 +88,19 @@ struct uvm_cpu { * [1] anonymous (PQ_SWAPBACKED) */ int64_t pagestate[2][UVM_PAGE_NUM_STATUS]; + + int64_t loan_obj; /* O->K loan */ + int64_t unloan_obj; /* O->K unloan */ + int64_t loanbreak_obj; /* O->K loan resolved on write */ + int64_t loanfree_obj; /* O->K loan resolved on free */ + + int64_t loan_anon; /* A->K loan */ + int64_t unloan_anon; /* A->K unloan */ + int64_t loanbreak_anon; /* A->K loan resolved on write */ + int64_t loanfree_anon; /* A->K loan resolved on free */ + + int64_t loan_zero; /* O->K loan (zero) */ + int64_t unloan_zero; /* O->K unloan (zero) */ }; /* Index: src/sys/uvm/uvm_extern.h diff -u src/sys/uvm/uvm_extern.h:1.176.2.3 src/sys/uvm/uvm_extern.h:1.176.2.4 --- src/sys/uvm/uvm_extern.h:1.176.2.3 Mon Nov 14 14:24:54 2011 +++ src/sys/uvm/uvm_extern.h Sun Nov 20 10:52:33 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_extern.h,v 1.176.2.3 2011/11/14 14:24:54 yamt Exp $ */ +/* $NetBSD: uvm_extern.h,v 1.176.2.4 2011/11/20 10:52:33 yamt Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -456,12 +456,26 @@ struct uvmexp_sysctl { int64_t colorhit; int64_t colormiss; int64_t ncolors; + int64_t possiblydirtypages; int64_t cleanpages; int64_t dirtypages; int64_t possiblydirtyanonpages; int64_t cleananonpages; int64_t dirtyanonpages; + + int64_t loan_obj; /* O->K loan */ + int64_t unloan_obj; /* O->K unloan */ + int64_t loanbreak_obj; /* O->K loan resolved on write */ + int64_t loanfree_obj; /* O->K loan resolved on free */ + + int64_t loan_anon; /* A->K loan */ + int64_t unloan_anon; /* A->K unloan */ + int64_t loanbreak_anon; /* A->K loan resolved on write */ + int64_t loanfree_anon; /* A->K loan resolved on free */ + + int64_t loan_zero; /* O->K loan (zero) */ + int64_t unloan_zero; /* O->K unloan (zero) */ }; #ifdef _KERNEL Index: src/sys/uvm/uvm_init.c diff -u src/sys/uvm/uvm_init.c:1.41 src/sys/uvm/uvm_init.c:1.41.4.1 --- src/sys/uvm/uvm_init.c:1.41 Sun Apr 24 03:56:50 2011 +++ src/sys/uvm/uvm_init.c Sun Nov 20 10:52:33 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_init.c,v 1.41 2011/04/24 03:56:50 rmind Exp $ */ +/* $NetBSD: uvm_init.c,v 1.41.4.1 2011/11/20 10:52:33 yamt Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvm_init.c,v 1.41 2011/04/24 03:56:50 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_init.c,v 1.41.4.1 2011/11/20 10:52:33 yamt Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -42,6 +42,8 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_init.c,v #include <sys/resourcevar.h> #include <sys/kmem.h> #include <sys/mman.h> +#include <sys/mutex.h> +#include <sys/rwlock.h> #include <sys/vnode.h> #include <uvm/uvm.h> @@ -157,7 +159,15 @@ uvm_init(void) kmem_init(); /* + * Initialize lock caches. + */ + + mutex_obj_init(); + rw_obj_init(); + + /* * Initialize the uvm_loan() facility. + * REQUIRE: mutex_obj_init */ uvm_loan_init(); Index: src/sys/uvm/uvm_loan.c diff -u src/sys/uvm/uvm_loan.c:1.81.2.3 src/sys/uvm/uvm_loan.c:1.81.2.4 --- src/sys/uvm/uvm_loan.c:1.81.2.3 Fri Nov 18 00:57:33 2011 +++ src/sys/uvm/uvm_loan.c Sun Nov 20 10:52:33 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_loan.c,v 1.81.2.3 2011/11/18 00:57:33 yamt Exp $ */ +/* $NetBSD: uvm_loan.c,v 1.81.2.4 2011/11/20 10:52:33 yamt 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.81.2.3 2011/11/18 00:57:33 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_loan.c,v 1.81.2.4 2011/11/20 10:52:33 yamt Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -340,6 +340,7 @@ int uvm_loananon(struct uvm_faultinfo *ufi, void ***output, int flags, struct vm_anon *anon) { + struct uvm_cpu *ucpu; struct vm_page *pg; int error; @@ -428,6 +429,11 @@ uvm_loananon(struct uvm_faultinfo *ufi, /* unlock and return success */ if (pg->uobject) mutex_exit(pg->uobject->vmobjlock); + + ucpu = uvm_cpu_get(); + ucpu->loan_anon++; + uvm_cpu_put(ucpu); + UVMHIST_LOG(loanhist, "->K done", 0,0,0,0); return (1); } @@ -444,6 +450,7 @@ uvm_loananon(struct uvm_faultinfo *ufi, static int uvm_loanpage(struct vm_page **pgpp, int npages) { + struct uvm_cpu *ucpu; int i; int error = 0; @@ -475,15 +482,20 @@ uvm_loanpage(struct vm_page **pgpp, int uvm_page_unbusy(pgpp, npages); - if (error) { - /* - * backout what we've done - */ - kmutex_t *slock = pgpp[0]->uobject->vmobjlock; + if (i > 0) { + ucpu = uvm_cpu_get(); + ucpu->loan_obj += i; + uvm_cpu_put(ucpu); + if (error) { + /* + * backout what we've done + */ + kmutex_t *slock = pgpp[0]->uobject->vmobjlock; - mutex_exit(slock); - uvm_unloan(pgpp, i, UVM_LOAN_TOPAGE); - mutex_enter(slock); + mutex_exit(slock); + uvm_unloan(pgpp, i, UVM_LOAN_TOPAGE); + mutex_enter(slock); + } } UVMHIST_LOG(loanhist, "done %d", error,0,0,0); @@ -829,7 +841,6 @@ fail: */ static struct uvm_object uvm_loanzero_object; -static kmutex_t uvm_loanzero_lock; static int uvm_loanzero(struct uvm_faultinfo *ufi, void ***output, int flags) @@ -871,12 +882,17 @@ again: } if ((flags & UVM_LOAN_TOANON) == 0) { /* loaning to kernel-page */ + struct uvm_cpu *ucpu; + mutex_enter(&uvm_pageqlock); pg->loan_count++; mutex_exit(&uvm_pageqlock); mutex_exit(uvm_loanzero_object.vmobjlock); **output = pg; (*output)++; + ucpu = uvm_cpu_get(); + ucpu->loan_zero++; + uvm_cpu_put(ucpu); return (1); } @@ -965,6 +981,10 @@ uvm_unloanpage(struct vm_page **ploans, mutex_enter(&uvm_pageqlock); while (npages-- > 0) { + struct uvm_object *obj; + struct vm_anon *anon; + struct uvm_cpu *ucpu; + pg = *ploans++; /* @@ -998,22 +1018,35 @@ uvm_unloanpage(struct vm_page **ploans, * an anon) or free it (if the page is now unowned). */ + obj = pg->uobject; + anon = pg->uanon; KASSERT(pg->loan_count > 0); pg->loan_count--; - if (pg->uobject == NULL && pg->uanon != NULL && + if (obj == NULL && anon != NULL && (pg->pqflags & PQ_ANON) == 0) { KASSERT(pg->loan_count > 0); pg->loan_count--; pg->pqflags |= PQ_ANON; } - if (pg->loan_count == 0 && pg->uobject == NULL && - pg->uanon == NULL) { + if (pg->loan_count == 0 && obj == NULL && anon == NULL) { KASSERT((pg->flags & PG_BUSY) == 0); uvm_pagefree(pg); } if (slock != NULL) { mutex_exit(slock); } + ucpu = uvm_cpu_get(); + if (obj != NULL) { + KASSERT(anon == NULL); /* XXX no O->A loan */ + if (obj == &uvm_loanzero_object) { + ucpu->unloan_zero++; + } else { + ucpu->unloan_obj++; + } + } else if (anon != NULL) { + ucpu->unloan_anon++; + } + uvm_cpu_put(ucpu); } mutex_exit(&uvm_pageqlock); } @@ -1087,10 +1120,7 @@ void uvm_loan_init(void) { - mutex_init(&uvm_loanzero_lock, MUTEX_DEFAULT, IPL_NONE); - uvm_obj_init(&uvm_loanzero_object, &ulz_pager, false, 0); - uvm_obj_setlock(&uvm_loanzero_object, &uvm_loanzero_lock); - + uvm_obj_init(&uvm_loanzero_object, &ulz_pager, true, 0); UVMHIST_INIT(loanhist, 300); } @@ -1105,14 +1135,17 @@ uvm_loan_init(void) struct vm_page * uvm_loanbreak(struct vm_page *uobjpage) { + struct uvm_cpu *ucpu; struct vm_page *pg; #ifdef DIAGNOSTIC struct uvm_object *uobj = uobjpage->uobject; #endif + const unsigned int count = uobjpage->loan_count; KASSERT(uobj != NULL); KASSERT(mutex_owned(uobj->vmobjlock)); KASSERT(uobjpage->flags & PG_BUSY); + KASSERT(count > 0); /* alloc new un-owned page */ pg = uvm_pagealloc(NULL, 0, NULL, 0); @@ -1124,39 +1157,30 @@ uvm_loanbreak(struct vm_page *uobjpage) * one and clear the fake flags on the new page (keep it busy). * force a reload of the old page by clearing it from all * pmaps. - * transfer dirtiness of the old page to the new page. * then lock the page queues to rename the pages. */ uvm_pagecopy(uobjpage, pg); /* old -> new */ pg->flags &= ~PG_FAKE; + KASSERT(uvm_pagegetdirty(pg) == UVM_PAGE_STATUS_DIRTY); pmap_page_protect(uobjpage, VM_PROT_NONE); - if (uvm_pagegetdirty(uobjpage) == UVM_PAGE_STATUS_UNKNOWN && - !pmap_clear_modify(uobjpage)) { - uvm_pagemarkdirty(uobjpage, UVM_PAGE_STATUS_CLEAN); - } - if (uvm_pagegetdirty(uobjpage) == UVM_PAGE_STATUS_CLEAN) { - uvm_pagemarkdirty(pg, UVM_PAGE_STATUS_CLEAN); - } else { - /* uvm_pagecopy marked it dirty */ - KASSERT(uvm_pagegetdirty(pg) == UVM_PAGE_STATUS_DIRTY); - /* a object with a dirty page should be dirty. */ - KASSERT(!UVM_OBJ_IS_CLEAN(uobj)); - } if (uobjpage->flags & PG_WANTED) wakeup(uobjpage); /* uobj still locked */ uobjpage->flags &= ~(PG_WANTED|PG_BUSY); UVM_PAGE_OWN(uobjpage, NULL); - mutex_enter(&uvm_pageqlock); - /* * replace uobjpage with new page. + * + * this will update the page dirtiness statistics. */ uvm_pagereplace(uobjpage, pg); + mutex_enter(&uvm_pageqlock); + KASSERT(uobjpage->uanon == NULL); /* XXX no O->A loan */ + /* * if the page is no longer referenced by * an anon (i.e. we are breaking an O->K @@ -1179,16 +1203,23 @@ uvm_loanbreak(struct vm_page *uobjpage) * PG_BUSY. it can now replace uobjpage. */ + ucpu = uvm_cpu_get(); + ucpu->loanbreak_obj += count; + uvm_cpu_put(ucpu); return pg; } int uvm_loanbreak_anon(struct vm_anon *anon, struct uvm_object *uobj) { + struct uvm_cpu *ucpu; struct vm_page *pg; + unsigned int oldstatus; + const unsigned int count = anon->an_page->loan_count; KASSERT(mutex_owned(anon->an_lock)); KASSERT(uobj == NULL || mutex_owned(uobj->vmobjlock)); + KASSERT(count > 0); /* get new un-owned replacement page */ pg = uvm_pagealloc(NULL, 0, NULL, 0); @@ -1198,15 +1229,18 @@ uvm_loanbreak_anon(struct vm_anon *anon, /* copy old -> new */ uvm_pagecopy(anon->an_page, pg); + KASSERT(uvm_pagegetdirty(pg) == UVM_PAGE_STATUS_DIRTY); /* force reload */ pmap_page_protect(anon->an_page, VM_PROT_NONE); + oldstatus = uvm_pagegetdirty(anon->an_page); mutex_enter(&uvm_pageqlock); /* KILL loan */ anon->an_page->uanon = NULL; /* in case we owned */ anon->an_page->pqflags &= ~PQ_ANON; + KASSERT(uobj == NULL); /* XXX O->A loan is currently broken */ if (uobj) { /* if we were receiver of loan */ anon->an_page->loan_count--; @@ -1234,6 +1268,12 @@ uvm_loanbreak_anon(struct vm_anon *anon, UVM_PAGE_OWN(pg, NULL); /* done! */ - + if (uobj == NULL) { + ucpu = uvm_cpu_get(); + ucpu->loanbreak_anon += count; + ucpu->pagestate[1][oldstatus]--; + ucpu->pagestate[1][UVM_PAGE_STATUS_DIRTY]++; + uvm_cpu_put(ucpu); + } return 0; } Index: src/sys/uvm/uvm_meter.c diff -u src/sys/uvm/uvm_meter.c:1.56.4.4 src/sys/uvm/uvm_meter.c:1.56.4.5 --- src/sys/uvm/uvm_meter.c:1.56.4.4 Mon Nov 14 14:24:54 2011 +++ src/sys/uvm/uvm_meter.c Sun Nov 20 10:52:34 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_meter.c,v 1.56.4.4 2011/11/14 14:24:54 yamt Exp $ */ +/* $NetBSD: uvm_meter.c,v 1.56.4.5 2011/11/20 10:52:34 yamt Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvm_meter.c,v 1.56.4.4 2011/11/14 14:24:54 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_meter.c,v 1.56.4.5 2011/11/20 10:52:34 yamt Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -176,6 +176,10 @@ sysctl_vm_uvmexp2(SYSCTLFN_ARGS) u.colormiss = uvmexp.colormiss; u.cpuhit = uvmexp.cpuhit; u.cpumiss = uvmexp.cpumiss; + /* + * XXX should use xcall + * XXX should be an array + */ for (CPU_INFO_FOREACH(cii, ci)) { struct uvm_cpu *ucpu = ci->ci_data.cpu_uvm; @@ -187,6 +191,19 @@ sysctl_vm_uvmexp2(SYSCTLFN_ARGS) ucpu->pagestate[1][UVM_PAGE_STATUS_UNKNOWN]; u.cleananonpages += ucpu->pagestate[1][UVM_PAGE_STATUS_CLEAN]; u.dirtyanonpages += ucpu->pagestate[1][UVM_PAGE_STATUS_DIRTY]; + + u.loan_obj += ucpu->loan_obj; + u.unloan_obj += ucpu->unloan_obj; + u.loanbreak_obj += ucpu->loanbreak_obj; + u.loanfree_obj += ucpu->loanfree_obj; + + u.loan_anon += ucpu->loan_anon; + u.unloan_anon += ucpu->unloan_anon; + u.loanbreak_anon += ucpu->loanbreak_anon; + u.loanfree_anon += ucpu->loanfree_anon; + + u.loan_zero += ucpu->loan_zero; + u.unloan_zero += ucpu->unloan_zero; } node = *rnode; node.sysctl_data = &u; Index: src/sys/uvm/uvm_page.c diff -u src/sys/uvm/uvm_page.c:1.178.2.6 src/sys/uvm/uvm_page.c:1.178.2.7 --- src/sys/uvm/uvm_page.c:1.178.2.6 Fri Nov 18 00:57:33 2011 +++ src/sys/uvm/uvm_page.c Sun Nov 20 10:52:34 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_page.c,v 1.178.2.6 2011/11/18 00:57:33 yamt Exp $ */ +/* $NetBSD: uvm_page.c,v 1.178.2.7 2011/11/20 10:52:34 yamt Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v 1.178.2.6 2011/11/18 00:57:33 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v 1.178.2.7 2011/11/20 10:52:34 yamt Exp $"); #include "opt_ddb.h" #include "opt_uvmhist.h" @@ -166,25 +166,21 @@ static void uvm_pageremove(struct uvm_ob */ static inline void -uvm_pageinsert_list(struct uvm_object *uobj, struct vm_page *pg, - struct vm_page *where) +uvm_pageinsert_list(struct uvm_object *uobj, struct vm_page *pg) { KASSERT(uobj == pg->uobject); KASSERT(mutex_owned(uobj->vmobjlock)); KASSERT((pg->flags & PG_TABLED) == 0); - KASSERT(where == NULL || (where->flags & PG_TABLED)); - KASSERT(where == NULL || (where->uobject == uobj)); if ((pg->pqflags & PQ_STAT) != 0) { struct uvm_cpu *ucpu; const unsigned int status = uvm_pagegetdirty(pg); const bool isaobj = (pg->pqflags & PQ_AOBJ) != 0; - kpreempt_disable(); - ucpu = curcpu()->ci_data.cpu_uvm; + ucpu = uvm_cpu_get(); ucpu->pagestate[isaobj][status]++; - kpreempt_enable(); + uvm_cpu_put(ucpu); if (!isaobj) { KASSERT((pg->pqflags & PQ_FILE) != 0); if (uobj->uo_npages == 0) { @@ -235,7 +231,7 @@ uvm_pageinsert(struct uvm_object *uobj, KASSERT(error == ENOMEM); return error; } - uvm_pageinsert_list(uobj, pg, NULL); + uvm_pageinsert_list(uobj, pg); return 0; } @@ -258,10 +254,9 @@ uvm_pageremove_list(struct uvm_object *u const unsigned int status = uvm_pagegetdirty(pg); const bool isaobj = (pg->pqflags & PQ_AOBJ) != 0; - kpreempt_disable(); - ucpu = curcpu()->ci_data.cpu_uvm; + ucpu = uvm_cpu_get(); ucpu->pagestate[isaobj][status]--; - kpreempt_enable(); + uvm_cpu_put(ucpu); if (!isaobj) { KASSERT((pg->pqflags & PQ_FILE) != 0); if (uobj->uo_npages == 1) { @@ -1329,10 +1324,9 @@ uvm_pagealloc_strat(struct uvm_object *o anon->an_page = pg; pg->pqflags = PQ_ANON; atomic_inc_uint(&uvmexp.anonpages); - kpreempt_disable(); - ucpu = curcpu()->ci_data.cpu_uvm; + ucpu = uvm_cpu_get(); ucpu->pagestate[1][UVM_PAGE_STATUS_CLEAN]++; - kpreempt_enable(); + uvm_cpu_put(ucpu); } else { if (obj) { int error; @@ -1414,7 +1408,12 @@ uvm_pagereplace(struct vm_page *oldpg, s UVM_PAGE_DIRTY_TAG); } } - uvm_pageinsert_list(uobj, newpg, oldpg); + /* + * oldpg->pqflags is stable. newpg is not reachable by others yet. + */ + newpg->pqflags = + (newpg->pqflags & ~PQ_STAT) | (oldpg->pqflags & PQ_STAT); + uvm_pageinsert_list(uobj, newpg); uvm_pageremove_list(uobj, oldpg); } @@ -1522,6 +1521,8 @@ uvm_pagefree(struct vm_page *pg) */ if (pg->loan_count) { + struct uvm_object * const obj = pg->uobject; + KASSERT(pg->wire_count == 0); /* @@ -1535,8 +1536,8 @@ uvm_pagefree(struct vm_page *pg) * unbusy the page, and we're done. */ - if (pg->uobject != NULL) { - uvm_pageremove(pg->uobject, pg); + if (obj != NULL) { + uvm_pageremove(obj, pg); uvm_pagemarkdirty(pg, UVM_PAGE_STATUS_DIRTY); } else if (pg->uanon != NULL) { if ((pg->pqflags & PQ_ANON) == 0) { @@ -1545,10 +1546,9 @@ uvm_pagefree(struct vm_page *pg) pg->pqflags &= ~PQ_ANON; atomic_dec_uint(&uvmexp.anonpages); status = uvm_pagegetdirty(pg); - kpreempt_disable(); - ucpu = curcpu()->ci_data.cpu_uvm; + ucpu = uvm_cpu_get(); ucpu->pagestate[1][status]--; - kpreempt_enable(); + uvm_cpu_put(ucpu); } pg->uanon->an_page = NULL; pg->uanon = NULL; @@ -1565,6 +1565,13 @@ uvm_pagefree(struct vm_page *pg) if (pg->uanon == NULL) { uvm_pagedequeue(pg); } + ucpu = uvm_cpu_get(); + if (obj != NULL) { + ucpu->loanfree_obj += pg->loan_count; + } else { + ucpu->loanfree_anon += pg->loan_count; + } + uvm_cpu_put(ucpu); return; } } @@ -1579,10 +1586,9 @@ uvm_pagefree(struct vm_page *pg) pg->uanon->an_page = NULL; atomic_dec_uint(&uvmexp.anonpages); status = uvm_pagegetdirty(pg); - kpreempt_disable(); - ucpu = curcpu()->ci_data.cpu_uvm; + ucpu = uvm_cpu_get(); ucpu->pagestate[1][status]--; - kpreempt_enable(); + uvm_cpu_put(ucpu); } /* Index: src/sys/uvm/uvm_page.h diff -u src/sys/uvm/uvm_page.h:1.73.2.6 src/sys/uvm/uvm_page.h:1.73.2.7 --- src/sys/uvm/uvm_page.h:1.73.2.6 Fri Nov 18 00:57:34 2011 +++ src/sys/uvm/uvm_page.h Sun Nov 20 10:52:34 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_page.h,v 1.73.2.6 2011/11/18 00:57:34 yamt Exp $ */ +/* $NetBSD: uvm_page.h,v 1.73.2.7 2011/11/20 10:52:34 yamt Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -300,6 +300,10 @@ bool uvm_page_locked_p(struct vm_page *) kmutex_t *uvm_page_getlock(struct vm_page *); bool uvm_page_samelock_p(struct vm_page *, struct vm_page *); +struct uvm_cpu; +struct uvm_cpu *uvm_cpu_get(void); +void uvm_cpu_put(struct uvm_cpu *); + /* * page dirtiness status for uvm_pagegetdirty and uvm_pagemarkdirty * Index: src/sys/uvm/uvm_page_status.c diff -u src/sys/uvm/uvm_page_status.c:1.1.2.4 src/sys/uvm/uvm_page_status.c:1.1.2.5 --- src/sys/uvm/uvm_page_status.c:1.1.2.4 Sun Nov 13 01:18:02 2011 +++ src/sys/uvm/uvm_page_status.c Sun Nov 20 10:52:35 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_page_status.c,v 1.1.2.4 2011/11/13 01:18:02 yamt Exp $ */ +/* $NetBSD: uvm_page_status.c,v 1.1.2.5 2011/11/20 10:52:35 yamt Exp $ */ /*- * Copyright (c)2011 YAMAMOTO Takashi, @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvm_page_status.c,v 1.1.2.4 2011/11/13 01:18:02 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_page_status.c,v 1.1.2.5 2011/11/20 10:52:35 yamt Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -73,11 +73,10 @@ stat_update(bool isanon, unsigned int ol struct uvm_cpu *ucpu; KASSERT(oldstatus != newstatus); - kpreempt_disable(); - ucpu = curcpu()->ci_data.cpu_uvm; + ucpu = uvm_cpu_get(); ucpu->pagestate[isanon][oldstatus]--; ucpu->pagestate[isanon][newstatus]++; - kpreempt_enable(); + uvm_cpu_put(ucpu); } /* @@ -92,7 +91,6 @@ uvm_pagemarkdirty(struct vm_page *pg, un const uint64_t idx = pg->offset >> PAGE_SHIFT; const unsigned int oldstatus = uvm_pagegetdirty(pg); - KASSERT(uobj != NULL || pg->uanon != NULL); KASSERT((~newstatus & (PG_CLEAN|PG_DIRTY)) != 0); KASSERT((newstatus & ~(PG_CLEAN|PG_DIRTY)) == 0); KASSERT(uvm_page_locked_p(pg)); @@ -181,3 +179,20 @@ uvm_pagecheckdirty(struct vm_page *pg, b } return modified; } + +struct uvm_cpu * +uvm_cpu_get(void) +{ + + kpreempt_disable(); + return curcpu()->ci_data.cpu_uvm; +} + +void +uvm_cpu_put(struct uvm_cpu *ucpu) +{ + + KASSERT(kpreempt_disabled()); + KASSERT(curcpu()->ci_data.cpu_uvm == ucpu); + kpreempt_enable(); +}