The map-entry clipping functions modify start and end entries of an

entry in the vm_map, making invariants related to the max_free entry
field invalid. Move the clipping work into vm_map_entry_link, so that
linking is okay when the new entry clips a current entry, and the
vm_map doesn't have to be briefly corrupted. Change assertions and
conditions in SPLAY_{LEFT,RIGHT}_STEP since the max_free invariants
can now be trusted in all cases.

Tested by:	pho
Reviewed by:	alc
Differential Revision:	https://reviews.freebsd.org/D22897
This commit is contained in:
dougm 2019-12-31 22:20:54 +00:00
parent 4621ede578
commit a26b60ac01

View File

@ -1028,9 +1028,11 @@ vm_size_max(vm_size_t a, vm_size_t b)
*/ \
y = root->left; \
max_free = root->max_free; \
KASSERT(max_free >= vm_map_entry_max_free_right(root, rlist), \
KASSERT(max_free == vm_size_max( \
vm_map_entry_max_free_left(root, llist), \
vm_map_entry_max_free_right(root, rlist)), \
("%s: max_free invariant fails", __func__)); \
if (y == llist ? max_free > 0 : max_free - 1 < y->max_free) \
if (max_free - 1 < vm_map_entry_max_free_left(root, llist)) \
max_free = vm_map_entry_max_free_right(root, rlist); \
if (y != llist && (test)) { \
/* Rotate right and make y root. */ \
@ -1067,9 +1069,11 @@ vm_size_max(vm_size_t a, vm_size_t b)
*/ \
y = root->right; \
max_free = root->max_free; \
KASSERT(max_free >= vm_map_entry_max_free_left(root, llist), \
KASSERT(max_free == vm_size_max( \
vm_map_entry_max_free_left(root, llist), \
vm_map_entry_max_free_right(root, rlist)), \
("%s: max_free invariant fails", __func__)); \
if (y == rlist ? max_free > 0 : max_free - 1 < y->max_free) \
if (max_free - 1 < vm_map_entry_max_free_right(root, rlist)) \
max_free = vm_map_entry_max_free_left(root, llist); \
if (y != rlist && (test)) { \
/* Rotate left and make y root. */ \
@ -1356,12 +1360,17 @@ vm_map_splay(vm_map_t map, vm_offset_t addr)
/*
* vm_map_entry_{un,}link:
*
* Insert/remove entries from maps.
* Insert/remove entries from maps. On linking, if new entry clips
* existing entry, trim existing entry to avoid overlap, and manage
* offsets. On unlinking, merge disappearing entry with neighbor, if
* called for, and manage offsets. Callers should not modify fields in
* entries already mapped.
*/
static void
vm_map_entry_link(vm_map_t map, vm_map_entry_t entry)
{
vm_map_entry_t header, llist, rlist, root;
vm_size_t max_free_left, max_free_right;
CTR3(KTR_VM,
"vm_map_entry_link: map %p, nentries %d, entry %p", map,
@ -1370,13 +1379,48 @@ vm_map_entry_link(vm_map_t map, vm_map_entry_t entry)
map->nentries++;
header = &map->header;
root = vm_map_splay_split(map, entry->start, 0, &llist, &rlist);
KASSERT(root == NULL,
("vm_map_entry_link: link object already mapped"));
root = entry;
root->max_free = vm_size_max(
vm_map_splay_merge_pred(header, root, llist),
vm_map_splay_merge_succ(header, root, rlist));
map->root = root;
if (root == NULL) {
/*
* The new entry does not overlap any existing entry in the
* map, so it becomes the new root of the map tree.
*/
max_free_left = vm_map_splay_merge_pred(header, entry, llist);
max_free_right = vm_map_splay_merge_succ(header, entry, rlist);
} else if (entry->start == root->start) {
/*
* The new entry is a clone of root, with only the end field
* changed. The root entry will be shrunk to abut the new
* entry, and will be the right child of the new root entry in
* the modified map.
*/
KASSERT(entry->end < root->end,
("%s: clip_start not within entry", __func__));
vm_map_splay_findprev(root, &llist);
root->offset += entry->end - root->start;
root->start = entry->end;
max_free_left = vm_map_splay_merge_pred(header, entry, llist);
max_free_right = root->max_free = vm_size_max(
vm_map_splay_merge_pred(entry, root, entry),
vm_map_splay_merge_right(header, root, rlist));
} else {
/*
* The new entry is a clone of root, with only the start field
* changed. The root entry will be shrunk to abut the new
* entry, and will be the left child of the new root entry in
* the modified map.
*/
KASSERT(entry->end == root->end,
("%s: clip_start not within entry", __func__));
vm_map_splay_findnext(root, &rlist);
entry->offset += entry->start - root->start;
root->end = entry->start;
max_free_left = root->max_free = vm_size_max(
vm_map_splay_merge_left(header, root, llist),
vm_map_splay_merge_succ(entry, root, entry));
max_free_right = vm_map_splay_merge_succ(header, entry, rlist);
}
entry->max_free = vm_size_max(max_free_left, max_free_right);
map->root = entry;
VM_MAP_ASSERT_CONSISTENT(map);
}
@ -2359,8 +2403,6 @@ _vm_map_clip_start(vm_map_t map, vm_map_entry_t entry, vm_offset_t start)
* so that this entry has the specified starting address.
*/
new_entry->end = start;
entry->offset += (start - entry->start);
entry->start = start;
vm_map_entry_link(map, new_entry);
}
@ -2396,8 +2438,7 @@ _vm_map_clip_end(vm_map_t map, vm_map_entry_t entry, vm_offset_t end)
* Split off the back portion. Insert the new entry AFTER this one,
* so that this entry has the specified ending address.
*/
new_entry->start = entry->end = end;
new_entry->offset += (end - entry->start);
new_entry->start = end;
vm_map_entry_link(map, new_entry);
}