summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2013-04-18 20:48:30 +0200
committerRichard Braun <rbraun@sceen.net>2013-04-18 20:48:30 +0200
commitd89587df0f7ff1671c26c49418de5de5613d2552 (patch)
treef2edde714cc937890561178de64d0029bc9ec4b5
parent833ec80f937dd7080291907031f9984e3195a5f1 (diff)
vm/vm_map: fix map entry clipping
-rw-r--r--vm/vm_map.c36
1 files changed, 24 insertions, 12 deletions
diff --git a/vm/vm_map.c b/vm/vm_map.c
index 70fcf874..e81d707e 100644
--- a/vm/vm_map.c
+++ b/vm/vm_map.c
@@ -573,6 +573,8 @@ static void
vm_map_link(struct vm_map *map, struct vm_map_entry *entry,
struct vm_map_entry *prev, struct vm_map_entry *next)
{
+ assert(entry->start < entry->end);
+
if ((prev == NULL) && (next == NULL))
list_insert_tail(&map->entry_list, &entry->list_node);
else if (prev == NULL)
@@ -587,6 +589,8 @@ vm_map_link(struct vm_map *map, struct vm_map_entry *entry,
static void
vm_map_unlink(struct vm_map *map, struct vm_map_entry *entry)
{
+ assert(entry->start < entry->end);
+
list_remove(&entry->list_node);
rbtree_remove(&map->entry_tree, &entry->tree_node);
map->nr_entries--;
@@ -817,31 +821,31 @@ static void
vm_map_split_entries(struct vm_map_entry *prev, struct vm_map_entry *next,
unsigned long split_addr)
{
- unsigned long diff;
-
- assert(prev->start < split_addr);
- assert(split_addr < prev->end);
+ unsigned long delta;
- diff = split_addr - prev->start;
+ delta = split_addr - prev->start;
prev->end = split_addr;
next->start = split_addr;
if (next->object != NULL)
- next->offset += diff;
+ next->offset += delta;
}
static void
vm_map_clip_start(struct vm_map *map, struct vm_map_entry *entry,
unsigned long start)
{
- struct vm_map_entry *new_entry;
+ struct vm_map_entry *new_entry, *next;
- if (entry->start >= start)
+ if ((start <= entry->start) || (start >= entry->end))
return;
+ next = vm_map_next(map, entry);
+ vm_map_unlink(map, entry);
new_entry = vm_map_entry_create(map);
*new_entry = *entry;
vm_map_split_entries(new_entry, entry, start);
+ vm_map_link(map, entry, NULL, next);
vm_map_link(map, new_entry, NULL, entry);
}
@@ -849,14 +853,17 @@ static void
vm_map_clip_end(struct vm_map *map, struct vm_map_entry *entry,
unsigned long end)
{
- struct vm_map_entry *new_entry;
+ struct vm_map_entry *new_entry, *prev;
- if (entry->end <= end)
+ if ((end <= entry->start) || (end >= entry->end))
return;
+ prev = vm_map_prev(map, entry);
+ vm_map_unlink(map, entry);
new_entry = vm_map_entry_create(map);
*new_entry = *entry;
vm_map_split_entries(entry, new_entry, end);
+ vm_map_link(map, entry, prev, NULL);
vm_map_link(map, new_entry, entry, NULL);
}
@@ -879,13 +886,18 @@ vm_map_remove(struct vm_map *map, unsigned long start, unsigned long end)
vm_map_clip_start(map, entry, start);
- while (!list_end(&map->entry_list, &entry->list_node)
- && (entry->start < end)) {
+ while (entry->start < end) {
vm_map_clip_end(map, entry, end);
map->size -= entry->end - entry->start;
node = list_next(&entry->list_node);
vm_map_unlink(map, entry);
+
+ /* TODO Defer destruction to shorten critical section */
vm_map_entry_destroy(entry, map);
+
+ if (list_end(&map->entry_list, node))
+ break;
+
entry = list_entry(node, struct vm_map_entry, list_node);
}