Changeset View
Standalone View
sys/vm/vm_map.c
Show First 20 Lines • Show All 1,477 Lines • ▼ Show 20 Lines | vm_map_fixed(vm_map_t map, vm_object_t object, vm_ooffset_t offset, | ||||
} else { | } else { | ||||
result = vm_map_insert(map, object, offset, start, end, | result = vm_map_insert(map, object, offset, start, end, | ||||
prot, max, cow); | prot, max, cow); | ||||
} | } | ||||
vm_map_unlock(map); | vm_map_unlock(map); | ||||
return (result); | return (result); | ||||
} | } | ||||
/* | static int | ||||
* vm_map_find finds an unallocated region in the target address | vm_map_find_locked(vm_map_t map, vm_object_t object, vm_ooffset_t offset, | ||||
* map with the given length. The search is defined to be | vm_offset_t *addr, vm_size_t length, vm_offset_t max_addr, int find_space, | ||||
* first-fit from the specified address; the region found is | vm_offset_t alignment, vm_prot_t prot, vm_prot_t max, int cow) | ||||
* 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, start; | vm_offset_t start; | ||||
#ifdef INVARIANTS | |||||
vm_offset_t prev_start; | |||||
#endif | |||||
int result; | int result; | ||||
KASSERT((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) == 0 || | start = *addr; | ||||
object == NULL, | result = KERN_SUCCESS; | ||||
("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; | |||||
do { | do { | ||||
if (find_space != VMFS_NO_SPACE) { | if (find_space != VMFS_NO_SPACE) { | ||||
if (vm_map_findspace(map, start, length, addr) || | if (vm_map_findspace(map, start, length, addr) || | ||||
(max_addr != 0 && *addr + length > max_addr)) { | (max_addr != 0 && *addr + length > max_addr)) | ||||
markj: Why do we drop the map lock here in the find_space == VMFS_OPTIMAL_SPACE case? | |||||
Not Done Inline ActionsIt comes from jhb' r253471, I do not know why did he decided to to the fallback this way. kib: It comes from jhb' r253471, I do not know why did he decided to to the fallback this way. | |||||
Not Done Inline ActionsI ask because I believe we otherwise hold the map lock for the duration of the loop. If we entirely avoid dropping the lock, then we can be sure that the map has not changed between successive iterations, so a single attempt at a given address is sufficient. markj: I ask because I believe we otherwise hold the map lock for the duration of the loop. If we… | |||||
Not Done Inline ActionsI think that drop of the lock can be avoided, but the second iteration cannot. Look at the VFS_OPTIMAL_SPACE case, where we retry with the VMFS_ANY_SPACE specifier if our allocation failed. kib: I think that drop of the lock can be avoided, but the second iteration cannot. Look at the… | |||||
Not Done Inline ActionsI don't recall there being any particular reason for dropping the map lock. alc: I don't recall there being any particular reason for dropping the map lock. | |||||
Not Done Inline ActionsI don't recall either, I think removing the lock drop is fine (and I think Alan's suggestion of doing that standalone first is probably a decent first change) jhb: I don't recall either, I think removing the lock drop is fine (and I think Alan's suggestion of… | |||||
if (find_space == VMFS_OPTIMAL_SPACE) { | |||||
find_space = VMFS_ANY_SPACE; | |||||
goto again; | |||||
} | |||||
vm_map_unlock(map); | |||||
return (KERN_NO_SPACE); | return (KERN_NO_SPACE); | ||||
} | |||||
switch (find_space) { | switch (find_space) { | ||||
case VMFS_SUPER_SPACE: | case VMFS_SUPER_SPACE: | ||||
case VMFS_OPTIMAL_SPACE: | case VMFS_OPTIMAL_SPACE: | ||||
pmap_align_superpage(object, offset, addr, | pmap_align_superpage(object, offset, addr, | ||||
length); | length); | ||||
break; | break; | ||||
case VMFS_ANY_SPACE: | case VMFS_ANY_SPACE: | ||||
break; | break; | ||||
default: | default: | ||||
if ((*addr & (alignment - 1)) != 0) { | if ((*addr & (alignment - 1)) != 0) { | ||||
*addr &= ~(alignment - 1); | *addr &= ~(alignment - 1); | ||||
*addr += alignment; | *addr += alignment; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
if (*addr < start || *addr + length < *addr || | |||||
*addr + length < length || | |||||
(max_addr != 0 && *addr + length > max_addr)) | |||||
return (KERN_NO_SPACE); | |||||
start = *addr; | start = *addr; | ||||
} | } | ||||
MPASS(result == KERN_SUCCESS || prev_start < start); | |||||
Not Done Inline ActionsThis probably breaks VMFS_OPTIMAL_SPACE since it would not retry with VMFS_ANY_SPACE if we failed to find a superpage aligned region? jhb: This probably breaks VMFS_OPTIMAL_SPACE since it would not retry with VMFS_ANY_SPACE if we… | |||||
Not Done Inline ActionsIf VMFS_OPTIMAL_SPACE case failed we execute goto again, which resets result to KERN_SUCCESS. kib: If VMFS_OPTIMAL_SPACE case failed we execute goto again, which resets result to KERN_SUCCESS. | |||||
Not Done Inline ActionsAh, ok. jhb: Ah, ok. | |||||
if ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) { | if ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) { | ||||
result = vm_map_stack_locked(map, start, length, | result = vm_map_stack_locked(map, start, length, | ||||
sgrowsiz, prot, max, cow); | sgrowsiz, prot, max, cow); | ||||
} else { | } else { | ||||
result = vm_map_insert(map, object, offset, start, | result = vm_map_insert(map, object, offset, start, | ||||
start + length, prot, max, cow); | start + length, prot, max, cow); | ||||
} | } | ||||
#ifdef INVARIANTS | |||||
prev_start = start; | |||||
#endif | |||||
} while (result == KERN_NO_SPACE && find_space != VMFS_NO_SPACE && | } while (result == KERN_NO_SPACE && find_space != VMFS_NO_SPACE && | ||||
find_space != VMFS_ANY_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 (;;) { | |||||
Not Done Inline ActionsI would perhaps remove the loop entirely and just do: result = vm_map_find_locked(...); if (result != KERN_SUCESS && find_space == VMFS_OPTIMAL_SPACE) { *addr = initial_addr; result = vm_map_find_locked(..., VMFS_ANY_SPACE, ...); } jhb: I would perhaps remove the loop entirely and just do:
```
result = vm_map_find_locked(...)… | |||||
Not Done Inline ActionsI considered this. I structured the second attempt with the loop because it is not obvious to the reader that the second invocation is same. See the next function vm_map_find_min() which uses loop for the same reason. kib: I considered this. I structured the second attempt with the loop because it is not obvious to… | |||||
Not Done Inline Actions
This comment led me to look at vm_map_find_min() for the first time in months, and I think that that function would really benefit having an explanatory comment added to the code. (The commit message for r320430 was quite clear, and could be a good starting point.) alc: > See the next function vm_map_find_min() which uses loop for the same reason.
This comment… | |||||
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); | vm_map_unlock(map); | ||||
return (result); | return (result); | ||||
} | } | ||||
/* | /* | ||||
* vm_map_find_min() is a variant of vm_map_find() that takes an | * vm_map_find_min() is a variant of vm_map_find() that takes an | ||||
Done Inline ActionsI suggest: "vm_map_find_min() is a variant of vm_map_find() that takes an additional parameter (min_addr) and treats the given address (*addr) differently. Specifically, it treats *addr as a hint and not as the minimum address where the mapping is created. alc: I suggest: "vm_map_find_min() is a variant of vm_map_find() that takes an additional parameter… | |||||
* additional parameter (min_addr) and treats the given address | * additional parameter (min_addr) and treats the given address | ||||
* (*addr) differently. Specifically, it treats *addr as a hint | * (*addr) differently. Specifically, it treats *addr as a hint | ||||
Not Done Inline ActionsPlease add another space after the period. alc: Please add another space after the period. | |||||
* and not as the minimum address where the mapping is created. | * and not as the minimum address where the mapping is created. | ||||
* | * | ||||
Done Inline Actions"This function ... First, it tries to ... alc: "This function ... First, it tries to ... | |||||
* This function works in two phases. First, it tries to | * This function works in two phases. First, it tries to | ||||
Done Inline Actions"... fails and the hint is greater than min_addr, it performs a second pass, replacing the hint with min_addr as the minimum address for the allocation. alc: "... fails and the hint is greater than min_addr, it performs a second pass, replacing the hint… | |||||
* allocate above the hint. If that fails and the hint is | * allocate above the hint. If that fails and the hint is | ||||
* greater than min_addr, it performs a second pass, replacing | * greater than min_addr, it performs a second pass, replacing | ||||
* the hint with min_addr as the minimum address for the | * the hint with min_addr as the minimum address for the | ||||
* allocation. | * allocation. | ||||
*/ | */ | ||||
int | int | ||||
vm_map_find_min(vm_map_t map, vm_object_t object, vm_ooffset_t offset, | 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, | vm_offset_t *addr, vm_size_t length, vm_offset_t min_addr, | ||||
▲ Show 20 Lines • Show All 2,807 Lines • Show Last 20 Lines |
Why do we drop the map lock here in the find_space == VMFS_OPTIMAL_SPACE case?