Index: vm_map.c =================================================================== --- vm_map.c +++ vm_map.c @@ -2837,6 +2837,64 @@ } /* + * vm_map_get_avail_entry: + * + * Get the first entry not less than start, or entry->start, + * once that entry is not in transition. Return NULL and + * set end if the entry comes after an unacceptible hole. + */ +static vm_map_entry_t +vm_map_get_avail_entry(vm_map_t map, vm_offset_t start, vm_offset_t *end, + bool holes_ok, vm_map_entry_t entry, vm_map_entry_t *first_entry) +{ + unsigned int last_timestamp; + bool first_call; + + first_call = entry == NULL; + for (;;) { + if (entry == NULL) { + if (!vm_map_lookup_entry(map, start, &entry)) { + if (!holes_ok) { + *end = start; + return (NULL); + } + entry = entry->next; + } + } + if (entry->start >= *end || + (entry->eflags & MAP_ENTRY_IN_TRANSITION) == 0) { + if (first_call) + *first_entry = entry; + return (entry); + } + + /* + * We have not yet clipped the entry. + */ + start = ulmax(start, entry->start); + entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP; + last_timestamp = map->timestamp; + 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. + */ + entry = NULL; + } + if (!first_call) + *first_entry = NULL; + } +} + + +/* * vm_map_unwire: * * Implements both kernel and user unwiring. @@ -2845,9 +2903,7 @@ 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; @@ -2857,64 +2913,14 @@ user_unwire = (flags & VM_MAP_WIRE_USER) != 0; vm_map_lock(map); VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry(map, start, &first_entry)) { - if (holes_ok) - first_entry = first_entry->next; - else { - vm_map_unlock(map); - return (KERN_INVALID_ADDRESS); - } + entry = vm_map_get_avail_entry(map, start, &end, holes_ok, + NULL, &first_entry); + if (entry == NULL) { + vm_map_unlock(map); + return (KERN_INVALID_ADDRESS); } - last_timestamp = map->timestamp; - entry = first_entry; rv = KERN_SUCCESS; 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 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; - } - } - if (entry == first_entry) - first_entry = tmp_entry; - else - first_entry = NULL; - entry = tmp_entry; - } - last_timestamp = map->timestamp; - continue; - } vm_map_clip_start(map, entry, start); vm_map_clip_end(map, entry, end); /* @@ -2945,7 +2951,12 @@ rv = KERN_INVALID_ARGUMENT; break; } - entry = entry->next; + entry = vm_map_get_avail_entry(map, start, &end, holes_ok, + entry->next, &first_entry); + if (entry == NULL) { + rv = KERN_INVALID_ADDRESS; + break; + } } need_wakeup = false; if (first_entry == NULL && @@ -3094,60 +3105,11 @@ holes_ok = (flags & VM_MAP_WIRE_HOLESOK) != 0; user_wire = (flags & VM_MAP_WIRE_USER) != 0; VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry(map, start, &first_entry)) { - if (holes_ok) - first_entry = first_entry->next; - else - return (KERN_INVALID_ADDRESS); - } - last_timestamp = map->timestamp; - entry = first_entry; + entry = vm_map_get_avail_entry(map, start, &end, holes_ok, + NULL, &first_entry); + if (entry == NULL) + return (KERN_INVALID_ADDRESS); 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? - */ - } - 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; - continue; - } vm_map_clip_start(map, entry, start); vm_map_clip_end(map, entry, end); /* @@ -3185,6 +3147,7 @@ */ saved_start = entry->start; saved_end = entry->end; + last_timestamp = map->timestamp; vm_map_busy(map); vm_map_unlock(map); @@ -3230,7 +3193,6 @@ entry = entry->next; } } - last_timestamp = map->timestamp; if (rv != KERN_SUCCESS) { vm_map_wire_entry_failure(map, entry, faddr); if (user_wire) @@ -3252,7 +3214,12 @@ rv = KERN_INVALID_ADDRESS; goto done; } - entry = entry->next; + entry = vm_map_get_avail_entry(map, start, &end, holes_ok, + entry->next, &first_entry); + if (entry == NULL) { + rv = KERN_INVALID_ADDRESS; + goto done; + } } rv = KERN_SUCCESS; done: