Index: sys/security/mac/mac_process.c =================================================================== --- sys/security/mac/mac_process.c +++ sys/security/mac/mac_process.c @@ -252,7 +252,7 @@ mac_proc_vm_revoke_recurse(struct thread *td, struct ucred *cred, struct vm_map *map) { - vm_map_entry_t vme; + vm_map_entry_t prev, vme; int result; vm_prot_t revokeperms; vm_object_t backing_object, object; @@ -264,7 +264,8 @@ return; vm_map_lock(map); - for (vme = map->header.next; vme != &map->header; vme = vme->next) { + for (prev = &map->header; + (vme = prev->next) != &map->header; prev = vme) { if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) { mac_proc_vm_revoke_recurse(td, cred, vme->object.sub_map); @@ -363,7 +364,7 @@ } pmap_protect(map->pmap, vme->start, vme->end, vme->protection & ~revokeperms); - vm_map_simplify_entry(map, vme); + vm_map_merge_entries(map, prev, vme); } } vm_map_unlock(map); Index: sys/vm/vm_map.h =================================================================== --- sys/vm/vm_map.h +++ sys/vm/vm_map.h @@ -418,7 +418,8 @@ boolean_t vm_map_lookup_entry (vm_map_t, vm_offset_t, vm_map_entry_t *); int vm_map_protect (vm_map_t, vm_offset_t, vm_offset_t, vm_prot_t, boolean_t); int vm_map_remove (vm_map_t, vm_offset_t, vm_offset_t); -void vm_map_simplify_entry(vm_map_t map, vm_map_entry_t entry); +void vm_map_merge_entries(vm_map_t map, vm_map_entry_t prev, + vm_map_entry_t entry); void vm_map_startup (void); int vm_map_submap (vm_map_t, vm_offset_t, vm_offset_t, vm_map_t); int vm_map_sync(vm_map_t, vm_offset_t, vm_offset_t, boolean_t, boolean_t); Index: sys/vm/vm_map.c =================================================================== --- sys/vm/vm_map.c +++ sys/vm/vm_map.c @@ -1546,7 +1546,7 @@ map->size += end - prev_entry->end; vm_map_entry_resize(map, prev_entry, end - prev_entry->end); - vm_map_simplify_entry(map, prev_entry); + vm_map_merge_entries(map, prev_entry, prev_entry->next); return (KERN_SUCCESS); } @@ -1606,7 +1606,8 @@ * with the previous entry when object is NULL. Here, we handle the * other cases, which are less common. */ - vm_map_simplify_entry(map, new_entry); + vm_map_merge_entries(map, prev_entry, new_entry); + vm_map_merge_entries(map, new_entry, new_entry->next); if ((cow & (MAP_PREFAULT | MAP_PREFAULT_PARTIAL)) != 0) { vm_map_pmap_enter(map, start, prot, object, OFF_TO_IDX(offset), @@ -2075,6 +2076,24 @@ } /* + * vm_map_merge_entries: + * + * Compare the given map entry to its successor, and merge it into its + * successor if possible. Return the successor. + */ +void +vm_map_merge_entries(vm_map_t map, vm_map_entry_t prev, vm_map_entry_t entry) +{ + + if ((entry->eflags & MAP_ENTRY_NOMERGE_MASK) != 0) + return; + if (vm_map_mergeable_neighbors(prev, entry)) { + vm_map_entry_unlink(map, prev, UNLINK_MERGE_NEXT); + vm_map_merged_neighbor_dispose(map, prev); + } +} + +/* * vm_map_simplify_entry: * * Simplify the given map entry by merging with either neighbor. This @@ -2086,7 +2105,7 @@ * possibly extended). When merging, this routine may delete one or * both neighbors. */ -void +static void vm_map_simplify_entry(vm_map_t map, vm_map_entry_t entry) { vm_map_entry_t next, prev; @@ -2176,7 +2195,7 @@ * This routine is called only when it is known that * the entry must be split. */ -static void +static vm_map_entry_t _vm_map_clip_start(vm_map_t map, vm_map_entry_t entry, vm_offset_t start) { vm_map_entry_t new_entry; @@ -2218,6 +2237,7 @@ * left the same. */ } + return (new_entry); } /* @@ -2447,7 +2467,7 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end, vm_prot_t new_prot, boolean_t set_max) { - vm_map_entry_t current, entry, in_tran; + vm_map_entry_t current, entry, in_tran, prev; vm_object_t obj; struct ucred *cred; vm_prot_t old_prot; @@ -2470,8 +2490,8 @@ VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry(map, start, &entry)) - entry = entry->next; + vm_map_lookup_entry(map, start-1, &prev); + entry = (prev->end > start) ? prev : prev->next; /* * Make a first pass to check for protection violations. @@ -2513,7 +2533,8 @@ * some may now be mergeable. */ rv = KERN_SUCCESS; - vm_map_clip_start(map, entry, start); + if (prev == entry) + prev = _vm_map_clip_start(map, entry, start); for (current = entry; current->start < end; current = current->next) { vm_map_clip_end(map, current, end); @@ -2572,7 +2593,8 @@ * [Note that clipping is not necessary the second time.] */ for (current = entry; current->start < end; - vm_map_simplify_entry(map, current), current = current->next) { + vm_map_merge_entries(map, prev, current), + prev = current, current = prev->next) { if (rv != KERN_SUCCESS || (current->eflags & MAP_ENTRY_GUARD) != 0) continue; @@ -2610,6 +2632,7 @@ #undef MASK } } + vm_map_merge_entries(map, prev, current); vm_map_unlock(map); return (rv); } @@ -2629,7 +2652,7 @@ vm_offset_t end, int behav) { - vm_map_entry_t current, entry; + vm_map_entry_t current, entry, prev; bool modify_map; /* @@ -2668,12 +2691,8 @@ */ 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); - } else { - entry = entry->next; - } + vm_map_lookup_entry(map, start-1, &prev); + entry = (prev->end > start) ? prev : prev->next; if (modify_map) { /* @@ -2682,8 +2701,10 @@ * We clip the vm_map_entry so that behavioral changes are * limited to the specified address range. */ + if (prev == entry) + prev = _vm_map_clip_start(map, entry, start); for (current = entry; current->start < end; - current = current->next) { + prev = current, current = prev->next) { if (current->eflags & MAP_ENTRY_IS_SUB_MAP) continue; @@ -2714,8 +2735,9 @@ default: break; } - vm_map_simplify_entry(map, current); + vm_map_merge_entries(map, prev, current); } + vm_map_merge_entries(map, prev, current); vm_map_unlock(map); } else { vm_pindex_t pstart, pend; @@ -2803,8 +2825,7 @@ vm_map_inherit(vm_map_t map, vm_offset_t start, vm_offset_t end, vm_inherit_t new_inheritance) { - vm_map_entry_t entry; - vm_map_entry_t temp_entry; + vm_map_entry_t entry, prev; switch (new_inheritance) { case VM_INHERIT_NONE: @@ -2819,19 +2840,20 @@ return (KERN_SUCCESS); vm_map_lock(map); VM_MAP_RANGE_CHECK(map, start, end); - if (vm_map_lookup_entry(map, start, &temp_entry)) { - entry = temp_entry; - vm_map_clip_start(map, entry, start); - } else - entry = temp_entry->next; + vm_map_lookup_entry(map, start-1, &prev); + if (start < prev->end) + prev = _vm_map_clip_start(map, prev, start); + entry = prev->next; while (entry->start < end) { vm_map_clip_end(map, entry, end); if ((entry->eflags & MAP_ENTRY_GUARD) == 0 || new_inheritance != VM_INHERIT_ZERO) entry->inheritance = new_inheritance; - vm_map_simplify_entry(map, entry); - entry = entry->next; + vm_map_merge_entries(map, prev, entry); + prev = entry; + entry = prev->next; } + vm_map_merge_entries(map, prev, entry); vm_map_unlock(map); return (KERN_SUCCESS); }