Index: head/sys/vm/vm_map.c =================================================================== --- head/sys/vm/vm_map.c +++ head/sys/vm/vm_map.c @@ -2837,6 +2837,55 @@ } /* + * vm_map_entry_in_transition: + * + * Release the map lock, and sleep until the entry is no longer in + * transition. Awake and acquire the map lock. If the map changed while + * another held the lock, lookup a possibly-changed entry at or after the + * 'start' position of the old entry. + */ +static vm_map_entry_t +vm_map_entry_in_transition(vm_map_t map, vm_offset_t in_start, + vm_offset_t *io_end, bool holes_ok, vm_map_entry_t in_entry) +{ + vm_map_entry_t entry; + vm_offset_t start; + u_int last_timestamp; + + VM_MAP_ASSERT_LOCKED(map); + KASSERT((in_entry->eflags & MAP_ENTRY_IN_TRANSITION) != 0, + ("not in-tranition map entry %p", in_entry)); + /* + * We have not yet clipped the entry. + */ + start = MAX(in_start, in_entry->start); + in_entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP; + last_timestamp = map->timestamp; + if (vm_map_unlock_and_wait(map, 0)) { + /* + * Allow interruption of user wiring/unwiring? + */ + } + vm_map_lock(map); + if (last_timestamp + 1 == map->timestamp) + return (in_entry); + + /* + * Look again for the entry because the map was modified while it was + * unlocked. Specifically, the entry may have been clipped, merged, or + * deleted. + */ + if (!vm_map_lookup_entry(map, start, &entry)) { + if (!holes_ok) { + *io_end = start; + return (NULL); + } + entry = entry->next; + } + return (entry); +} + +/* * vm_map_unwire: * * Implements both kernel and user unwiring. @@ -2845,11 +2894,9 @@ vm_map_unwire(vm_map_t map, vm_offset_t start, vm_offset_t end, int flags) { - vm_map_entry_t entry, first_entry, tmp_entry; - vm_offset_t saved_start; - unsigned int last_timestamp; + vm_map_entry_t entry, first_entry; int rv; - bool holes_ok, need_wakeup, user_unwire; + bool first_iteration, holes_ok, need_wakeup, user_unwire; if (start == end) return (KERN_SUCCESS); @@ -2865,7 +2912,7 @@ return (KERN_INVALID_ADDRESS); } } - last_timestamp = map->timestamp; + first_iteration = true; entry = first_entry; rv = KERN_SUCCESS; while (entry->start < end) { @@ -2873,48 +2920,20 @@ /* * We have not yet clipped the entry. */ - saved_start = (start >= entry->start) ? start : - entry->start; - entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP; - if (vm_map_unlock_and_wait(map, 0)) { - /* - * Allow interruption of user unwiring? - */ - } - vm_map_lock(map); - if (last_timestamp+1 != map->timestamp) { - /* - * Look again for the entry because the map was - * modified while it was unlocked. - * Specifically, the entry may have been - * clipped, merged, or deleted. - */ - if (!vm_map_lookup_entry(map, saved_start, - &tmp_entry)) { - if (holes_ok) - tmp_entry = tmp_entry->next; - else { - if (saved_start == start) { - /* - * First_entry has been deleted. - */ - vm_map_unlock(map); - return (KERN_INVALID_ADDRESS); - } - end = saved_start; - rv = KERN_INVALID_ADDRESS; - break; - } + entry = vm_map_entry_in_transition(map, start, &end, + holes_ok, entry); + if (entry == NULL) { + if (first_iteration) { + vm_map_unlock(map); + return (KERN_INVALID_ADDRESS); } - if (entry == first_entry) - first_entry = tmp_entry; - else - first_entry = NULL; - entry = tmp_entry; + rv = KERN_INVALID_ADDRESS; + break; } - last_timestamp = map->timestamp; + first_entry = first_iteration ? entry : NULL; continue; } + first_iteration = false; vm_map_clip_start(map, entry, start); vm_map_clip_end(map, entry, end); /* @@ -3081,7 +3100,7 @@ u_long npages; u_int last_timestamp; int rv; - bool holes_ok, need_wakeup, user_wire; + bool first_iteration, holes_ok, need_wakeup, user_wire; vm_prot_t prot; VM_MAP_ASSERT_LOCKED(map); @@ -3100,54 +3119,25 @@ else return (KERN_INVALID_ADDRESS); } - last_timestamp = map->timestamp; + first_iteration = true; entry = first_entry; while (entry->start < end) { if (entry->eflags & MAP_ENTRY_IN_TRANSITION) { /* * We have not yet clipped the entry. */ - saved_start = (start >= entry->start) ? start : - entry->start; - entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP; - if (vm_map_unlock_and_wait(map, 0)) { - /* - * Allow interruption of user wiring? - */ + entry = vm_map_entry_in_transition(map, start, &end, + holes_ok, entry); + if (entry == NULL) { + if (first_iteration) + return (KERN_INVALID_ADDRESS); + rv = KERN_INVALID_ADDRESS; + goto done; } - vm_map_lock(map); - if (last_timestamp + 1 != map->timestamp) { - /* - * Look again for the entry because the map was - * modified while it was unlocked. - * Specifically, the entry may have been - * clipped, merged, or deleted. - */ - if (!vm_map_lookup_entry(map, saved_start, - &tmp_entry)) { - if (holes_ok) - tmp_entry = tmp_entry->next; - else { - if (saved_start == start) { - /* - * first_entry has been deleted. - */ - return (KERN_INVALID_ADDRESS); - } - end = saved_start; - rv = KERN_INVALID_ADDRESS; - goto done; - } - } - if (entry == first_entry) - first_entry = tmp_entry; - else - first_entry = NULL; - entry = tmp_entry; - } - last_timestamp = map->timestamp; + first_entry = first_iteration ? entry : NULL; continue; } + first_iteration = false; vm_map_clip_start(map, entry, start); vm_map_clip_end(map, entry, end); /* @@ -3185,6 +3175,7 @@ */ saved_start = entry->start; saved_end = entry->end; + last_timestamp = map->timestamp; vm_map_busy(map); vm_map_unlock(map); @@ -3230,7 +3221,6 @@ entry = entry->next; } } - last_timestamp = map->timestamp; if (rv != KERN_SUCCESS) { vm_map_wire_entry_failure(map, entry, faddr); if (user_wire)