Index: sys/vm/vm_map.c =================================================================== --- sys/vm/vm_map.c +++ sys/vm/vm_map.c @@ -1483,50 +1483,24 @@ return (result); } -/* - * vm_map_find finds an unallocated region in the target address - * map with the given length. The search is defined to be - * first-fit from the specified address; the region found is - * returned in the same parameter. - * - * If object is non-NULL, ref count must be bumped by caller - * prior to making call to account for the new entry. - */ -int -vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset, - vm_offset_t *addr, /* IN/OUT */ - vm_size_t length, vm_offset_t max_addr, int find_space, - vm_prot_t prot, vm_prot_t max, int cow) +static int +vm_map_find_locked(vm_map_t map, vm_object_t object, vm_ooffset_t offset, + vm_offset_t *addr, vm_size_t length, vm_offset_t max_addr, int find_space, + vm_offset_t alignment, vm_prot_t prot, vm_prot_t max, int cow) { - vm_offset_t alignment, initial_addr, start; + vm_offset_t start; +#ifdef INVARIANTS + vm_offset_t prev_start; +#endif int result; - KASSERT((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) == 0 || - object == NULL, - ("vm_map_find: non-NULL backing object for stack")); - if (find_space == VMFS_OPTIMAL_SPACE && (object == NULL || - (object->flags & OBJ_COLORED) == 0)) - find_space = VMFS_ANY_SPACE; - if (find_space >> 8 != 0) { - KASSERT((find_space & 0xff) == 0, ("bad VMFS flags")); - alignment = (vm_offset_t)1 << (find_space >> 8); - } else - alignment = 0; - initial_addr = *addr; - vm_map_lock(map); -again: - start = initial_addr; + start = *addr; + result = KERN_SUCCESS; do { if (find_space != VMFS_NO_SPACE) { if (vm_map_findspace(map, start, length, addr) || - (max_addr != 0 && *addr + length > max_addr)) { - if (find_space == VMFS_OPTIMAL_SPACE) { - find_space = VMFS_ANY_SPACE; - goto again; - } - vm_map_unlock(map); + (max_addr != 0 && *addr + length > max_addr)) return (KERN_NO_SPACE); - } switch (find_space) { case VMFS_SUPER_SPACE: case VMFS_OPTIMAL_SPACE: @@ -1542,9 +1516,13 @@ } break; } - + if (*addr < start || *addr + length < *addr || + *addr + length < length || + (max_addr != 0 && *addr + length > max_addr)) + return (KERN_NO_SPACE); start = *addr; } + MPASS(result == KERN_SUCCESS || prev_start < start); if ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) { result = vm_map_stack_locked(map, start, length, sgrowsiz, prot, max, cow); @@ -1552,12 +1530,68 @@ result = vm_map_insert(map, object, offset, start, start + length, prot, max, cow); } +#ifdef INVARIANTS + prev_start = start; +#endif } while (result == KERN_NO_SPACE && find_space != VMFS_NO_SPACE && find_space != VMFS_ANY_SPACE); + return (result); +} + + +/* + * vm_map_find finds an unallocated region in the target address + * map with the given length. The search is defined to be + * first-fit from the specified address; the region found is + * returned in the same parameter. + * + * If object is non-NULL, ref count must be bumped by caller + * prior to making call to account for the new entry. + */ +int +vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset, + vm_offset_t *addr /* IN/OUT */, vm_size_t length, vm_offset_t max_addr, + int find_space, vm_prot_t prot, vm_prot_t max, int cow) +{ + vm_offset_t alignment, initial_addr; + int result; + + KASSERT((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) == 0 || + object == NULL, + ("vm_map_find: non-NULL backing object for stack")); + if (find_space == VMFS_OPTIMAL_SPACE && (object == NULL || + (object->flags & OBJ_COLORED) == 0)) + find_space = VMFS_ANY_SPACE; + if (find_space >> 8 != 0) { + KASSERT((find_space & 0xff) == 0, ("bad VMFS flags")); + alignment = (vm_offset_t)1 << (find_space >> 8); + } else + alignment = 0; + initial_addr = *addr; + vm_map_lock(map); + for (;;) { + result = vm_map_find_locked(map, object, offset, addr, length, + max_addr, find_space, alignment, prot, max, cow); + if (result == KERN_SUCCESS || find_space != VMFS_OPTIMAL_SPACE) + break; + find_space = VMFS_ANY_SPACE; + *addr = initial_addr; + } vm_map_unlock(map); return (result); } +/* + * vm_map_find_min: A wrapper around vm_map_find(). It treats + * the passed address (*addr) as the hint and not as the absolute + * minimal address of the range where the mapping is created. + * + * Function works in two phases. First, try to allocate above + * the hint. If that fails, do the second pass with less + * restrictive constraints for the start of allocation by + * specifying minimal allocation address as the start, if this + * limit is less than hint. + */ int vm_map_find_min(vm_map_t map, vm_object_t object, vm_ooffset_t offset, vm_offset_t *addr, vm_size_t length, vm_offset_t min_addr,