diff options
author | Richard Braun <rbraun@sceen.net> | 2013-04-18 20:48:30 +0200 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2013-04-18 20:48:30 +0200 |
commit | d89587df0f7ff1671c26c49418de5de5613d2552 (patch) | |
tree | f2edde714cc937890561178de64d0029bc9ec4b5 | |
parent | 833ec80f937dd7080291907031f9984e3195a5f1 (diff) |
vm/vm_map: fix map entry clipping
-rw-r--r-- | vm/vm_map.c | 36 |
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); } |