Index: vm_map.c =================================================================== --- vm_map.c +++ vm_map.c @@ -2839,6 +2839,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. @@ -2847,74 +2905,25 @@ 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; - boolean_t need_wakeup, result, user_unwire; + boolean_t result; + bool holes_ok, need_wakeup, user_unwire; if (start == end) return (KERN_SUCCESS); - user_unwire = (flags & VM_MAP_WIRE_USER) ? TRUE : FALSE; + user_unwire = (flags & VM_MAP_WIRE_USER) != 0; + holes_ok = (flags & VM_MAP_WIRE_HOLESOK) != 0; vm_map_lock(map); VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry(map, start, &first_entry)) { - if (flags & VM_MAP_WIRE_HOLESOK) - 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 (flags & VM_MAP_WIRE_HOLESOK) - 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; - 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); /* @@ -2930,11 +2939,11 @@ * Check the map for holes in the specified region. * If VM_MAP_WIRE_HOLESOK was specified, skip this check. */ - if (((flags & VM_MAP_WIRE_HOLESOK) == 0) && + if ((!holes_ok) && (entry->end < end && entry->next->start > entry->end)) { end = entry->end; rv = KERN_INVALID_ADDRESS; - goto done; + break; } /* * If system unwiring, require that the entry is system wired. @@ -2943,19 +2952,22 @@ vm_map_entry_system_wired_count(entry) == 0) { end = entry->end; rv = KERN_INVALID_ARGUMENT; - goto done; + 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; + } } - rv = KERN_SUCCESS; -done: - need_wakeup = FALSE; + need_wakeup = false; if (first_entry == NULL) { result = vm_map_lookup_entry(map, start, &first_entry); - if (!result && (flags & VM_MAP_WIRE_HOLESOK)) + if (!result) { + KASSERT(holes_ok, ("vm_map_unwire: lookup failed")); first_entry = first_entry->next; - else - KASSERT(result, ("vm_map_unwire: lookup failed")); + } } for (entry = first_entry; entry->start < end; entry = entry->next) { /* @@ -2969,7 +2981,7 @@ */ if ((entry->eflags & MAP_ENTRY_IN_TRANSITION) == 0 || entry->wiring_thread != curthread) { - KASSERT((flags & VM_MAP_WIRE_HOLESOK) != 0, + KASSERT(holes_ok, ("vm_map_unwire: !HOLESOK and new/changed entry")); continue; } @@ -2991,7 +3003,7 @@ entry->wiring_thread = NULL; if (entry->eflags & MAP_ENTRY_NEEDS_WAKEUP) { entry->eflags &= ~MAP_ENTRY_NEEDS_WAKEUP; - need_wakeup = TRUE; + need_wakeup = true; } vm_map_simplify_entry(map, entry); } @@ -3085,7 +3097,8 @@ u_long npages; u_int last_timestamp; int rv; - boolean_t need_wakeup, result, user_wire; + boolean_t result; + bool holes_ok, need_wakeup, user_wire; vm_prot_t prot; VM_MAP_ASSERT_LOCKED(map); @@ -3095,62 +3108,15 @@ prot = 0; if (flags & VM_MAP_WIRE_WRITE) prot |= VM_PROT_WRITE; - user_wire = (flags & VM_MAP_WIRE_USER) ? TRUE : FALSE; + user_wire = (flags & VM_MAP_WIRE_USER) != 0; + holes_ok = (flags & VM_MAP_WIRE_HOLESOK) != 0; VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry(map, start, &first_entry)) { - if (flags & VM_MAP_WIRE_HOLESOK) - 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); + 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 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 (flags & VM_MAP_WIRE_HOLESOK) - 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); /* @@ -3165,14 +3131,12 @@ if ((entry->protection & (VM_PROT_READ | VM_PROT_EXECUTE)) == 0 || (entry->protection & prot) != prot) { entry->eflags |= MAP_ENTRY_WIRE_SKIPPED; - if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { + if (!holes_ok) { end = entry->end; rv = KERN_INVALID_ADDRESS; - goto done; + break; } - goto next_entry; - } - if (entry->wired_count == 0) { + } else if (entry->wired_count == 0) { entry->wired_count++; npages = atop(entry->end - entry->start); @@ -3181,7 +3145,7 @@ entry->start); end = entry->end; rv = KERN_RESOURCE_SHORTAGE; - goto done; + break; } /* @@ -3190,6 +3154,7 @@ */ saved_start = entry->start; saved_end = entry->end; + last_timestamp = map->timestamp; vm_map_busy(map); vm_map_unlock(map); @@ -3234,13 +3199,12 @@ entry = entry->next; } } - last_timestamp = map->timestamp; if (rv != KERN_SUCCESS) { vm_map_wire_entry_failure(map, entry, faddr); if (user_wire) vm_map_wire_user_count_sub(npages); end = entry->end; - goto done; + break; } } else if (!user_wire || (entry->eflags & MAP_ENTRY_USER_WIRED) == 0) { @@ -3250,24 +3214,26 @@ * Check the map for holes in the specified region. * If VM_MAP_WIRE_HOLESOK was specified, skip this check. */ - next_entry: - if ((flags & VM_MAP_WIRE_HOLESOK) == 0 && + if (!holes_ok && entry->end < end && entry->next->start > entry->end) { end = entry->end; rv = KERN_INVALID_ADDRESS; - goto done; + 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; + } } - rv = KERN_SUCCESS; -done: - need_wakeup = FALSE; + need_wakeup = false; if (first_entry == NULL) { result = vm_map_lookup_entry(map, start, &first_entry); - if (!result && (flags & VM_MAP_WIRE_HOLESOK)) + if (!result) { + KASSERT(holes_ok, ("vm_map_wire: lookup failed")); first_entry = first_entry->next; - else - KASSERT(result, ("vm_map_wire: lookup failed")); + } } for (entry = first_entry; entry->start < end; entry = entry->next) { /* @@ -3281,15 +3247,14 @@ */ if ((entry->eflags & MAP_ENTRY_IN_TRANSITION) == 0 || entry->wiring_thread != curthread) { - KASSERT((flags & VM_MAP_WIRE_HOLESOK) != 0, + KASSERT(holes_ok, ("vm_map_wire: !HOLESOK and new/changed entry")); continue; } - if ((entry->eflags & MAP_ENTRY_WIRE_SKIPPED) != 0) - goto next_entry_done; - - if (rv == KERN_SUCCESS) { + if ((entry->eflags & MAP_ENTRY_WIRE_SKIPPED) != 0) { + /* do nothing */ + } else if (rv == KERN_SUCCESS) { if (user_wire) entry->eflags |= MAP_ENTRY_USER_WIRED; } else if (entry->wired_count == -1) { @@ -3312,7 +3277,6 @@ } else entry->wired_count--; } - next_entry_done: KASSERT((entry->eflags & MAP_ENTRY_IN_TRANSITION) != 0, ("vm_map_wire: in-transition flag missing %p", entry)); KASSERT(entry->wiring_thread == curthread, @@ -3322,7 +3286,7 @@ entry->wiring_thread = NULL; if (entry->eflags & MAP_ENTRY_NEEDS_WAKEUP) { entry->eflags &= ~MAP_ENTRY_NEEDS_WAKEUP; - need_wakeup = TRUE; + need_wakeup = true; } vm_map_simplify_entry(map, entry); }