Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Dec 2010 06:09:02 +0000 (UTC)
From:      Max Laier <mlaier@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r216554 - stable/7/sys/vm
Message-ID:  <201012190609.oBJ692Pq061176@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mlaier
Date: Sun Dec 19 06:09:02 2010
New Revision: 216554
URL: http://svn.freebsd.org/changeset/base/216554

Log:
  MFC r216335:
    Fix a long standing (from the original 4.4BSD lite sources) race between
    vmspace_fork and vm_map_wire that would lead to "vm_fault_copy_wired: page
    missing" panics.  While faulting in pages for a map entry that is being
    wired down, mark the containing map as busy.  In vmspace_fork wait until
    the map is unbusy, before we try to copy the entries.
  
    Sponsored by:	Isilon Systems, Inc.
  
  Approved by:	re (kib)

Modified:
  stable/7/sys/vm/vm_map.c
  stable/7/sys/vm/vm_map.h
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/vm/vm_map.c
==============================================================================
--- stable/7/sys/vm/vm_map.c	Sun Dec 19 06:07:35 2010	(r216553)
+++ stable/7/sys/vm/vm_map.c	Sun Dec 19 06:09:02 2010	(r216554)
@@ -561,6 +561,56 @@ vm_map_wakeup(vm_map_t map)
 	wakeup(&map->root);
 }
 
+void
+vm_map_busy(vm_map_t map)
+{
+
+#ifdef INVARIANTS
+	if (map->system_map) {
+		mtx_assert(&map->system_mtx, MA_OWNED);
+	} else
+		sx_assert(&map->lock, SX_XLOCKED);
+#endif
+	map->busy++;
+}
+
+void
+vm_map_unbusy(vm_map_t map)
+{
+
+#ifdef INVARIANTS
+	if (map->system_map) {
+		mtx_assert(&map->system_mtx, MA_OWNED);
+	} else
+		sx_assert(&map->lock, SX_XLOCKED);
+#endif
+	KASSERT(map->busy, ("vm_map_unbusy: not busy"));
+	if (--map->busy == 0 && (map->flags & MAP_BUSY_WAKEUP)) {
+		vm_map_modflags(map, 0, MAP_BUSY_WAKEUP);
+		wakeup(&map->busy);
+	}
+}
+
+void 
+vm_map_wait_busy(vm_map_t map)
+{
+
+#ifdef INVARIANTS
+	if (map->system_map) {
+		mtx_assert(&map->system_mtx, MA_OWNED);
+	} else
+		sx_assert(&map->lock, SX_XLOCKED);
+#endif
+	while (map->busy) {
+		vm_map_modflags(map, MAP_BUSY_WAKEUP, 0);
+		if (map->system_map)
+			msleep(&map->busy, &map->system_mtx, 0, "mbusy", 0);
+		else
+			sx_sleep(&map->busy, &map->lock, 0, "mbusy", 0);
+	}
+	map->timestamp++;
+}
+
 long
 vmspace_resident_count(struct vmspace *vmspace)
 {
@@ -609,6 +659,7 @@ _vm_map_init(vm_map_t map, vm_offset_t m
 	map->flags = 0;
 	map->root = NULL;
 	map->timestamp = 0;
+	map->busy = 0;
 }
 
 void
@@ -2070,12 +2121,14 @@ vm_map_wire(vm_map_t map, vm_offset_t st
 			    entry->object.vm_object->type == OBJT_SG);
 			/*
 			 * Release the map lock, relying on the in-transition
-			 * mark.
+			 * mark.  Mark the map busy for fork.
 			 */
+			vm_map_busy(map);
 			vm_map_unlock(map);
 			rv = vm_fault_wire(map, saved_start, saved_end,
 			    user_wire, fictitious);
 			vm_map_lock(map);
+			vm_map_unbusy(map);
 			if (last_timestamp + 1 != map->timestamp) {
 				/*
 				 * Look again for the entry because the map was
@@ -2605,6 +2658,8 @@ vmspace_fork(struct vmspace *vm1)
 	vm_object_t object;
 
 	vm_map_lock(old_map);
+	if (old_map->busy)
+		vm_map_wait_busy(old_map);
 
 	vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset);
 	if (vm2 == NULL)

Modified: stable/7/sys/vm/vm_map.h
==============================================================================
--- stable/7/sys/vm/vm_map.h	Sun Dec 19 06:07:35 2010	(r216553)
+++ stable/7/sys/vm/vm_map.h	Sun Dec 19 06:09:02 2010	(r216554)
@@ -194,12 +194,14 @@ struct vm_map {
 	pmap_t pmap;			/* (c) Physical map */
 #define	min_offset	header.start	/* (c) */
 #define	max_offset	header.end	/* (c) */
+	int busy;
 };
 
 /*
  * vm_flags_t values
  */
 #define MAP_WIREFUTURE		0x01	/* wire all future pages */
+#define	MAP_BUSY_WAKEUP		0x02
 
 #ifdef	_KERNEL
 static __inline vm_offset_t
@@ -276,6 +278,9 @@ int _vm_map_lock_upgrade(vm_map_t map, c
 void _vm_map_lock_downgrade(vm_map_t map, const char *file, int line);
 int vm_map_unlock_and_wait(vm_map_t map, boolean_t user_wait);
 void vm_map_wakeup(vm_map_t map);
+void vm_map_busy(vm_map_t map);
+void vm_map_unbusy(vm_map_t map);
+void vm_map_wait_busy(vm_map_t map);
 
 #define	vm_map_lock(map)	_vm_map_lock(map, LOCK_FILE, LOCK_LINE)
 #define	vm_map_unlock(map)	_vm_map_unlock(map, LOCK_FILE, LOCK_LINE)



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