svn commit: r254089 - stable/9/sys/vm
Konstantin Belousov
kib at FreeBSD.org
Thu Aug 8 06:12:30 UTC 2013
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
More information about the svn-src-stable-9
mailing list