Module Name: src
Committed By: rmind
Date: Sat Aug 6 17:25:04 UTC 2011
Modified Files:
src/sys/uvm: uvm_amap.c uvm_anon.c uvm_anon.h uvm_fault.c uvm_loan.c
uvm_map.c
Log Message:
- Rework uvm_anfree() into uvm_anon_freelst(), which always drops the lock.
- Free anons in uvm_anon_freelst() without lock held.
- Mechanic sync to unused loaning code.
To generate a diff of this commit:
cvs rdiff -u -r1.101 -r1.102 src/sys/uvm/uvm_amap.c
cvs rdiff -u -r1.58 -r1.59 src/sys/uvm/uvm_anon.c
cvs rdiff -u -r1.29 -r1.30 src/sys/uvm/uvm_anon.h
cvs rdiff -u -r1.189 -r1.190 src/sys/uvm/uvm_fault.c
cvs rdiff -u -r1.80 -r1.81 src/sys/uvm/uvm_loan.c
cvs rdiff -u -r1.302 -r1.303 src/sys/uvm/uvm_map.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/uvm/uvm_amap.c
diff -u src/sys/uvm/uvm_amap.c:1.101 src/sys/uvm/uvm_amap.c:1.102
--- src/sys/uvm/uvm_amap.c:1.101 Tue Jul 5 13:47:24 2011
+++ src/sys/uvm/uvm_amap.c Sat Aug 6 17:25:03 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_amap.c,v 1.101 2011/07/05 13:47:24 yamt Exp $ */
+/* $NetBSD: uvm_amap.c,v 1.102 2011/08/06 17:25:03 rmind Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_amap.c,v 1.101 2011/07/05 13:47:24 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_amap.c,v 1.102 2011/08/06 17:25:03 rmind Exp $");
#include "opt_uvmhist.h"
@@ -365,9 +365,8 @@
amap_pp_adjref(amap, slotoff + slotmapped,
slotadd, 1, &tofree);
}
- uvm_anfree(tofree);
#endif
- amap_unlock(amap);
+ uvm_anon_freelst(amap, tofree);
UVMHIST_LOG(maphist,
"<- done (case 1f), amap = 0x%x, sltneed=%d",
amap, slotneed, 0, 0);
@@ -382,9 +381,8 @@
amap_pp_adjref(amap, slotoff, slotadd, 1,
&tofree);
}
- uvm_anfree(tofree);
#endif
- amap_unlock(amap);
+ uvm_anon_freelst(amap, tofree);
UVMHIST_LOG(maphist,
"<- done (case 1b), amap = 0x%x, sltneed=%d",
amap, slotneed, 0, 0);
@@ -412,8 +410,7 @@
}
#endif
amap->am_nslot = slotneed;
- uvm_anfree(tofree);
- amap_unlock(amap);
+ uvm_anon_freelst(amap, tofree);
/*
* no need to zero am_anon since that was done at
@@ -614,8 +611,8 @@
oldnslots = amap->am_maxslot;
amap->am_maxslot = slotalloc;
- uvm_anfree(tofree);
- amap_unlock(amap);
+ uvm_anon_freelst(amap, tofree);
+
kmem_free(oldsl, oldnslots * sizeof(*oldsl));
kmem_free(oldbck, oldnslots * sizeof(*oldbck));
kmem_free(oldover, oldnslots * sizeof(*oldover));
@@ -694,6 +691,7 @@
void
amap_wipeout(struct vm_amap *amap)
{
+ struct vm_anon *tofree = NULL;
u_int lcv;
UVMHIST_FUNC("amap_wipeout"); UVMHIST_CALLED(maphist);
@@ -724,11 +722,12 @@
anon->an_ref, 0, 0);
/*
- * Drop the reference, and free the anon, if it is last.
+ * Drop the reference. Defer freeing.
*/
if (--anon->an_ref == 0) {
- uvm_anfree(anon);
+ anon->an_link = tofree;
+ tofree = anon;
}
if (curlwp->l_cpu->ci_schedstate.spc_flags & SPCF_SHOULDYIELD) {
preempt();
@@ -740,7 +739,7 @@
*/
amap->am_nused = 0;
- amap_unlock(amap);
+ uvm_anon_freelst(amap, tofree);
amap_free(amap);
UVMHIST_LOG(maphist,"<- done!", 0,0,0,0);
}
@@ -915,7 +914,6 @@
len >> PAGE_SHIFT, -1, &tofree);
}
#endif
- uvm_anfree(tofree);
/*
* If we referenced any anons, then share the source amap's lock.
@@ -927,9 +925,11 @@
amap->am_lock = srcamap->am_lock;
mutex_obj_hold(amap->am_lock);
}
- amap_unlock(srcamap);
- if (amap->am_lock == NULL)
+ uvm_anon_freelst(srcamap, tofree);
+
+ if (amap->am_lock == NULL) {
amap->am_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
+ }
amap_list_insert(amap);
/*
@@ -1047,9 +1047,10 @@
if (nanon) {
nanon->an_ref--;
KASSERT(nanon->an_ref == 0);
- uvm_anfree(nanon);
+ uvm_anon_freelst(amap, nanon);
+ } else {
+ amap_unlock(amap);
}
- amap_unlock(amap);
uvm_wait("cownowpage");
goto ReStart;
}
@@ -1279,7 +1280,7 @@
if (--anon->an_ref == 0) {
/*
* Eliminated the last reference to an anon - defer
- * freeing as uvm_anfree() can unlock the amap.
+ * freeing as uvm_anon_freelst() will unlock the amap.
*/
anon->an_link = *tofree;
*tofree = anon;
@@ -1543,6 +1544,8 @@
amap_adjref_anons(struct vm_amap *amap, vaddr_t offset, vsize_t len,
int refv, bool all)
{
+ struct vm_anon *tofree = NULL;
+
#ifdef UVM_AMAP_PPREF
KASSERT(mutex_owned(amap->am_lock));
@@ -1550,16 +1553,14 @@
amap_pp_establish(amap, offset);
}
if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
- struct vm_anon *tofree = NULL;
-
if (all) {
amap_pp_adjref(amap, 0, amap->am_nslot, refv, &tofree);
} else {
amap_pp_adjref(amap, offset, len, refv, &tofree);
}
- uvm_anfree(tofree);
}
#endif
+ uvm_anon_freelst(amap, tofree);
}
/*
@@ -1580,7 +1581,6 @@
}
amap->am_ref++;
amap_adjref_anons(amap, offset, len, 1, (flags & AMAP_REFALL) != 0);
- amap_unlock(amap);
UVMHIST_LOG(maphist,"<- done! amap=0x%x", amap, 0, 0, 0);
}
@@ -1620,7 +1620,6 @@
amap->am_flags &= ~AMAP_SHARED;
}
amap_adjref_anons(amap, offset, len, -1, all);
- amap_unlock(amap);
UVMHIST_LOG(maphist,"<- done!", 0, 0, 0, 0);
}
Index: src/sys/uvm/uvm_anon.c
diff -u src/sys/uvm/uvm_anon.c:1.58 src/sys/uvm/uvm_anon.c:1.59
--- src/sys/uvm/uvm_anon.c:1.58 Tue Jul 5 13:47:24 2011
+++ src/sys/uvm/uvm_anon.c Sat Aug 6 17:25:03 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_anon.c,v 1.58 2011/07/05 13:47:24 yamt Exp $ */
+/* $NetBSD: uvm_anon.c,v 1.59 2011/08/06 17:25:03 rmind Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_anon.c,v 1.58 2011/07/05 13:47:24 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_anon.c,v 1.59 2011/08/06 17:25:03 rmind Exp $");
#include "opt_uvmhist.h"
@@ -62,6 +62,7 @@
struct vm_anon *anon = object;
anon->an_ref = 0;
+ anon->an_lock = NULL;
anon->an_page = NULL;
#if defined(VMSWAP)
anon->an_swslot = 0;
@@ -82,33 +83,32 @@
anon = pool_cache_get(&uvm_anon_cache, PR_NOWAIT);
if (anon) {
KASSERT(anon->an_ref == 0);
+ KASSERT(anon->an_lock == NULL);
KASSERT(anon->an_page == NULL);
#if defined(VMSWAP)
KASSERT(anon->an_swslot == 0);
#endif
anon->an_ref = 1;
- anon->an_lock = NULL;
}
return anon;
}
/*
- * uvm_anfree1: free a single anon.
+ * uvm_anon_dispose: free any resident page or swap resources of anon.
*
* => anon must be removed from the amap (if anon was in an amap).
- * => amap must be locked or anon must not be associated.
- * => amap lock may be dropped and re-acquired here.
+ * => amap must be locked; we may drop and re-acquire the lock here.
*/
static void
-uvm_anfree1(struct vm_anon *anon)
+uvm_anon_dispose(struct vm_anon *anon)
{
struct vm_page *pg = anon->an_page;
- UVMHIST_FUNC("uvm_anfree"); UVMHIST_CALLED(maphist);
+ UVMHIST_FUNC("uvm_anon_dispose"); UVMHIST_CALLED(maphist);
UVMHIST_LOG(maphist,"(anon=0x%x)", anon, 0,0,0);
- KASSERT(anon->an_lock == NULL || mutex_owned(anon->an_lock));
+ KASSERT(mutex_owned(anon->an_lock));
/*
* If there is a resident page and it is loaned, then anon may not
@@ -180,35 +180,57 @@
#endif
/*
- * Free any swap resources, leave a page replacement hint, drop
- * the reference on lock and finally destroy the anon itself.
+ * Free any swap resources, leave a page replacement hint.
*/
uvm_anon_dropswap(anon);
uvmpdpol_anfree(anon);
+ UVMHIST_LOG(maphist,"<- done!",0,0,0,0);
+}
+
+/*
+ * uvm_anon_free: free a single anon.
+ *
+ * => anon must be already disposed.
+ */
+void
+uvm_anon_free(struct vm_anon *anon)
+{
+ KASSERT(anon->an_ref == 0);
+ KASSERT(anon->an_lock == NULL);
KASSERT(anon->an_page == NULL);
#if defined(VMSWAP)
KASSERT(anon->an_swslot == 0);
#endif
-
pool_cache_put(&uvm_anon_cache, anon);
- UVMHIST_LOG(maphist,"<- done!",0,0,0,0);
}
/*
- * uvm_anfree: free a linked list of anon structures.
+ * uvm_anon_freelst: free a linked list of anon structures.
+ *
+ * => anon must be locked, we will unlock it.
*/
void
-uvm_anfree(struct vm_anon *anon)
+uvm_anon_freelst(struct vm_amap *amap, struct vm_anon *anonlst)
{
- struct vm_anon *next;
+ struct vm_anon *anon = anonlst;
+
+ KASSERT(mutex_owned(amap->am_lock));
- for (; anon != NULL; anon = next) {
- /* Note: clearing an_link also clears a reference count. */
- next = anon->an_link;
- anon->an_link = NULL;
- uvm_anfree1(anon);
+ while (anon) {
+ uvm_anon_dispose(anon);
+ anon = anon->an_link;
+ }
+ amap_unlock(amap);
+
+ while (anonlst) {
+ anon = anonlst->an_link;
+ /* Note: clears an_ref as well. */
+ anonlst->an_link = NULL;
+ anonlst->an_lock = NULL;
+ uvm_anon_free(anonlst);
+ anonlst = anon;
}
}
@@ -403,9 +425,9 @@
uvm_anon_release(struct vm_anon *anon)
{
struct vm_page *pg = anon->an_page;
- kmutex_t *lock = anon->an_lock;
+ kmutex_t *lock;
- KASSERT(mutex_owned(lock));
+ KASSERT(mutex_owned(anon->an_lock));
KASSERT(pg != NULL);
KASSERT((pg->flags & PG_RELEASED) != 0);
KASSERT((pg->flags & PG_BUSY) != 0);
@@ -417,10 +439,13 @@
mutex_enter(&uvm_pageqlock);
uvm_pagefree(pg);
mutex_exit(&uvm_pageqlock);
+ mutex_exit(anon->an_lock);
KASSERT(anon->an_page == NULL);
- uvm_anfree(anon);
- mutex_exit(lock);
+ /* Note: extra reference is held for PG_RELEASED case. */
+ lock = anon->an_lock;
+ anon->an_lock = NULL;
+ uvm_anon_free(anon);
mutex_obj_free(lock);
}
Index: src/sys/uvm/uvm_anon.h
diff -u src/sys/uvm/uvm_anon.h:1.29 src/sys/uvm/uvm_anon.h:1.30
--- src/sys/uvm/uvm_anon.h:1.29 Fri Jun 24 01:39:22 2011
+++ src/sys/uvm/uvm_anon.h Sat Aug 6 17:25:03 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_anon.h,v 1.29 2011/06/24 01:39:22 rmind Exp $ */
+/* $NetBSD: uvm_anon.h,v 1.30 2011/08/06 17:25:03 rmind Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -100,7 +100,8 @@
*/
struct vm_anon *uvm_analloc(void);
-void uvm_anfree(struct vm_anon *);
+void uvm_anon_free(struct vm_anon *);
+void uvm_anon_freelst(struct vm_amap *, struct vm_anon *);
void uvm_anon_init(void);
struct vm_page *uvm_anon_lockloanpg(struct vm_anon *);
#if defined(VMSWAP)
Index: src/sys/uvm/uvm_fault.c
diff -u src/sys/uvm/uvm_fault.c:1.189 src/sys/uvm/uvm_fault.c:1.190
--- src/sys/uvm/uvm_fault.c:1.189 Tue Jul 5 13:47:24 2011
+++ src/sys/uvm/uvm_fault.c Sat Aug 6 17:25:03 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_fault.c,v 1.189 2011/07/05 13:47:24 yamt Exp $ */
+/* $NetBSD: uvm_fault.c,v 1.190 2011/08/06 17:25:03 rmind 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.189 2011/07/05 13:47:24 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,v 1.190 2011/08/06 17:25:03 rmind Exp $");
#include "opt_uvmhist.h"
@@ -846,7 +846,7 @@
flt.anon_spare->an_ref--;
KASSERT(flt.anon_spare->an_ref == 0);
KASSERT(flt.anon_spare->an_lock == NULL);
- uvm_anfree(flt.anon_spare);
+ uvm_anon_free(flt.anon_spare);
}
return error;
}
Index: src/sys/uvm/uvm_loan.c
diff -u src/sys/uvm/uvm_loan.c:1.80 src/sys/uvm/uvm_loan.c:1.81
--- src/sys/uvm/uvm_loan.c:1.80 Sun Jun 12 03:36:03 2011
+++ src/sys/uvm/uvm_loan.c Sat Aug 6 17:25:03 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_loan.c,v 1.80 2011/06/12 03:36:03 rmind Exp $ */
+/* $NetBSD: uvm_loan.c,v 1.81 2011/08/06 17:25:03 rmind 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.80 2011/06/12 03:36:03 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_loan.c,v 1.81 2011/08/06 17:25:03 rmind Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -750,10 +750,9 @@
*/
if (pg->uanon) {
+ /* XXX: locking */
anon = pg->uanon;
- mutex_enter(anon->an_lock);
anon->an_ref++;
- mutex_exit(anon->an_lock);
if (pg->flags & PG_WANTED) {
wakeup(pg);
}
@@ -773,23 +772,19 @@
if (anon == NULL) {
goto fail;
}
- anon->an_page = pg;
- pg->uanon = anon;
mutex_enter(&uvm_pageqlock);
if (pg->wire_count > 0) {
mutex_exit(&uvm_pageqlock);
UVMHIST_LOG(loanhist, "wired %p", pg,0,0,0);
- pg->uanon = NULL;
- anon->an_page = NULL;
- anon->an_ref--;
- uvm_anfree(anon);
goto fail;
}
if (pg->loan_count == 0) {
pmap_page_protect(pg, VM_PROT_READ);
}
pg->loan_count++;
- anon->an_lock =
+ pg->uanon = anon;
+ anon->an_page = pg;
+ anon->an_lock = /* TODO: share amap lock */
uvm_pageactivate(pg);
mutex_exit(&uvm_pageqlock);
if (pg->flags & PG_WANTED) {
@@ -814,6 +809,10 @@
pg->flags &= ~(PG_WANTED|PG_BUSY);
UVM_PAGE_OWN(pg, NULL);
uvmfault_unlockall(ufi, amap, uobj, NULL);
+ if (anon) {
+ anon->an_ref--;
+ uvm_anon_free(anon);
+ }
#endif /* notdef */
return (-1);
}
@@ -937,20 +936,18 @@
uvm_unloananon(struct vm_anon **aloans, int nanons)
{
#ifdef notdef
- struct vm_anon *anon;
+ struct vm_anon *anon, *to_free = NULL;
+ /* TODO: locking */
+ amap_lock(amap);
while (nanons-- > 0) {
- int refs;
-
anon = *aloans++;
- mutex_enter(anon->an_lock);
- refs = --anon->an_ref;
- mutex_exit(anon->an_lock);
-
- if (refs == 0) {
- uvm_anfree(anon);
+ if (--anon->an_ref == 0) {
+ anon->an_link = to_free;
+ to_free = anon;
}
}
+ uvm_anon_freelst(amap, to_free);
#endif /* notdef */
}
Index: src/sys/uvm/uvm_map.c
diff -u src/sys/uvm/uvm_map.c:1.302 src/sys/uvm/uvm_map.c:1.303
--- src/sys/uvm/uvm_map.c:1.302 Sat Jul 30 20:05:46 2011
+++ src/sys/uvm/uvm_map.c Sat Aug 6 17:25:03 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_map.c,v 1.302 2011/07/30 20:05:46 martin Exp $ */
+/* $NetBSD: uvm_map.c,v 1.303 2011/08/06 17:25:03 rmind Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.302 2011/07/30 20:05:46 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.303 2011/08/06 17:25:03 rmind Exp $");
#include "opt_ddb.h"
#include "opt_uvmhist.h"
@@ -3947,10 +3947,11 @@
if (amap == NULL || (flags & (PGO_DEACTIVATE|PGO_FREE)) == 0)
goto flush_object;
- amap_lock(amap);
- anon_tofree = NULL;
offset = start - current->start;
size = MIN(end, current->end) - start;
+ anon_tofree = NULL;
+
+ amap_lock(amap);
for ( ; size != 0; size -= PAGE_SIZE, offset += PAGE_SIZE) {
anon = amap_lookup(¤t->aref, offset);
if (anon == NULL)
@@ -4012,8 +4013,7 @@
continue;
}
}
- uvm_anfree(anon_tofree);
- amap_unlock(amap);
+ uvm_anon_freelst(amap, anon_tofree);
flush_object:
/*