Date: Thu, 8 Aug 2013 06:12:29 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r254089 - stable/9/sys/vm Message-ID: <201308080612.r786CTWK010479@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Thu Aug 8 06:12:29 2013 New Revision: 254089 URL: http://svnweb.freebsd.org/changeset/base/254089 Log: MFC r253190: Add the thread owner of the MAP_ENTRY_IN_TRANSITION flag to struct vm_map_entry. In vm_map_wire() and vm_map_unwire(), only process the entries which transition owner is the current thread. Modified: stable/9/sys/vm/vm_map.c stable/9/sys/vm/vm_map.h Directory Properties: stable/9/sys/ (props changed) Modified: stable/9/sys/vm/vm_map.c ============================================================================== --- stable/9/sys/vm/vm_map.c Thu Aug 8 06:07:28 2013 (r254088) +++ stable/9/sys/vm/vm_map.c Thu Aug 8 06:12:29 2013 (r254089) @@ -2272,6 +2272,7 @@ vm_map_unwire(vm_map_t map, vm_offset_t * above.) */ entry->eflags |= MAP_ENTRY_IN_TRANSITION; + entry->wiring_thread = curthread; /* * Check the map for holes in the specified region. * If VM_MAP_WIRE_HOLESOK was specified, skip this check. @@ -2304,8 +2305,24 @@ done: else KASSERT(result, ("vm_map_unwire: lookup failed")); } - entry = first_entry; - while (entry != &map->header && entry->start < end) { + for (entry = first_entry; entry != &map->header && entry->start < end; + entry = entry->next) { + /* + * If VM_MAP_WIRE_HOLESOK was specified, an empty + * space in the unwired region could have been mapped + * while the map lock was dropped for draining + * MAP_ENTRY_IN_TRANSITION. Moreover, another thread + * could be simultaneously wiring this new mapping + * entry. Detect these cases and skip any entries + * marked as in transition by us. + */ + if ((entry->eflags & MAP_ENTRY_IN_TRANSITION) == 0 || + entry->wiring_thread != curthread) { + KASSERT((flags & VM_MAP_WIRE_HOLESOK) != 0, + ("vm_map_unwire: !HOLESOK and new/changed entry")); + continue; + } + if (rv == KERN_SUCCESS && (!user_unwire || (entry->eflags & MAP_ENTRY_USER_WIRED))) { if (user_unwire) @@ -2321,15 +2338,15 @@ done: entry->object.vm_object->type == OBJT_SG)); } } - KASSERT(entry->eflags & MAP_ENTRY_IN_TRANSITION, - ("vm_map_unwire: in-transition flag missing")); + KASSERT((entry->eflags & MAP_ENTRY_IN_TRANSITION) != 0, + ("vm_map_unwire: in-transition flag missing")); entry->eflags &= ~MAP_ENTRY_IN_TRANSITION; + entry->wiring_thread = NULL; if (entry->eflags & MAP_ENTRY_NEEDS_WAKEUP) { entry->eflags &= ~MAP_ENTRY_NEEDS_WAKEUP; need_wakeup = TRUE; } vm_map_simplify_entry(map, entry); - entry = entry->next; } vm_map_unlock(map); if (need_wakeup) @@ -2423,6 +2440,7 @@ vm_map_wire(vm_map_t map, vm_offset_t st * above.) */ entry->eflags |= MAP_ENTRY_IN_TRANSITION; + entry->wiring_thread = curthread; if ((entry->protection & (VM_PROT_READ | VM_PROT_EXECUTE)) == 0 || (entry->protection & prot) != prot) { entry->eflags |= MAP_ENTRY_WIRE_SKIPPED; @@ -2514,10 +2532,27 @@ done: else KASSERT(result, ("vm_map_wire: lookup failed")); } - entry = first_entry; - while (entry != &map->header && entry->start < end) { + for (entry = first_entry; entry != &map->header && entry->start < end; + entry = entry->next) { if ((entry->eflags & MAP_ENTRY_WIRE_SKIPPED) != 0) goto next_entry_done; + + /* + * If VM_MAP_WIRE_HOLESOK was specified, an empty + * space in the unwired region could have been mapped + * while the map lock was dropped for faulting in the + * pages or draining MAP_ENTRY_IN_TRANSITION. + * Moreover, another thread could be simultaneously + * wiring this new mapping entry. Detect these cases + * and skip any entries marked as in transition by us. + */ + if ((entry->eflags & MAP_ENTRY_IN_TRANSITION) == 0 || + entry->wiring_thread != curthread) { + KASSERT((flags & VM_MAP_WIRE_HOLESOK) != 0, + ("vm_map_wire: !HOLESOK and new/changed entry")); + continue; + } + if (rv == KERN_SUCCESS) { if (user_wire) entry->eflags |= MAP_ENTRY_USER_WIRED; @@ -2542,15 +2577,18 @@ done: } } next_entry_done: - KASSERT(entry->eflags & MAP_ENTRY_IN_TRANSITION, - ("vm_map_wire: in-transition flag missing")); - entry->eflags &= ~(MAP_ENTRY_IN_TRANSITION|MAP_ENTRY_WIRE_SKIPPED); + KASSERT((entry->eflags & MAP_ENTRY_IN_TRANSITION) != 0, + ("vm_map_wire: in-transition flag missing %p", entry)); + KASSERT(entry->wiring_thread == curthread, + ("vm_map_wire: alien wire %p", entry)); + entry->eflags &= ~(MAP_ENTRY_IN_TRANSITION | + MAP_ENTRY_WIRE_SKIPPED); + entry->wiring_thread = NULL; if (entry->eflags & MAP_ENTRY_NEEDS_WAKEUP) { entry->eflags &= ~MAP_ENTRY_NEEDS_WAKEUP; need_wakeup = TRUE; } vm_map_simplify_entry(map, entry); - entry = entry->next; } vm_map_unlock(map); if (need_wakeup) @@ -3185,6 +3223,7 @@ vmspace_fork(struct vmspace *vm1, vm_oof *new_entry = *old_entry; new_entry->eflags &= ~(MAP_ENTRY_USER_WIRED | MAP_ENTRY_IN_TRANSITION); + new_entry->wiring_thread = NULL; new_entry->wired_count = 0; if (new_entry->eflags & MAP_ENTRY_VN_WRITECNT) { vnode_pager_update_writecount(object, @@ -3219,6 +3258,7 @@ vmspace_fork(struct vmspace *vm1, vm_oof */ new_entry->eflags &= ~(MAP_ENTRY_USER_WIRED | MAP_ENTRY_IN_TRANSITION | MAP_ENTRY_VN_WRITECNT); + new_entry->wiring_thread = NULL; new_entry->wired_count = 0; new_entry->object.vm_object = NULL; new_entry->cred = NULL; Modified: stable/9/sys/vm/vm_map.h ============================================================================== --- stable/9/sys/vm/vm_map.h Thu Aug 8 06:07:28 2013 (r254088) +++ stable/9/sys/vm/vm_map.h Thu Aug 8 06:12:29 2013 (r254089) @@ -116,6 +116,7 @@ struct vm_map_entry { int wired_count; /* can be paged if = 0 */ vm_pindex_t next_read; /* index of the next sequential read */ struct ucred *cred; /* tmp storage for creator ref */ + struct thread *wiring_thread; }; #define MAP_ENTRY_NOSYNC 0x0001
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308080612.r786CTWK010479>