Changeset View
Changeset View
Standalone View
Standalone View
head/sys/vm/vm_map.c
Show First 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | |||||
static uma_zone_t mapentzone; | static uma_zone_t mapentzone; | ||||
static uma_zone_t kmapentzone; | static uma_zone_t kmapentzone; | ||||
static uma_zone_t mapzone; | static uma_zone_t mapzone; | ||||
static uma_zone_t vmspace_zone; | static uma_zone_t vmspace_zone; | ||||
static int vmspace_zinit(void *mem, int size, int flags); | 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); | ||||
static int vm_map_growstack(vm_map_t map, vm_offset_t addr, | static int vm_map_growstack(vm_map_t map, vm_offset_t addr, | ||||
vm_map_entry_t gap_entry); | vm_map_entry_t gap_entry); | ||||
static void vm_map_pmap_enter(vm_map_t map, vm_offset_t addr, vm_prot_t prot, | static void vm_map_pmap_enter(vm_map_t map, vm_offset_t addr, vm_prot_t prot, | ||||
vm_object_t object, vm_pindex_t pindex, vm_size_t size, int flags); | vm_object_t object, vm_pindex_t pindex, vm_size_t size, int flags); | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
▲ Show 20 Lines • Show All 1,336 Lines • ▼ Show 20 Lines | if ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) { | ||||
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); | ||||
} | } | ||||
/* | /* | ||||
* 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 | ||||
* first-fit from the specified address; the region found is | * first-fit from the specified address; the region found is | ||||
* returned in the same parameter. | * returned in the same parameter. | ||||
* | * | ||||
* If object is non-NULL, ref count must be bumped by caller | * If object is non-NULL, ref count must be bumped by caller | ||||
* prior to making call to account for the new entry. | * prior to making call to account for the new entry. | ||||
*/ | */ | ||||
int | int | ||||
vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset, | vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset, | ||||
vm_offset_t *addr, /* IN/OUT */ | vm_offset_t *addr, /* IN/OUT */ | ||||
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, | ||||
("vm_map_find: non-NULL backing object for stack")); | ("vm_map_find: non-NULL backing object for stack")); | ||||
if (find_space == VMFS_OPTIMAL_SPACE && (object == NULL || | if (find_space == VMFS_OPTIMAL_SPACE && (object == NULL || | ||||
(object->flags & OBJ_COLORED) == 0)) | (object->flags & OBJ_COLORED) == 0)) | ||||
find_space = VMFS_ANY_SPACE; | find_space = VMFS_ANY_SPACE; | ||||
if (find_space >> 8 != 0) { | if (find_space >> 8 != 0) { | ||||
KASSERT((find_space & 0xff) == 0, ("bad VMFS flags")); | KASSERT((find_space & 0xff) == 0, ("bad VMFS flags")); | ||||
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); | ||||
again: | |||||
start = initial_addr; | |||||
do { | |||||
if (find_space != VMFS_NO_SPACE) { | if (find_space != VMFS_NO_SPACE) { | ||||
if (vm_map_findspace(map, start, length, addr) || | 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: | |||||
if (vm_map_findspace(map, min_addr, length, addr) || | |||||
(max_addr != 0 && *addr + length > max_addr)) { | (max_addr != 0 && *addr + length > max_addr)) { | ||||
rv = KERN_NO_SPACE; | |||||
goto done; | |||||
} | |||||
if (find_space != VMFS_ANY_SPACE && | |||||
(rv = vm_map_alignspace(map, object, offset, addr, length, | |||||
max_addr, alignment)) != KERN_SUCCESS) { | |||||
if (find_space == VMFS_OPTIMAL_SPACE) { | if (find_space == VMFS_OPTIMAL_SPACE) { | ||||
find_space = VMFS_ANY_SPACE; | find_space = VMFS_ANY_SPACE; | ||||
goto again; | goto again; | ||||
} | } | ||||
vm_map_unlock(map); | goto done; | ||||
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 ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) { | ||||
result = vm_map_stack_locked(map, start, length, | rv = vm_map_stack_locked(map, *addr, length, sgrowsiz, prot, | ||||
sgrowsiz, prot, max, cow); | max, cow); | ||||
} else { | } else { | ||||
result = vm_map_insert(map, object, offset, start, | rv = vm_map_insert(map, object, offset, *addr, *addr + length, | ||||
start + length, prot, max, cow); | prot, max, cow); | ||||
} | } | ||||
} while (result == KERN_NO_SPACE && find_space != VMFS_NO_SPACE && | done: | ||||
find_space != VMFS_ANY_SPACE); | |||||
vm_map_unlock(map); | vm_map_unlock(map); | ||||
return (result); | return (rv); | ||||
} | } | ||||
/* | /* | ||||
* 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 | ||||
* 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 | ||||
* and not as the minimum address where the mapping is created. | * and not as the minimum address where the mapping is created. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 2,816 Lines • Show Last 20 Lines |