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(&current->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:
 		/*

Reply via email to