Refactor vm_map_find(), creating a separate function, vm_map_alignspace(),
for finding aligned free space in the given map. With this change, we always return KERN_NO_SPACE when we fail to find free space. Whereas, previously, we might return KERN_INVALID_ADDRESS. Also, with this change, we explicitly check for address wrap, rather than relying upon the map's min and max addresses to establish sentinel-like regions. This refactoring was inspired by the problem that we addressed in r326098. Reviewed by: kib Tested by: pho Discussed with: markj MFC after: 3 weeks Differential Revision: https://reviews.freebsd.org/D13346
This commit is contained in:
parent
1f33276ab5
commit
fec296887f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=327218
138
sys/vm/vm_map.c
138
sys/vm/vm_map.c
@ -132,6 +132,9 @@ static int vmspace_zinit(void *mem, int size, int flags);
|
|||||||
static int vm_map_zinit(void *mem, int ize, int flags);
|
static int vm_map_zinit(void *mem, int ize, int flags);
|
||||||
static void _vm_map_init(vm_map_t map, pmap_t pmap, vm_offset_t min,
|
static void _vm_map_init(vm_map_t map, pmap_t pmap, vm_offset_t min,
|
||||||
vm_offset_t max);
|
vm_offset_t max);
|
||||||
|
static int vm_map_alignspace(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, vm_offset_t alignment);
|
||||||
static void vm_map_entry_deallocate(vm_map_entry_t entry, boolean_t system_map);
|
static void vm_map_entry_deallocate(vm_map_entry_t entry, boolean_t system_map);
|
||||||
static void vm_map_entry_dispose(vm_map_t map, vm_map_entry_t entry);
|
static void vm_map_entry_dispose(vm_map_t map, vm_map_entry_t entry);
|
||||||
static void vm_map_entry_unwire(vm_map_t map, vm_map_entry_t entry);
|
static void vm_map_entry_unwire(vm_map_t map, vm_map_entry_t entry);
|
||||||
@ -1483,6 +1486,70 @@ vm_map_fixed(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
|
|||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Searches for the specified amount of free space in the given map with the
|
||||||
|
* specified alignment. Performs an address-ordered, first-fit search from
|
||||||
|
* the given address "*addr", with an optional upper bound "max_addr". If the
|
||||||
|
* parameter "alignment" is zero, then the alignment is computed from the
|
||||||
|
* given (object, offset) pair so as to enable the greatest possible use of
|
||||||
|
* superpage mappings. Returns KERN_SUCCESS and the address of the free space
|
||||||
|
* in "*addr" if successful. Otherwise, returns KERN_NO_SPACE.
|
||||||
|
*
|
||||||
|
* The map must be locked. Initially, there must be at least "length" bytes
|
||||||
|
* of free space at the given address.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
vm_map_alignspace(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,
|
||||||
|
vm_offset_t alignment)
|
||||||
|
{
|
||||||
|
vm_offset_t aligned_addr, free_addr;
|
||||||
|
|
||||||
|
VM_MAP_ASSERT_LOCKED(map);
|
||||||
|
free_addr = *addr;
|
||||||
|
KASSERT(!vm_map_findspace(map, free_addr, length, addr) &&
|
||||||
|
free_addr == *addr, ("caller provided insufficient free space"));
|
||||||
|
for (;;) {
|
||||||
|
/*
|
||||||
|
* At the start of every iteration, the free space at address
|
||||||
|
* "*addr" is at least "length" bytes.
|
||||||
|
*/
|
||||||
|
if (alignment == 0)
|
||||||
|
pmap_align_superpage(object, offset, addr, length);
|
||||||
|
else if ((*addr & (alignment - 1)) != 0) {
|
||||||
|
*addr &= ~(alignment - 1);
|
||||||
|
*addr += alignment;
|
||||||
|
}
|
||||||
|
aligned_addr = *addr;
|
||||||
|
if (aligned_addr == free_addr) {
|
||||||
|
/*
|
||||||
|
* Alignment did not change "*addr", so "*addr" must
|
||||||
|
* still provide sufficient free space.
|
||||||
|
*/
|
||||||
|
return (KERN_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test for address wrap on "*addr". A wrapped "*addr" could
|
||||||
|
* be a valid address, in which case vm_map_findspace() cannot
|
||||||
|
* be relied upon to fail.
|
||||||
|
*/
|
||||||
|
if (aligned_addr < free_addr ||
|
||||||
|
vm_map_findspace(map, aligned_addr, length, addr) ||
|
||||||
|
(max_addr != 0 && *addr + length > max_addr))
|
||||||
|
return (KERN_NO_SPACE);
|
||||||
|
free_addr = *addr;
|
||||||
|
if (free_addr == aligned_addr) {
|
||||||
|
/*
|
||||||
|
* If a successful call to vm_map_findspace() did not
|
||||||
|
* change "*addr", then "*addr" must still be aligned
|
||||||
|
* and provide sufficient free space.
|
||||||
|
*/
|
||||||
|
return (KERN_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* vm_map_find finds an unallocated region in the target address
|
* vm_map_find finds an unallocated region in the target address
|
||||||
* map with the given length. The search is defined to be
|
* map with the given length. The search is defined to be
|
||||||
@ -1498,8 +1565,8 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
|
|||||||
vm_size_t length, vm_offset_t max_addr, int find_space,
|
vm_size_t length, vm_offset_t max_addr, int find_space,
|
||||||
vm_prot_t prot, vm_prot_t max, int cow)
|
vm_prot_t prot, vm_prot_t max, int cow)
|
||||||
{
|
{
|
||||||
vm_offset_t alignment, initial_addr, start;
|
vm_offset_t alignment, min_addr;
|
||||||
int result;
|
int rv;
|
||||||
|
|
||||||
KASSERT((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) == 0 ||
|
KASSERT((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) == 0 ||
|
||||||
object == NULL,
|
object == NULL,
|
||||||
@ -1512,50 +1579,39 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
|
|||||||
alignment = (vm_offset_t)1 << (find_space >> 8);
|
alignment = (vm_offset_t)1 << (find_space >> 8);
|
||||||
} else
|
} else
|
||||||
alignment = 0;
|
alignment = 0;
|
||||||
initial_addr = *addr;
|
|
||||||
vm_map_lock(map);
|
vm_map_lock(map);
|
||||||
|
if (find_space != VMFS_NO_SPACE) {
|
||||||
|
KASSERT(find_space == VMFS_ANY_SPACE ||
|
||||||
|
find_space == VMFS_OPTIMAL_SPACE ||
|
||||||
|
find_space == VMFS_SUPER_SPACE ||
|
||||||
|
alignment != 0, ("unexpected VMFS flag"));
|
||||||
|
min_addr = *addr;
|
||||||
again:
|
again:
|
||||||
start = initial_addr;
|
if (vm_map_findspace(map, min_addr, length, addr) ||
|
||||||
do {
|
(max_addr != 0 && *addr + length > max_addr)) {
|
||||||
if (find_space != VMFS_NO_SPACE) {
|
rv = KERN_NO_SPACE;
|
||||||
if (vm_map_findspace(map, start, length, addr) ||
|
goto done;
|
||||||
(max_addr != 0 && *addr + length > max_addr)) {
|
|
||||||
if (find_space == VMFS_OPTIMAL_SPACE) {
|
|
||||||
find_space = VMFS_ANY_SPACE;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
vm_map_unlock(map);
|
|
||||||
return (KERN_NO_SPACE);
|
|
||||||
}
|
|
||||||
switch (find_space) {
|
|
||||||
case VMFS_SUPER_SPACE:
|
|
||||||
case VMFS_OPTIMAL_SPACE:
|
|
||||||
pmap_align_superpage(object, offset, addr,
|
|
||||||
length);
|
|
||||||
break;
|
|
||||||
case VMFS_ANY_SPACE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if ((*addr & (alignment - 1)) != 0) {
|
|
||||||
*addr &= ~(alignment - 1);
|
|
||||||
*addr += alignment;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
start = *addr;
|
|
||||||
}
|
}
|
||||||
if ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) {
|
if (find_space != VMFS_ANY_SPACE &&
|
||||||
result = vm_map_stack_locked(map, start, length,
|
(rv = vm_map_alignspace(map, object, offset, addr, length,
|
||||||
sgrowsiz, prot, max, cow);
|
max_addr, alignment)) != KERN_SUCCESS) {
|
||||||
} else {
|
if (find_space == VMFS_OPTIMAL_SPACE) {
|
||||||
result = vm_map_insert(map, object, offset, start,
|
find_space = VMFS_ANY_SPACE;
|
||||||
start + length, prot, max, cow);
|
goto again;
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
} while (result == KERN_NO_SPACE && find_space != VMFS_NO_SPACE &&
|
}
|
||||||
find_space != VMFS_ANY_SPACE);
|
if ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) {
|
||||||
|
rv = vm_map_stack_locked(map, *addr, length, sgrowsiz, prot,
|
||||||
|
max, cow);
|
||||||
|
} else {
|
||||||
|
rv = vm_map_insert(map, object, offset, *addr, *addr + length,
|
||||||
|
prot, max, cow);
|
||||||
|
}
|
||||||
|
done:
|
||||||
vm_map_unlock(map);
|
vm_map_unlock(map);
|
||||||
return (result);
|
return (rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user