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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to