Changeset View
Changeset View
Standalone View
Standalone View
head/sys/vm/vm_map.c
Show First 20 Lines • Show All 2,381 Lines • ▼ Show 20 Lines | #define vm_map_clip_start(map, entry, startaddr) \ | ||||
if (startaddr > entry->start) \ | if (startaddr > entry->start) \ | ||||
_vm_map_clip_start(map, entry, startaddr); \ | _vm_map_clip_start(map, entry, startaddr); \ | ||||
} | } | ||||
/* | /* | ||||
* This routine is called only when it is known that | * This routine is called only when it is known that | ||||
* the entry must be split. | * the entry must be split. | ||||
*/ | */ | ||||
static void | static inline void | ||||
_vm_map_clip_start(vm_map_t map, vm_map_entry_t entry, vm_offset_t start) | _vm_map_clip_start(vm_map_t map, vm_map_entry_t entry, vm_offset_t start) | ||||
{ | { | ||||
vm_map_entry_t new_entry; | vm_map_entry_t new_entry; | ||||
VM_MAP_ASSERT_LOCKED(map); | VM_MAP_ASSERT_LOCKED(map); | ||||
KASSERT(entry->end > start && entry->start < start, | KASSERT(entry->end > start && entry->start < start, | ||||
("_vm_map_clip_start: invalid clip of entry %p", entry)); | ("_vm_map_clip_start: invalid clip of entry %p", entry)); | ||||
new_entry = vm_map_entry_clone(map, entry); | new_entry = vm_map_entry_clone(map, entry); | ||||
/* | /* | ||||
* Split off the front portion. Insert the new entry BEFORE this one, | * Split off the front portion. Insert the new entry BEFORE this one, | ||||
* so that this entry has the specified starting address. | * so that this entry has the specified starting address. | ||||
*/ | */ | ||||
new_entry->end = start; | new_entry->end = start; | ||||
vm_map_entry_link(map, new_entry); | vm_map_entry_link(map, new_entry); | ||||
} | } | ||||
/* | /* | ||||
* vm_map_lookup_clip_start: | |||||
* | |||||
* Find the entry at or just after 'start', and clip it if 'start' is in | |||||
* the interior of the entry. Return entry after 'start', and in | |||||
* prev_entry set the entry before 'start'. | |||||
*/ | |||||
static inline vm_map_entry_t | |||||
vm_map_lookup_clip_start(vm_map_t map, vm_offset_t start, | |||||
vm_map_entry_t *prev_entry) | |||||
{ | |||||
vm_map_entry_t entry; | |||||
if (vm_map_lookup_entry(map, start, prev_entry)) { | |||||
entry = *prev_entry; | |||||
vm_map_clip_start(map, entry, start); | |||||
*prev_entry = vm_map_entry_pred(entry); | |||||
} else | |||||
entry = vm_map_entry_succ(*prev_entry); | |||||
return (entry); | |||||
} | |||||
/* | |||||
* vm_map_clip_end: [ internal use only ] | * vm_map_clip_end: [ internal use only ] | ||||
* | * | ||||
* Asserts that the given entry ends at or before | * Asserts that the given entry ends at or before | ||||
* the specified address; if necessary, | * the specified address; if necessary, | ||||
* it splits the entry into two. | * it splits the entry into two. | ||||
*/ | */ | ||||
#define vm_map_clip_end(map, entry, endaddr) \ | #define vm_map_clip_end(map, entry, endaddr) \ | ||||
{ \ | { \ | ||||
if ((endaddr) < (entry->end)) \ | if ((endaddr) < (entry->end)) \ | ||||
_vm_map_clip_end((map), (entry), (endaddr)); \ | _vm_map_clip_end((map), (entry), (endaddr)); \ | ||||
} | } | ||||
/* | /* | ||||
* This routine is called only when it is known that | * This routine is called only when it is known that | ||||
* the entry must be split. | * the entry must be split. | ||||
*/ | */ | ||||
static void | static inline void | ||||
_vm_map_clip_end(vm_map_t map, vm_map_entry_t entry, vm_offset_t end) | _vm_map_clip_end(vm_map_t map, vm_map_entry_t entry, vm_offset_t end) | ||||
{ | { | ||||
vm_map_entry_t new_entry; | vm_map_entry_t new_entry; | ||||
VM_MAP_ASSERT_LOCKED(map); | VM_MAP_ASSERT_LOCKED(map); | ||||
KASSERT(entry->start < end && entry->end > end, | KASSERT(entry->start < end && entry->end > end, | ||||
("_vm_map_clip_end: invalid clip of entry %p", entry)); | ("_vm_map_clip_end: invalid clip of entry %p", entry)); | ||||
▲ Show 20 Lines • Show All 395 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 (modify_map) | |||||
vm_map_clip_start(map, entry, start); | |||||
prev_entry = vm_map_entry_pred(entry); | |||||
} else { | |||||
prev_entry = entry; | |||||
entry = vm_map_entry_succ(entry); | |||||
} | |||||
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. | ||||
*/ | */ | ||||
for (; entry->start < end; | for (entry = vm_map_lookup_clip_start(map, start, &prev_entry); | ||||
entry->start < end; | |||||
prev_entry = entry, entry = vm_map_entry_succ(entry)) { | prev_entry = entry, entry = vm_map_entry_succ(entry)) { | ||||
if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) != 0) | if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) != 0) | ||||
continue; | continue; | ||||
vm_map_clip_end(map, entry, end); | vm_map_clip_end(map, entry, end); | ||||
switch (behav) { | switch (behav) { | ||||
case MADV_NORMAL: | case MADV_NORMAL: | ||||
vm_map_entry_set_behavior(entry, | vm_map_entry_set_behavior(entry, | ||||
Show All 31 Lines | if (modify_map) { | ||||
/* | /* | ||||
* madvise behaviors that are implemented in the underlying | * madvise behaviors that are implemented in the underlying | ||||
* vm_object. | * vm_object. | ||||
* | * | ||||
* Since we don't clip the vm_map_entry, we have to clip | * Since we don't clip the vm_map_entry, we have to clip | ||||
* the vm_object pindex and count. | * the vm_object pindex and count. | ||||
*/ | */ | ||||
if (!vm_map_lookup_entry(map, start, &entry)) | |||||
entry = vm_map_entry_succ(entry); | |||||
for (; entry->start < end; | for (; entry->start < end; | ||||
entry = vm_map_entry_succ(entry)) { | entry = vm_map_entry_succ(entry)) { | ||||
vm_offset_t useEnd, useStart; | vm_offset_t useEnd, useStart; | ||||
if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) != 0) | if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) != 0) | ||||
continue; | continue; | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | 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, &prev_entry)) { | for (entry = vm_map_lookup_clip_start(map, start, &prev_entry); | ||||
entry = prev_entry; | entry->start < end; | ||||
vm_map_clip_start(map, entry, start); | |||||
prev_entry = vm_map_entry_pred(entry); | |||||
} else | |||||
entry = vm_map_entry_succ(prev_entry); | |||||
for (; entry->start < end; | |||||
prev_entry = entry, entry = vm_map_entry_succ(entry)) { | prev_entry = entry, entry = vm_map_entry_succ(entry)) { | ||||
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_try_merge_entries(map, prev_entry, entry); | vm_map_try_merge_entries(map, prev_entry, entry); | ||||
} | } | ||||
vm_map_try_merge_entries(map, prev_entry, entry); | vm_map_try_merge_entries(map, prev_entry, entry); | ||||
▲ Show 20 Lines • Show All 706 Lines • ▼ Show 20 Lines | |||||
* vm_map_delete: [ internal use only ] | * vm_map_delete: [ internal use only ] | ||||
* | * | ||||
* 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, next_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. | ||||
* Step through all entries in this region. | |||||
*/ | */ | ||||
if (!vm_map_lookup_entry(map, start, &first_entry)) | for (entry = vm_map_lookup_clip_start(map, start, &entry); | ||||
entry = vm_map_entry_succ(first_entry); | entry->start < end; entry = next_entry) { | ||||
else { | |||||
entry = first_entry; | |||||
vm_map_clip_start(map, entry, start); | |||||
} | |||||
/* | /* | ||||
* Step through all entries in this region | |||||
*/ | |||||
while (entry->start < end) { | |||||
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) { | ||||
/* | /* | ||||
* 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, | next_entry = vm_map_lookup_clip_start(map, | ||||
&tmp_entry)) | saved_start, &next_entry); | ||||
entry = vm_map_entry_succ(tmp_entry); | } else | ||||
else { | next_entry = entry; | ||||
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 = vm_map_entry_succ(entry); | |||||
next = vm_map_entry_succ(entry); | |||||
/* | /* | ||||
* Unwire before removing addresses from the pmap; otherwise, | * Unwire before removing addresses from the pmap; otherwise, | ||||
* unwiring will put the entries back in the pmap. | * unwiring will put the entries back in the pmap. | ||||
*/ | */ | ||||
if (entry->wired_count != 0) | if (entry->wired_count != 0) | ||||
vm_map_entry_unwire(map, entry); | vm_map_entry_unwire(map, entry); | ||||
/* | /* | ||||
Show All 10 Lines | for (entry = vm_map_lookup_clip_start(map, start, &entry); | ||||
/* | /* | ||||
* Delete the entry only after removing all pmap | * Delete the entry only after removing all pmap | ||||
* entries pointing to its pages. (Otherwise, its | * entries pointing to its pages. (Otherwise, its | ||||
* page frames may be reallocated, and any modify bits | * page frames may be reallocated, and any modify bits | ||||
* will be set in the wrong object!) | * will be set in the wrong object!) | ||||
*/ | */ | ||||
vm_map_entry_delete(map, entry); | vm_map_entry_delete(map, entry); | ||||
entry = next; | |||||
} | } | ||||
return (KERN_SUCCESS); | return (KERN_SUCCESS); | ||||
} | } | ||||
/* | /* | ||||
* vm_map_remove: | * vm_map_remove: | ||||
* | * | ||||
* Remove the given address range from the target map. | * Remove the given address range from the target map. | ||||
▲ Show 20 Lines • Show All 1,367 Lines • Show Last 20 Lines |