Changeset View
Standalone View
vm_map.c
Show First 20 Lines • Show All 977 Lines • ▼ Show 20 Lines | |||||
static inline vm_size_t | static inline vm_size_t | ||||
vm_map_entry_max_free_right(vm_map_entry_t root, vm_map_entry_t right_ancestor) | vm_map_entry_max_free_right(vm_map_entry_t root, vm_map_entry_t right_ancestor) | ||||
{ | { | ||||
return (root->right != NULL ? | return (root->right != NULL ? | ||||
root->right->max_free : right_ancestor->start - root->end); | root->right->max_free : right_ancestor->start - root->end); | ||||
} | } | ||||
/* | |||||
* vm_map_splay_split, vm_map_splay_merge: | |||||
* | |||||
* The Sleator and Tarjan top-down splay algorithm with the following | |||||
* variation. Max_free must be computed bottom-up, so on the downward | |||||
* pass (vm_map_splay_split), maintain the left and right spines in | |||||
* reverse order, and ensure that the max_free values for those nodes | |||||
* store the values of their descendents not on the search path. Later, | |||||
* make a second pass up each side (vm_map_splay_merge) to fix the | |||||
* pointers and compute max_free. The time bound is O(log n) amortized. | |||||
*/ | |||||
#define SPLAY_LEFT_STEP(root, y, rlist, test) do { \ | #define SPLAY_LEFT_STEP(root, y, rlist, test) do { \ | ||||
vm_size_t max_free; \ | vm_size_t max_free; \ | ||||
\ | \ | ||||
/* \ | /* \ | ||||
* Infer root->right->max_free == root->max_free when \ | * Infer root->right->max_free == root->max_free when \ | ||||
* y->max_free < root->max_free || root->max_free == 0. \ | * y->max_free < root->max_free || root->max_free == 0. \ | ||||
* Otherwise, look right to find it. \ | * Otherwise, look right to find it. \ | ||||
*/ \ | */ \ | ||||
▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | if (rlist != &map->header) { | ||||
} while (rlist != &map->header); | } while (rlist != &map->header); | ||||
root->right = prev; | root->right = prev; | ||||
} | } | ||||
root->max_free = MAX(max_free_left, max_free_right); | root->max_free = MAX(max_free_left, max_free_right); | ||||
map->root = root; | map->root = root; | ||||
} | } | ||||
/* | /* | ||||
* vm_map_splay: | |||||
* | |||||
* The Sleator and Tarjan top-down splay algorithm with the | |||||
* following variation. Max_free must be computed bottom-up, so | |||||
* on the downward pass, maintain the left and right spines in | |||||
* reverse order. Then, make a second pass up each side to fix | |||||
* the pointers and compute max_free. The time bound is O(log n) | |||||
* amortized. | |||||
markj: Should this comment be preserved? | |||||
Done Inline ActionsI've updated it a bit and put it just before the first splay-specific code. dougm: I've updated it a bit and put it just before the first splay-specific code. | |||||
* | |||||
* The new root is the vm_map_entry containing "addr", or else an | |||||
* adjacent entry (lower if possible) if addr is not in the tree. | |||||
* | |||||
* The map must be locked, and leaves it so. | |||||
* | |||||
* Returns: the new root. | |||||
*/ | |||||
static vm_map_entry_t | |||||
vm_map_splay(vm_map_t map, vm_offset_t addr) | |||||
{ | |||||
vm_map_entry_t llist, rlist, root; | |||||
root = vm_map_splay_split(map, addr, 0, &llist, &rlist); | |||||
if (root != NULL) { | |||||
/* do nothing */ | |||||
} else if (llist != &map->header) { | |||||
/* | |||||
* Recover the greatest node in the left | |||||
* subtree and make it the root. | |||||
*/ | |||||
root = llist; | |||||
llist = root->right; | |||||
root->right = NULL; | |||||
} else if (rlist != &map->header) { | |||||
/* | |||||
* Recover the least node in the right | |||||
* subtree and make it the root. | |||||
*/ | |||||
root = rlist; | |||||
rlist = root->left; | |||||
root->left = NULL; | |||||
} else { | |||||
/* There is no root. */ | |||||
return (NULL); | |||||
} | |||||
vm_map_splay_merge(map, root, llist, rlist); | |||||
VM_MAP_ASSERT_CONSISTENT(map); | |||||
return (root); | |||||
} | |||||
/* | |||||
* vm_map_entry_{un,}link: | * vm_map_entry_{un,}link: | ||||
* | * | ||||
* Insert/remove entries from maps. | * Insert/remove entries from maps. | ||||
*/ | */ | ||||
static void | static void | ||||
vm_map_entry_link(vm_map_t map, vm_map_entry_t entry) | vm_map_entry_link(vm_map_t map, vm_map_entry_t entry) | ||||
{ | { | ||||
vm_map_entry_t llist, rlist, root; | vm_map_entry_t llist, rlist, root; | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | vm_map_entry_resize(vm_map_t map, vm_map_entry_t entry, vm_size_t grow_amount) | ||||
entry->end += grow_amount; | entry->end += grow_amount; | ||||
vm_map_splay_merge(map, root, llist, rlist); | vm_map_splay_merge(map, root, llist, rlist); | ||||
VM_MAP_ASSERT_CONSISTENT(map); | VM_MAP_ASSERT_CONSISTENT(map); | ||||
CTR4(KTR_VM, "%s: map %p, nentries %d, entry %p", | CTR4(KTR_VM, "%s: map %p, nentries %d, entry %p", | ||||
__func__, map, map->nentries, entry); | __func__, map, map->nentries, entry); | ||||
} | } | ||||
/* | /* | ||||
* vm_map_lookup_entry: [ internal use only ] | * vm_map_lookup_helper: [ internal use only ] | ||||
* | * | ||||
* Finds the map entry containing (or | * Finds the map entry containing (or adjacent to) the specified address | ||||
* immediately preceding) the specified address | * in the given map; the entry is returned in the "entry" parameter. The | ||||
* in the given map; the entry is returned | * boolean result indicates whether the address is actually contained in | ||||
* in the "entry" parameter. The boolean | * the map. If the address is not contained in the map, parameter lesseq | ||||
* result indicates whether the address is | * determines whether the entry provided is before or after the address. | ||||
Done Inline Actions"the entry provided" markj: "the entry provided" | |||||
* actually contained in the map. | * If the address is contained in the map, parameter nbr, if not NULL, is | ||||
* where the next or previous entry is saved, depending on the value of | |||||
* eflags in the found entry. | |||||
*/ | */ | ||||
boolean_t | static bool | ||||
vm_map_lookup_entry( | vm_map_lookup_helper(vm_map_t map, vm_offset_t addr, bool lesseq, | ||||
vm_map_t map, | vm_map_entry_t *entry, vm_map_entry_t *nbr) /* OUT */ | ||||
vm_offset_t address, | |||||
vm_map_entry_t *entry) /* OUT */ | |||||
{ | { | ||||
vm_map_entry_t cur, lbound; | vm_map_entry_t llist, rlist, root; | ||||
boolean_t locked; | bool locked, found; | ||||
/* | /* | ||||
* If the map is empty, then the map entry immediately preceding | * If the map is empty, then the map entry immediately preceding | ||||
* "address" is the map's header. | * "addr" is the map's header. | ||||
*/ | */ | ||||
cur = map->root; | root = map->root; | ||||
if (cur == NULL) { | if (root == NULL) { | ||||
*entry = &map->header; | *entry = &map->header; | ||||
return (FALSE); | return (false); | ||||
} | } | ||||
if (address >= cur->start && cur->end > address) { | |||||
*entry = cur; | |||||
return (TRUE); | |||||
} | |||||
if ((locked = vm_map_locked(map)) || | if ((locked = vm_map_locked(map)) || | ||||
sx_try_upgrade(&map->lock)) { | sx_try_upgrade(&map->lock)) { | ||||
/* | /* | ||||
* Splay requires a write lock on the map. However, it only | * Splay requires a write lock on the map. However, it only | ||||
* restructures the binary search tree; it does not otherwise | * restructures the binary search tree; it does not otherwise | ||||
* change the map. Thus, the map's timestamp need not change | * change the map. Thus, the map's timestamp need not change | ||||
* on a temporary upgrade. | * on a temporary upgrade. | ||||
*/ | */ | ||||
cur = vm_map_splay(map, address); | root = vm_map_splay_split(map, addr, 0, &llist, &rlist); | ||||
if (!locked) | found = root != NULL; | ||||
Not Done Inline Actionsrv typically denotes a value containing Mach error code, a 'Return Value' from some function. kib: rv typically denotes a value containing Mach error code, a 'Return Value' from some function. | |||||
sx_downgrade(&map->lock); | *entry = root; | ||||
if (root != NULL) { | |||||
if (nbr == NULL) | |||||
Not Done Inline ActionsThis ';' should be on the new line and properly indented. Sometimes people even add a comment like /* Ignore */; kib: This ';' should be on the new line and properly indented. Sometimes people even add a comment… | |||||
; /* Ignore. */ | |||||
else if ((root->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { | |||||
vm_map_splay_findnext(root, &rlist); | |||||
*nbr = rlist; | |||||
} else { | |||||
vm_map_splay_findprev(root, &llist); | |||||
*nbr = llist; | |||||
} | |||||
} else if (llist != &map->header) { | |||||
/* | /* | ||||
* If "address" is contained within a map entry, the new root | * Recover the greatest node in the left | ||||
* is that map entry. Otherwise, the new root is a map entry | * subtree and make it the root. | ||||
* immediately before or after "address". | |||||
*/ | */ | ||||
if (address < cur->start) { | *entry = lesseq ? llist : rlist; | ||||
*entry = &map->header; | root = llist; | ||||
return (FALSE); | llist = root->right; | ||||
root->right = NULL; | |||||
} else { | |||||
/* | |||||
* Recover the least node in the right | |||||
* subtree and make it the root. | |||||
*/ | |||||
*entry = lesseq ? llist : rlist; | |||||
root = rlist; | |||||
rlist = root->left; | |||||
root->left = NULL; | |||||
} | } | ||||
*entry = cur; | vm_map_splay_merge(map, root, llist, rlist); | ||||
Not Done Inline ActionsAll of the vm_map_splay_merge() calls are followed by this assert. Is there a reason to not just assert in vm_map_splay_merge() instead? markj: All of the `vm_map_splay_merge()` calls are followed by this assert. Is there a reason to not… | |||||
Done Inline ActionsThere is an exception in vm_map_findspace, and I don't think the consistency check would pass there. I could avoid calling vm_map_splay_merge there, and just copy a bit of code. Or I could stop trying to bring ranges on either side of the found space to the top of the map, and let the range to the right stay (possibly) near the bottom of the tree. dougm: There is an exception in vm_map_findspace, and I don't think the consistency check would pass… | |||||
return (address < cur->end); | VM_MAP_ASSERT_CONSISTENT(map); | ||||
if (!locked) | |||||
sx_downgrade(&map->lock); | |||||
return (found); | |||||
} | } | ||||
/* | /* | ||||
Not Done Inline ActionsThere should be a blank line before multi-line comment. Since you change a lot of code in the function, it makes sense to fix this style bug. kib: There should be a blank line before multi-line comment. Since you change a lot of code in the… | |||||
* Since the map is only locked for read access, perform a | * Since the map is only locked for read access, perform a | ||||
* standard binary search tree lookup for "address". | * standard binary search tree lookup for "addr". | ||||
*/ | */ | ||||
lbound = &map->header; | llist = rlist = &map->header; | ||||
do { | do { | ||||
if (address < cur->start) { | if (addr < root->start) { | ||||
cur = cur->left; | rlist = root; | ||||
} else if (cur->end <= address) { | root = root->left; | ||||
lbound = cur; | } else if (root->end <= addr) { | ||||
cur = cur->right; | llist = root; | ||||
root = root->right; | |||||
} else { | } else { | ||||
*entry = cur; | *entry = root; | ||||
return (TRUE); | if (nbr == NULL); | ||||
else if ((root->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { | |||||
/* Make nbr the successor to root. */ | |||||
if (root->right != NULL) { | |||||
rlist = root->right; | |||||
while (rlist->left != NULL) | |||||
rlist = rlist->left; | |||||
} | } | ||||
} while (cur != NULL); | *nbr = rlist; | ||||
*entry = lbound; | } else { | ||||
return (FALSE); | /* Make nbr the predecessor to root. */ | ||||
if (root->left != NULL) { | |||||
llist = root->left; | |||||
while (llist->right != NULL) | |||||
llist = llist->right; | |||||
} | } | ||||
*nbr = llist; | |||||
} | |||||
return (true); | |||||
} | |||||
} while (root != NULL); | |||||
*entry = lesseq ? llist : rlist; | |||||
return (false); | |||||
} | |||||
bool | |||||
vm_map_lookup_entry(vm_map_t map, vm_offset_t addr, | |||||
vm_map_entry_t *entry) /* OUT */ | |||||
{ | |||||
return (vm_map_lookup_helper(map, addr, true, entry, NULL)); | |||||
} | |||||
static bool | |||||
vm_map_lookup_entry_ge(vm_map_t map, vm_offset_t addr, | |||||
Done Inline ActionsIt would be a bit more consistent with other code to use a "_ge" suffix instead. We have vm_radix_lookup_ge() and SWAP_PCTRIE_LOOKUP_GE(), for example. markj: It would be a bit more consistent with other code to use a "_ge" suffix instead. We have… | |||||
vm_map_entry_t *entry) /* OUT */ | |||||
{ | |||||
return (vm_map_lookup_helper(map, addr, false, entry, NULL)); | |||||
} | |||||
/* | /* | ||||
* vm_map_insert: | * vm_map_insert: | ||||
* | * | ||||
* Inserts the given whole VM object into the target | * Inserts the given whole VM object into the target | ||||
* map at the specified address range. The object's | * map at the specified address range. The object's | ||||
* size should match that of the address range. | * size should match that of the address range. | ||||
* | * | ||||
* Requires that the map be locked, and leaves it so. | * Requires that the map be locked, and leaves it so. | ||||
* | * | ||||
* 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_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset, | vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset, | ||||
vm_offset_t start, vm_offset_t end, vm_prot_t prot, vm_prot_t max, int cow) | vm_offset_t start, vm_offset_t end, vm_prot_t prot, vm_prot_t max, int cow) | ||||
{ | { | ||||
vm_map_entry_t new_entry, prev_entry, temp_entry; | vm_map_entry_t new_entry, prev_entry; | ||||
struct ucred *cred; | struct ucred *cred; | ||||
vm_eflags_t protoeflags; | vm_eflags_t protoeflags; | ||||
vm_inherit_t inheritance; | vm_inherit_t inheritance; | ||||
VM_MAP_ASSERT_LOCKED(map); | VM_MAP_ASSERT_LOCKED(map); | ||||
KASSERT(object != kernel_object || | KASSERT(object != kernel_object || | ||||
(cow & MAP_COPY_ON_WRITE) == 0, | (cow & MAP_COPY_ON_WRITE) == 0, | ||||
("vm_map_insert: kernel object and COW")); | ("vm_map_insert: kernel object and COW")); | ||||
KASSERT(object == NULL || (cow & MAP_NOFAULT) == 0, | KASSERT(object == NULL || (cow & MAP_NOFAULT) == 0, | ||||
("vm_map_insert: paradoxical MAP_NOFAULT request")); | ("vm_map_insert: paradoxical MAP_NOFAULT request")); | ||||
KASSERT((prot & ~max) == 0, | KASSERT((prot & ~max) == 0, | ||||
("prot %#x is not subset of max_prot %#x", prot, max)); | ("prot %#x is not subset of max_prot %#x", prot, max)); | ||||
/* | /* | ||||
* Check that the start and end points are not bogus. | * Check that the start and end points are not bogus. | ||||
*/ | */ | ||||
if (start < vm_map_min(map) || end > vm_map_max(map) || | if (start < vm_map_min(map) || end > vm_map_max(map) || | ||||
start >= end) | start >= end) | ||||
return (KERN_INVALID_ADDRESS); | return (KERN_INVALID_ADDRESS); | ||||
/* | /* | ||||
* Find the entry prior to the proposed starting address; if it's part | * Find the entry prior to the proposed starting address; if it's part | ||||
* of an existing entry, this range is bogus. | * of an existing entry, this range is bogus. | ||||
*/ | */ | ||||
if (vm_map_lookup_entry(map, start, &temp_entry)) | if (vm_map_lookup_entry(map, start, &prev_entry)) | ||||
return (KERN_NO_SPACE); | return (KERN_NO_SPACE); | ||||
prev_entry = temp_entry; | |||||
/* | /* | ||||
* Assert that the next entry doesn't overlap the end point. | * Assert that the next entry doesn't overlap the end point. | ||||
*/ | */ | ||||
if (prev_entry->next->start < end) | if (prev_entry->next->start < end) | ||||
return (KERN_NO_SPACE); | return (KERN_NO_SPACE); | ||||
if ((cow & MAP_CREATE_GUARD) != 0 && (object != NULL || | if ((cow & MAP_CREATE_GUARD) != 0 && (object != NULL || | ||||
max != VM_PROT_NONE)) | max != VM_PROT_NONE)) | ||||
▲ Show 20 Lines • Show All 846 Lines • ▼ Show 20 Lines | vm_map_submap( | ||||
vm_map_lock(submap); | vm_map_lock(submap); | ||||
submap->flags |= MAP_IS_SUB_MAP; | submap->flags |= MAP_IS_SUB_MAP; | ||||
vm_map_unlock(submap); | vm_map_unlock(submap); | ||||
vm_map_lock(map); | vm_map_lock(map); | ||||
VM_MAP_RANGE_CHECK(map, start, end); | VM_MAP_RANGE_CHECK(map, start, end); | ||||
if (vm_map_lookup_entry(map, start, &entry)) { | if (vm_map_lookup_entry_ge(map, start, &entry)) | ||||
vm_map_clip_start(map, entry, start); | vm_map_clip_start(map, entry, start); | ||||
} else | |||||
entry = entry->next; | |||||
vm_map_clip_end(map, entry, end); | vm_map_clip_end(map, entry, end); | ||||
if ((entry->start == start) && (entry->end == end) && | if ((entry->start == start) && (entry->end == end) && | ||||
((entry->eflags & MAP_ENTRY_COW) == 0) && | ((entry->eflags & MAP_ENTRY_COW) == 0) && | ||||
(entry->object.vm_object == NULL)) { | (entry->object.vm_object == NULL)) { | ||||
entry->object.sub_map = submap; | entry->object.sub_map = submap; | ||||
entry->eflags |= MAP_ENTRY_IS_SUB_MAP; | entry->eflags |= MAP_ENTRY_IS_SUB_MAP; | ||||
▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | again: | ||||
* need to fault pages into the map and will drop the map lock while | * need to fault pages into the map and will drop the map lock while | ||||
* doing so, and the VM object may end up in an inconsistent state if we | * doing so, and the VM object may end up in an inconsistent state if we | ||||
* update the protection on the map entry in between faults. | * update the protection on the map entry in between faults. | ||||
*/ | */ | ||||
vm_map_wait_busy(map); | vm_map_wait_busy(map); | ||||
VM_MAP_RANGE_CHECK(map, start, end); | VM_MAP_RANGE_CHECK(map, start, end); | ||||
if (!vm_map_lookup_entry(map, start, &entry)) | vm_map_lookup_entry_ge(map, start, &entry); | ||||
entry = entry->next; | |||||
/* | /* | ||||
* Make a first pass to check for protection violations. | * Make a first pass to check for protection violations. | ||||
*/ | */ | ||||
for (current = entry; current->start < end; current = current->next) { | for (current = entry; current->start < end; current = current->next) { | ||||
if ((current->eflags & MAP_ENTRY_GUARD) != 0) | if ((current->eflags & MAP_ENTRY_GUARD) != 0) | ||||
continue; | continue; | ||||
if (current->eflags & MAP_ENTRY_IS_SUB_MAP) { | if (current->eflags & MAP_ENTRY_IS_SUB_MAP) { | ||||
▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | default: | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* | /* | ||||
* Locate starting entry and clip if necessary. | * Locate starting entry and clip if necessary. | ||||
*/ | */ | ||||
VM_MAP_RANGE_CHECK(map, start, end); | VM_MAP_RANGE_CHECK(map, start, end); | ||||
if (vm_map_lookup_entry(map, start, &entry)) { | if (vm_map_lookup_entry_ge(map, start, &entry)) { | ||||
if (modify_map) | if (modify_map) | ||||
vm_map_clip_start(map, entry, start); | vm_map_clip_start(map, entry, start); | ||||
} else { | |||||
entry = entry->next; | |||||
} | } | ||||
if (modify_map) { | if (modify_map) { | ||||
/* | /* | ||||
* madvise behaviors that are implemented in the vm_map_entry. | * madvise behaviors that are implemented in the vm_map_entry. | ||||
* | * | ||||
* We clip the vm_map_entry so that behavioral changes are | * We clip the vm_map_entry so that behavioral changes are | ||||
* limited to the specified address range. | * limited to the specified address range. | ||||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | |||||
* affects how the map will be shared with | * affects how the map will be shared with | ||||
* child maps at the time of vmspace_fork. | * child maps at the time of vmspace_fork. | ||||
*/ | */ | ||||
int | int | ||||
vm_map_inherit(vm_map_t map, vm_offset_t start, vm_offset_t end, | vm_map_inherit(vm_map_t map, vm_offset_t start, vm_offset_t end, | ||||
vm_inherit_t new_inheritance) | vm_inherit_t new_inheritance) | ||||
{ | { | ||||
vm_map_entry_t entry; | vm_map_entry_t entry; | ||||
vm_map_entry_t temp_entry; | |||||
switch (new_inheritance) { | switch (new_inheritance) { | ||||
case VM_INHERIT_NONE: | case VM_INHERIT_NONE: | ||||
case VM_INHERIT_COPY: | case VM_INHERIT_COPY: | ||||
case VM_INHERIT_SHARE: | case VM_INHERIT_SHARE: | ||||
case VM_INHERIT_ZERO: | case VM_INHERIT_ZERO: | ||||
break; | break; | ||||
default: | default: | ||||
return (KERN_INVALID_ARGUMENT); | return (KERN_INVALID_ARGUMENT); | ||||
} | } | ||||
if (start == end) | if (start == end) | ||||
return (KERN_SUCCESS); | return (KERN_SUCCESS); | ||||
vm_map_lock(map); | vm_map_lock(map); | ||||
VM_MAP_RANGE_CHECK(map, start, end); | VM_MAP_RANGE_CHECK(map, start, end); | ||||
if (vm_map_lookup_entry(map, start, &temp_entry)) { | if (vm_map_lookup_entry_ge(map, start, &entry)) | ||||
entry = temp_entry; | |||||
vm_map_clip_start(map, entry, start); | vm_map_clip_start(map, entry, start); | ||||
} else | |||||
entry = temp_entry->next; | |||||
while (entry->start < end) { | while (entry->start < end) { | ||||
vm_map_clip_end(map, entry, end); | vm_map_clip_end(map, entry, end); | ||||
if ((entry->eflags & MAP_ENTRY_GUARD) == 0 || | if ((entry->eflags & MAP_ENTRY_GUARD) == 0 || | ||||
new_inheritance != VM_INHERIT_ZERO) | new_inheritance != VM_INHERIT_ZERO) | ||||
entry->inheritance = new_inheritance; | entry->inheritance = new_inheritance; | ||||
vm_map_simplify_entry(map, entry); | vm_map_simplify_entry(map, entry); | ||||
entry = entry->next; | entry = entry->next; | ||||
} | } | ||||
Show All 16 Lines | vm_map_unwire(vm_map_t map, vm_offset_t start, vm_offset_t end, | ||||
int rv; | int rv; | ||||
boolean_t need_wakeup, result, user_unwire; | boolean_t need_wakeup, result, user_unwire; | ||||
if (start == end) | if (start == end) | ||||
return (KERN_SUCCESS); | return (KERN_SUCCESS); | ||||
user_unwire = (flags & VM_MAP_WIRE_USER) ? TRUE : FALSE; | user_unwire = (flags & VM_MAP_WIRE_USER) ? TRUE : FALSE; | ||||
vm_map_lock(map); | vm_map_lock(map); | ||||
VM_MAP_RANGE_CHECK(map, start, end); | VM_MAP_RANGE_CHECK(map, start, end); | ||||
if (!vm_map_lookup_entry(map, start, &first_entry)) { | if (!vm_map_lookup_entry_ge(map, start, &first_entry)) { | ||||
if (flags & VM_MAP_WIRE_HOLESOK) | if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { | ||||
first_entry = first_entry->next; | |||||
else { | |||||
vm_map_unlock(map); | vm_map_unlock(map); | ||||
return (KERN_INVALID_ADDRESS); | return (KERN_INVALID_ADDRESS); | ||||
} | } | ||||
} | } | ||||
last_timestamp = map->timestamp; | last_timestamp = map->timestamp; | ||||
entry = first_entry; | entry = first_entry; | ||||
while (entry->start < end) { | while (entry->start < end) { | ||||
if (entry->eflags & MAP_ENTRY_IN_TRANSITION) { | if (entry->eflags & MAP_ENTRY_IN_TRANSITION) { | ||||
Show All 11 Lines | if (entry->eflags & MAP_ENTRY_IN_TRANSITION) { | ||||
vm_map_lock(map); | vm_map_lock(map); | ||||
if (last_timestamp+1 != map->timestamp) { | if (last_timestamp+1 != map->timestamp) { | ||||
/* | /* | ||||
* Look again for the entry because the map was | * Look again for the entry because the map was | ||||
* modified while it was unlocked. | * modified while it was unlocked. | ||||
* Specifically, the entry may have been | * Specifically, the entry may have been | ||||
* clipped, merged, or deleted. | * clipped, merged, or deleted. | ||||
*/ | */ | ||||
if (!vm_map_lookup_entry(map, saved_start, | if (!vm_map_lookup_entry_ge(map, saved_start, | ||||
&tmp_entry)) { | &tmp_entry)) { | ||||
if (flags & VM_MAP_WIRE_HOLESOK) | if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { | ||||
tmp_entry = tmp_entry->next; | |||||
else { | |||||
if (saved_start == start) { | if (saved_start == start) { | ||||
/* | /* | ||||
* First_entry has been deleted. | * First_entry has been deleted. | ||||
*/ | */ | ||||
vm_map_unlock(map); | vm_map_unlock(map); | ||||
return (KERN_INVALID_ADDRESS); | return (KERN_INVALID_ADDRESS); | ||||
} | } | ||||
end = saved_start; | end = saved_start; | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (!user_unwire && | ||||
goto done; | goto done; | ||||
} | } | ||||
entry = entry->next; | entry = entry->next; | ||||
} | } | ||||
rv = KERN_SUCCESS; | rv = KERN_SUCCESS; | ||||
done: | done: | ||||
need_wakeup = FALSE; | need_wakeup = FALSE; | ||||
if (first_entry == NULL) { | if (first_entry == NULL) { | ||||
result = vm_map_lookup_entry(map, start, &first_entry); | result = vm_map_lookup_entry_ge(map, start, &first_entry); | ||||
if (!result && (flags & VM_MAP_WIRE_HOLESOK)) | KASSERT(result || (flags & VM_MAP_WIRE_HOLESOK) != 0, | ||||
first_entry = first_entry->next; | ("vm_map_unwire: lookup failed")); | ||||
else | |||||
KASSERT(result, ("vm_map_unwire: lookup failed")); | |||||
} | } | ||||
for (entry = first_entry; entry->start < end; entry = entry->next) { | for (entry = first_entry; entry->start < end; entry = entry->next) { | ||||
/* | /* | ||||
* If VM_MAP_WIRE_HOLESOK was specified, an empty | * If VM_MAP_WIRE_HOLESOK was specified, an empty | ||||
* space in the unwired region could have been mapped | * space in the unwired region could have been mapped | ||||
* while the map lock was dropped for draining | * while the map lock was dropped for draining | ||||
* MAP_ENTRY_IN_TRANSITION. Moreover, another thread | * MAP_ENTRY_IN_TRANSITION. Moreover, another thread | ||||
* could be simultaneously wiring this new mapping | * could be simultaneously wiring this new mapping | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | vm_map_wire_locked(vm_map_t map, vm_offset_t start, vm_offset_t end, int flags) | ||||
if (start == end) | if (start == end) | ||||
return (KERN_SUCCESS); | return (KERN_SUCCESS); | ||||
prot = 0; | prot = 0; | ||||
if (flags & VM_MAP_WIRE_WRITE) | if (flags & VM_MAP_WIRE_WRITE) | ||||
prot |= VM_PROT_WRITE; | prot |= VM_PROT_WRITE; | ||||
user_wire = (flags & VM_MAP_WIRE_USER) ? TRUE : FALSE; | user_wire = (flags & VM_MAP_WIRE_USER) ? TRUE : FALSE; | ||||
VM_MAP_RANGE_CHECK(map, start, end); | VM_MAP_RANGE_CHECK(map, start, end); | ||||
if (!vm_map_lookup_entry(map, start, &first_entry)) { | if (!vm_map_lookup_entry_ge(map, start, &first_entry)) { | ||||
if (flags & VM_MAP_WIRE_HOLESOK) | if ((flags & VM_MAP_WIRE_HOLESOK) == 0) | ||||
first_entry = first_entry->next; | |||||
else | |||||
return (KERN_INVALID_ADDRESS); | return (KERN_INVALID_ADDRESS); | ||||
} | } | ||||
last_timestamp = map->timestamp; | last_timestamp = map->timestamp; | ||||
entry = first_entry; | entry = first_entry; | ||||
while (entry->start < end) { | while (entry->start < end) { | ||||
if (entry->eflags & MAP_ENTRY_IN_TRANSITION) { | if (entry->eflags & MAP_ENTRY_IN_TRANSITION) { | ||||
/* | /* | ||||
* We have not yet clipped the entry. | * We have not yet clipped the entry. | ||||
Show All 9 Lines | if (entry->eflags & MAP_ENTRY_IN_TRANSITION) { | ||||
vm_map_lock(map); | vm_map_lock(map); | ||||
if (last_timestamp + 1 != map->timestamp) { | if (last_timestamp + 1 != map->timestamp) { | ||||
/* | /* | ||||
* Look again for the entry because the map was | * Look again for the entry because the map was | ||||
* modified while it was unlocked. | * modified while it was unlocked. | ||||
* Specifically, the entry may have been | * Specifically, the entry may have been | ||||
* clipped, merged, or deleted. | * clipped, merged, or deleted. | ||||
*/ | */ | ||||
if (!vm_map_lookup_entry(map, saved_start, | if (!vm_map_lookup_entry_ge(map, saved_start, | ||||
&tmp_entry)) { | &tmp_entry)) { | ||||
if (flags & VM_MAP_WIRE_HOLESOK) | if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { | ||||
tmp_entry = tmp_entry->next; | |||||
else { | |||||
if (saved_start == start) { | if (saved_start == start) { | ||||
/* | /* | ||||
* first_entry has been deleted. | * first_entry has been deleted. | ||||
*/ | */ | ||||
return (KERN_INVALID_ADDRESS); | return (KERN_INVALID_ADDRESS); | ||||
} | } | ||||
end = saved_start; | end = saved_start; | ||||
rv = KERN_INVALID_ADDRESS; | rv = KERN_INVALID_ADDRESS; | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | if ((flags & VM_MAP_WIRE_HOLESOK) == 0 && | ||||
goto done; | goto done; | ||||
} | } | ||||
entry = entry->next; | entry = entry->next; | ||||
} | } | ||||
rv = KERN_SUCCESS; | rv = KERN_SUCCESS; | ||||
done: | done: | ||||
need_wakeup = FALSE; | need_wakeup = FALSE; | ||||
if (first_entry == NULL) { | if (first_entry == NULL) { | ||||
result = vm_map_lookup_entry(map, start, &first_entry); | result = vm_map_lookup_entry_ge(map, start, &first_entry); | ||||
if (!result && (flags & VM_MAP_WIRE_HOLESOK)) | KASSERT(result || (flags & VM_MAP_WIRE_HOLESOK) != 0, | ||||
first_entry = first_entry->next; | ("vm_map_wire: lookup failed")); | ||||
else | |||||
KASSERT(result, ("vm_map_wire: lookup failed")); | |||||
} | } | ||||
for (entry = first_entry; entry->start < end; entry = entry->next) { | for (entry = first_entry; entry->start < end; entry = entry->next) { | ||||
/* | /* | ||||
* If VM_MAP_WIRE_HOLESOK was specified, an empty | * If VM_MAP_WIRE_HOLESOK was specified, an empty | ||||
* space in the unwired region could have been mapped | * space in the unwired region could have been mapped | ||||
* while the map lock was dropped for faulting in the | * while the map lock was dropped for faulting in the | ||||
* pages or draining MAP_ENTRY_IN_TRANSITION. | * pages or draining MAP_ENTRY_IN_TRANSITION. | ||||
* Moreover, another thread could be simultaneously | * Moreover, another thread could be simultaneously | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | vm_map_sync( | ||||
unsigned int last_timestamp; | unsigned int last_timestamp; | ||||
boolean_t failed; | boolean_t failed; | ||||
vm_map_lock_read(map); | vm_map_lock_read(map); | ||||
VM_MAP_RANGE_CHECK(map, start, end); | VM_MAP_RANGE_CHECK(map, start, end); | ||||
if (!vm_map_lookup_entry(map, start, &entry)) { | if (!vm_map_lookup_entry(map, start, &entry)) { | ||||
vm_map_unlock_read(map); | vm_map_unlock_read(map); | ||||
return (KERN_INVALID_ADDRESS); | return (KERN_INVALID_ADDRESS); | ||||
} else if (start == end) { | } | ||||
if (start == end) { | |||||
start = entry->start; | start = entry->start; | ||||
end = entry->end; | end = entry->end; | ||||
} | } | ||||
/* | /* | ||||
* Make a first pass to check for user-wired memory and holes. | * Make a first pass to check for user-wired memory and holes. | ||||
*/ | */ | ||||
for (current = entry; current->start < end; current = current->next) { | for (current = entry; current->start < end; current = current->next) { | ||||
if (invalidate && (current->eflags & MAP_ENTRY_USER_WIRED)) { | if (invalidate && (current->eflags & MAP_ENTRY_USER_WIRED)) { | ||||
Show All 38 Lines | for (current = entry; current->start < end;) { | ||||
vm_object_reference(object); | vm_object_reference(object); | ||||
last_timestamp = map->timestamp; | last_timestamp = map->timestamp; | ||||
vm_map_unlock_read(map); | vm_map_unlock_read(map); | ||||
if (!vm_object_sync(object, offset, size, syncio, invalidate)) | if (!vm_object_sync(object, offset, size, syncio, invalidate)) | ||||
failed = TRUE; | failed = TRUE; | ||||
start += size; | start += size; | ||||
vm_object_deallocate(object); | vm_object_deallocate(object); | ||||
vm_map_lock_read(map); | vm_map_lock_read(map); | ||||
if (last_timestamp == map->timestamp || | if (last_timestamp == map->timestamp) | ||||
!vm_map_lookup_entry(map, start, ¤t)) | |||||
current = current->next; | current = current->next; | ||||
else | |||||
vm_map_lookup_entry_ge(map, start, ¤t); | |||||
} | } | ||||
vm_map_unlock_read(map); | vm_map_unlock_read(map); | ||||
return (failed ? KERN_FAILURE : KERN_SUCCESS); | return (failed ? KERN_FAILURE : KERN_SUCCESS); | ||||
} | } | ||||
/* | /* | ||||
* vm_map_entry_unwire: [ internal use only ] | * vm_map_entry_unwire: [ internal use only ] | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* Deallocates the given address range from the target | * Deallocates the given address range from the target | ||||
* map. | * map. | ||||
*/ | */ | ||||
int | int | ||||
vm_map_delete(vm_map_t map, vm_offset_t start, vm_offset_t end) | vm_map_delete(vm_map_t map, vm_offset_t start, vm_offset_t end) | ||||
{ | { | ||||
vm_map_entry_t entry; | vm_map_entry_t entry; | ||||
vm_map_entry_t first_entry; | |||||
VM_MAP_ASSERT_LOCKED(map); | VM_MAP_ASSERT_LOCKED(map); | ||||
if (start == end) | if (start == end) | ||||
return (KERN_SUCCESS); | return (KERN_SUCCESS); | ||||
/* | /* | ||||
* Find the start of the region, and clip it | * Find the start of the region, and clip it | ||||
*/ | */ | ||||
if (!vm_map_lookup_entry(map, start, &first_entry)) | if (vm_map_lookup_entry_ge(map, start, &entry)) | ||||
entry = first_entry->next; | |||||
else { | |||||
entry = first_entry; | |||||
vm_map_clip_start(map, entry, start); | vm_map_clip_start(map, entry, start); | ||||
} | |||||
/* | /* | ||||
* Step through all entries in this region | * Step through all entries in this region | ||||
*/ | */ | ||||
while (entry->start < end) { | while (entry->start < end) { | ||||
vm_map_entry_t next; | vm_map_entry_t next; | ||||
/* | /* | ||||
* Wait for wiring or unwiring of an entry to complete. | * Wait for wiring or unwiring of an entry to complete. | ||||
* Also wait for any system wirings to disappear on | * Also wait for any system wirings to disappear on | ||||
* user maps. | * user maps. | ||||
*/ | */ | ||||
if ((entry->eflags & MAP_ENTRY_IN_TRANSITION) != 0 || | if ((entry->eflags & MAP_ENTRY_IN_TRANSITION) != 0 || | ||||
(vm_map_pmap(map) != kernel_pmap && | (vm_map_pmap(map) != kernel_pmap && | ||||
vm_map_entry_system_wired_count(entry) != 0)) { | vm_map_entry_system_wired_count(entry) != 0)) { | ||||
unsigned int last_timestamp; | unsigned int last_timestamp; | ||||
vm_offset_t saved_start; | vm_offset_t saved_start; | ||||
vm_map_entry_t tmp_entry; | |||||
saved_start = entry->start; | saved_start = entry->start; | ||||
entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP; | entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP; | ||||
last_timestamp = map->timestamp; | last_timestamp = map->timestamp; | ||||
(void) vm_map_unlock_and_wait(map, 0); | (void) vm_map_unlock_and_wait(map, 0); | ||||
vm_map_lock(map); | vm_map_lock(map); | ||||
if (last_timestamp + 1 != map->timestamp) { | if (last_timestamp + 1 == map->timestamp) | ||||
continue; | |||||
/* | /* | ||||
* Look again for the entry because the map was | * Look again for the entry because the map was | ||||
* modified while it was unlocked. | * modified while it was unlocked. Specifically, the | ||||
* Specifically, the entry may have been | * entry may have been clipped, merged, or deleted. | ||||
* clipped, merged, or deleted. | |||||
*/ | */ | ||||
if (!vm_map_lookup_entry(map, saved_start, | if (vm_map_lookup_entry_ge(map, saved_start, &entry)) | ||||
&tmp_entry)) | vm_map_clip_start(map, entry, saved_start); | ||||
entry = tmp_entry->next; | |||||
else { | |||||
entry = tmp_entry; | |||||
vm_map_clip_start(map, entry, | |||||
saved_start); | |||||
} | |||||
} | |||||
continue; | continue; | ||||
} | } | ||||
vm_map_clip_end(map, entry, end); | vm_map_clip_end(map, entry, end); | ||||
next = entry->next; | next = entry->next; | ||||
/* | /* | ||||
* Unwire before removing addresses from the pmap; otherwise, | * Unwire before removing addresses from the pmap; otherwise, | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* The map must be locked. A read lock is sufficient. | * The map must be locked. A read lock is sufficient. | ||||
*/ | */ | ||||
boolean_t | boolean_t | ||||
vm_map_check_protection(vm_map_t map, vm_offset_t start, vm_offset_t end, | vm_map_check_protection(vm_map_t map, vm_offset_t start, vm_offset_t end, | ||||
vm_prot_t protection) | vm_prot_t protection) | ||||
{ | { | ||||
vm_map_entry_t entry; | vm_map_entry_t entry; | ||||
vm_map_entry_t tmp_entry; | |||||
if (!vm_map_lookup_entry(map, start, &tmp_entry)) | if (!vm_map_lookup_entry(map, start, &entry)) | ||||
return (FALSE); | return (FALSE); | ||||
entry = tmp_entry; | |||||
while (start < end) { | while (start < end) { | ||||
/* | /* | ||||
* No holes allowed! | * No holes allowed! | ||||
*/ | */ | ||||
if (start < entry->start) | if (start < entry->start) | ||||
return (FALSE); | return (FALSE); | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 419 Lines • ▼ Show 20 Lines | |||||
SYSCTL_INT(_security_bsd, OID_AUTO, stack_guard_page, CTLFLAG_RWTUN, | SYSCTL_INT(_security_bsd, OID_AUTO, stack_guard_page, CTLFLAG_RWTUN, | ||||
&stack_guard_page, 0, | &stack_guard_page, 0, | ||||
"Specifies the number of guard pages for a stack that grows"); | "Specifies the number of guard pages for a stack that grows"); | ||||
static int | static int | ||||
vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, | vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, | ||||
vm_size_t growsize, vm_prot_t prot, vm_prot_t max, int cow) | vm_size_t growsize, vm_prot_t prot, vm_prot_t max, int cow) | ||||
{ | { | ||||
vm_map_entry_t new_entry, prev_entry; | vm_map_entry_t new_entry; | ||||
vm_offset_t bot, gap_bot, gap_top, top; | vm_offset_t bot, gap_bot, gap_top, top; | ||||
vm_size_t init_ssize, sgp; | vm_size_t init_ssize, sgp; | ||||
int orient, rv; | int orient, rv; | ||||
/* | /* | ||||
* The stack orientation is piggybacked with the cow argument. | * The stack orientation is piggybacked with the cow argument. | ||||
* Extract it into orient and mask the cow argument so that we | * Extract it into orient and mask the cow argument so that we | ||||
* don't pass it around further. | * don't pass it around further. | ||||
Show All 11 Lines | vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize, | ||||
if (sgp >= max_ssize) | if (sgp >= max_ssize) | ||||
return (KERN_INVALID_ARGUMENT); | return (KERN_INVALID_ARGUMENT); | ||||
init_ssize = growsize; | init_ssize = growsize; | ||||
if (max_ssize < init_ssize + sgp) | if (max_ssize < init_ssize + sgp) | ||||
init_ssize = max_ssize - sgp; | init_ssize = max_ssize - sgp; | ||||
/* If addr is already mapped, no go */ | /* If addr is already mapped, no go */ | ||||
if (vm_map_lookup_entry(map, addrbos, &prev_entry)) | if (vm_map_lookup_entry_ge(map, addrbos, &new_entry)) | ||||
return (KERN_NO_SPACE); | return (KERN_NO_SPACE); | ||||
/* | /* | ||||
* If we can't accommodate max_ssize in the current mapping, no go. | * If we can't accommodate max_ssize in the current mapping, no go. | ||||
*/ | */ | ||||
if (prev_entry->next->start < addrbos + max_ssize) | if (new_entry->start < addrbos + max_ssize) | ||||
return (KERN_NO_SPACE); | return (KERN_NO_SPACE); | ||||
/* | /* | ||||
* We initially map a stack of only init_ssize. We will grow as | * We initially map a stack of only init_ssize. We will grow as | ||||
* needed later. Depending on the orientation of the stack (i.e. | * needed later. Depending on the orientation of the stack (i.e. | ||||
* the grow direction) we either map at the top of the range, the | * the grow direction) we either map at the top of the range, the | ||||
* bottom of the range or in the middle. | * bottom of the range or in the middle. | ||||
* | * | ||||
Show All 10 Lines | if (orient == MAP_STACK_GROWS_DOWN) { | ||||
bot = addrbos; | bot = addrbos; | ||||
top = bot + init_ssize; | top = bot + init_ssize; | ||||
gap_bot = top; | gap_bot = top; | ||||
gap_top = addrbos + max_ssize; | gap_top = addrbos + max_ssize; | ||||
} | } | ||||
rv = vm_map_insert(map, NULL, 0, bot, top, prot, max, cow); | rv = vm_map_insert(map, NULL, 0, bot, top, prot, max, cow); | ||||
if (rv != KERN_SUCCESS) | if (rv != KERN_SUCCESS) | ||||
return (rv); | return (rv); | ||||
new_entry = prev_entry->next; | |||||
KASSERT(new_entry->end == top || new_entry->start == bot, | KASSERT(new_entry->end == top || new_entry->start == bot, | ||||
("Bad entry start/end for new stack entry")); | ("Bad entry start/end for new stack entry")); | ||||
KASSERT((orient & MAP_STACK_GROWS_DOWN) == 0 || | KASSERT((orient & MAP_STACK_GROWS_DOWN) == 0 || | ||||
(new_entry->eflags & MAP_ENTRY_GROWS_DOWN) != 0, | (new_entry->eflags & MAP_ENTRY_GROWS_DOWN) != 0, | ||||
("new entry lacks MAP_ENTRY_GROWS_DOWN")); | ("new entry lacks MAP_ENTRY_GROWS_DOWN")); | ||||
KASSERT((orient & MAP_STACK_GROWS_UP) == 0 || | KASSERT((orient & MAP_STACK_GROWS_UP) == 0 || | ||||
(new_entry->eflags & MAP_ENTRY_GROWS_UP) != 0, | (new_entry->eflags & MAP_ENTRY_GROWS_UP) != 0, | ||||
("new entry lacks MAP_ENTRY_GROWS_UP")); | ("new entry lacks MAP_ENTRY_GROWS_UP")); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | #endif | ||||
MPASS(!map->system_map); | MPASS(!map->system_map); | ||||
guard = stack_guard_page * PAGE_SIZE; | guard = stack_guard_page * PAGE_SIZE; | ||||
lmemlim = lim_cur(curthread, RLIMIT_MEMLOCK); | lmemlim = lim_cur(curthread, RLIMIT_MEMLOCK); | ||||
stacklim = lim_cur(curthread, RLIMIT_STACK); | stacklim = lim_cur(curthread, RLIMIT_STACK); | ||||
vmemlim = lim_cur(curthread, RLIMIT_VMEM); | vmemlim = lim_cur(curthread, RLIMIT_VMEM); | ||||
retry: | retry: | ||||
/* If addr is not in a hole for a stack grow area, no need to grow. */ | /* If addr is not in a hole for a stack grow area, no need to grow. */ | ||||
if (gap_entry == NULL && !vm_map_lookup_entry(map, addr, &gap_entry)) | if (gap_entry == NULL && | ||||
!vm_map_lookup_helper(map, addr, true, &gap_entry, &stack_entry)) | |||||
return (KERN_FAILURE); | return (KERN_FAILURE); | ||||
if ((gap_entry->eflags & MAP_ENTRY_GUARD) == 0) | if ((gap_entry->eflags & MAP_ENTRY_GUARD) == 0) | ||||
return (KERN_SUCCESS); | return (KERN_SUCCESS); | ||||
if ((gap_entry->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { | if ((gap_entry->eflags & MAP_ENTRY_STACK_GAP_DN) != 0) { | ||||
stack_entry = gap_entry->next; | |||||
if ((stack_entry->eflags & MAP_ENTRY_GROWS_DOWN) == 0 || | if ((stack_entry->eflags & MAP_ENTRY_GROWS_DOWN) == 0 || | ||||
stack_entry->start != gap_entry->end) | stack_entry->start != gap_entry->end) | ||||
return (KERN_FAILURE); | return (KERN_FAILURE); | ||||
grow_amount = round_page(stack_entry->start - addr); | grow_amount = round_page(stack_entry->start - addr); | ||||
grow_down = true; | grow_down = true; | ||||
} else if ((gap_entry->eflags & MAP_ENTRY_STACK_GAP_UP) != 0) { | } else if ((gap_entry->eflags & MAP_ENTRY_STACK_GAP_UP) != 0) { | ||||
stack_entry = gap_entry->prev; | |||||
if ((stack_entry->eflags & MAP_ENTRY_GROWS_UP) == 0 || | if ((stack_entry->eflags & MAP_ENTRY_GROWS_UP) == 0 || | ||||
stack_entry->end != gap_entry->start) | stack_entry->end != gap_entry->start) | ||||
return (KERN_FAILURE); | return (KERN_FAILURE); | ||||
grow_amount = round_page(addr + 1 - stack_entry->end); | grow_amount = round_page(addr + 1 - stack_entry->end); | ||||
grow_down = false; | grow_down = false; | ||||
} else { | } else { | ||||
return (KERN_FAILURE); | return (KERN_FAILURE); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 650 Lines • Show Last 20 Lines |
Should this comment be preserved?