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_try_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_try_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_try_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_try_merge_entries(map, prev_entry, new_entry); + vm_map_try_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,26 @@ } /* + * vm_map_try_merge_entries: + * + * Compare the given map entry to its predecessor, and merge it into its + * predecessor if possible. The entry remains valid, and may be extended. + * The predecessor may be deleted. + * + * The map must be locked. + */ +void +vm_map_try_merge_entries(vm_map_t map, vm_map_entry_t prev, vm_map_entry_t entry) +{ + + if ((entry->eflags & MAP_ENTRY_NOMERGE_MASK) == 0 && + 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 +2107,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 +2197,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 +2239,7 @@ * left the same. */ } + return (new_entry); } /* @@ -2447,7 +2469,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 +2492,11 @@ VM_MAP_RANGE_CHECK(map, start, end); - if (!vm_map_lookup_entry(map, start, &entry)) - entry = entry->next; + if (start == 0) + prev = &map->header; + else + 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 +2538,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 +2598,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_try_merge_entries(map, prev, current), + prev = current, current = prev->next) { if (rv != KERN_SUCCESS || (current->eflags & MAP_ENTRY_GUARD) != 0) continue; @@ -2610,6 +2637,7 @@ #undef MASK } } + vm_map_try_merge_entries(map, prev, current); vm_map_unlock(map); return (rv); } @@ -2629,7 +2657,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 +2696,11 @@ */ 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; - } + if (start == 0) + prev = &map->header; + else + vm_map_lookup_entry(map, start - 1, &prev); + entry = (prev->end > start) ? prev : prev->next; if (modify_map) { /* @@ -2682,8 +2709,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 +2743,9 @@ default: break; } - vm_map_simplify_entry(map, current); + vm_map_try_merge_entries(map, prev, current); } + vm_map_try_merge_entries(map, prev, current); vm_map_unlock(map); } else { vm_pindex_t pstart, pend;