From owner-svn-src-stable-7@FreeBSD.ORG Sun Dec 19 06:09:02 2010 Return-Path: Delivered-To: svn-src-stable-7@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C0F5B106564A; Sun, 19 Dec 2010 06:09:02 +0000 (UTC) (envelope-from mlaier@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id AED698FC1B; Sun, 19 Dec 2010 06:09:02 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id oBJ6925m061179; Sun, 19 Dec 2010 06:09:02 GMT (envelope-from mlaier@svn.freebsd.org) Received: (from mlaier@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id oBJ692Pq061176; Sun, 19 Dec 2010 06:09:02 GMT (envelope-from mlaier@svn.freebsd.org) Message-Id: <201012190609.oBJ692Pq061176@svn.freebsd.org> From: Max Laier Date: Sun, 19 Dec 2010 06:09:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r216554 - stable/7/sys/vm X-BeenThere: svn-src-stable-7@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 7-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 19 Dec 2010 06:09:03 -0000 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)