Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 5 Feb 2018 12:49:20 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r328880 - head/sys/vm
Message-ID:  <201802051249.w15CnKxn020407@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Mon Feb  5 12:49:20 2018
New Revision: 328880
URL: https://svnweb.freebsd.org/changeset/base/328880

Log:
  On munlock(), unwire correct page.
  
  It is possible, for complex fork()/collapse situations, to have
  sibling address spaces to partially share shadow chains. If one
  sibling performs wiring, it can happen that a transient page, invalid
  and busy, is installed into a shadow object which is visible to other
  sibling for the duration of vm_fault_hold().  When the backing object
  contains the valid page, and the wiring is performed on read-only
  entry, the transient page is eventually removed.
  
  But the sibling which observed the transient page might perform the
  unwire, executing vm_object_unwire().  There, the first page found in
  the shadow chain is considered as the page that was wired for the
  mapping.  It is really the page below it which is wired.  So we unwire
  the wrong page, either triggering the asserts of breaking the page'
  wire counter.
  
  As the fix, wait for the busy state to finish if we find such page
  during unwire, and restart the shadow chain walk after the sleep.
  
  Reported and tested by:	pho
  Reviewed by:	markj
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week
  Differential revision:	https://reviews.freebsd.org/D14184

Modified:
  head/sys/vm/vm_object.c

Modified: head/sys/vm/vm_object.c
==============================================================================
--- head/sys/vm/vm_object.c	Mon Feb  5 10:29:57 2018	(r328879)
+++ head/sys/vm/vm_object.c	Mon Feb  5 12:49:20 2018	(r328880)
@@ -2278,7 +2278,7 @@ void
 vm_object_unwire(vm_object_t object, vm_ooffset_t offset, vm_size_t length,
     uint8_t queue)
 {
-	vm_object_t tobject;
+	vm_object_t tobject, t1object;
 	vm_page_t m, tm;
 	vm_pindex_t end_pindex, pindex, tpindex;
 	int depth, locked_depth;
@@ -2292,6 +2292,7 @@ vm_object_unwire(vm_object_t object, vm_ooffset_t offs
 		return;
 	pindex = OFF_TO_IDX(offset);
 	end_pindex = pindex + atop(length);
+again:
 	locked_depth = 1;
 	VM_OBJECT_RLOCK(object);
 	m = vm_page_find_least(object, pindex);
@@ -2325,16 +2326,26 @@ vm_object_unwire(vm_object_t object, vm_ooffset_t offs
 			m = TAILQ_NEXT(m, listq);
 		}
 		vm_page_lock(tm);
+		if (vm_page_xbusied(tm)) {
+			for (tobject = object; locked_depth >= 1;
+			    locked_depth--) {
+				t1object = tobject->backing_object;
+				VM_OBJECT_RUNLOCK(tobject);
+				tobject = t1object;
+			}
+			vm_page_busy_sleep(tm, "unwbo", true);
+			goto again;
+		}
 		vm_page_unwire(tm, queue);
 		vm_page_unlock(tm);
 next_page:
 		pindex++;
 	}
 	/* Release the accumulated object locks. */
-	for (depth = 0; depth < locked_depth; depth++) {
-		tobject = object->backing_object;
-		VM_OBJECT_RUNLOCK(object);
-		object = tobject;
+	for (tobject = object; locked_depth >= 1; locked_depth--) {
+		t1object = tobject->backing_object;
+		VM_OBJECT_RUNLOCK(tobject);
+		tobject = t1object;
 	}
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201802051249.w15CnKxn020407>