This function attempts to coalesce a VM map entry with its preceeding entry. It wraps vm_object_coalesce. --- vm/vm_map.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++-- vm/vm_map.h | 2 ++ 2 files changed, 77 insertions(+), 2 deletions(-)
diff --git a/vm/vm_map.c b/vm/vm_map.c index 97fc09ce..fc7c4381 100644 --- a/vm/vm_map.c +++ b/vm/vm_map.c @@ -113,8 +113,7 @@ MACRO_END * start or end value.] Note that these clippings may not * always be necessary (as the two resulting entries are then * not changed); however, the clipping is done for convenience. - * No attempt is currently made to "glue back together" two - * abutting entries. + * The entries can later be "glued back together" (coalesced). * * The symmetric (shadow) copy strategy implements virtual copy * by copying VM object references from one map to @@ -4929,6 +4928,80 @@ vm_region_create_proxy (task_t task, vm_address_t address, return ret; } +/* + * Routine: vm_map_coalesce_entry + * Purpose: + * Try to coalesce an entry with the preceeding entry in the map. + * Conditions: + * The map is locked. If coalesced, the entry is destroyed + * by the call. + * Returns: + * Whether the entry was coalesced. + */ +boolean_t +vm_map_coalesce_entry( + vm_map_t map, + vm_map_entry_t entry) +{ + vm_map_entry_t prev = entry->vme_prev; + vm_size_t prev_size; + vm_size_t entry_size; + + /* + * Check the basic conditions for coalescing the two entries. + */ + if ((entry == vm_map_to_entry(map)) || + (prev == vm_map_to_entry(map)) || + (prev->vme_end != entry->vme_start) || + (prev->is_shared || entry->is_shared) || + (prev->is_sub_map || entry->is_sub_map) || + (prev->inheritance != entry->inheritance) || + (prev->protection != entry->protection) || + (prev->max_protection != entry->max_protection) || + (prev->needs_copy != entry->needs_copy) || + (prev->in_transition || entry->in_transition) || + (prev->wired_count != entry->wired_count) || + (prev->projected_on != 0) || + (entry->projected_on != 0)) + return FALSE; + + prev_size = prev->vme_end - prev->vme_start; + entry_size = entry->vme_end - entry->vme_start; + assert(prev->gap_size == 0); + + /* + * See if we can coalesce the two objects. + */ + if (!vm_object_coalesce(prev->object.vm_object, + entry->object.vm_object, + prev->offset, + entry->offset, + prev_size, + entry_size)) + return FALSE; + + /* + * Update the hints. + */ + if (map->hint == entry) + SAVE_HINT(map, prev); + if (map->first_free == entry) + map->first_free = prev; + + /* + * Get rid of the entry without changing any wirings or the pmap, + * and without altering map->size. + */ + prev->vme_end = entry->vme_end; + vm_map_entry_unlink(map, entry); + vm_object_deallocate(entry->object.vm_object); + vm_map_entry_dispose(map, entry); + + return TRUE; +} + + + /* * Routine: vm_map_machine_attribute * Purpose: diff --git a/vm/vm_map.h b/vm/vm_map.h index 3d1c9428..a4949e4e 100644 --- a/vm/vm_map.h +++ b/vm/vm_map.h @@ -442,6 +442,8 @@ extern vm_map_copy_t vm_map_copy_copy(vm_map_copy_t); extern kern_return_t vm_map_copy_discard_cont(vm_map_copyin_args_t, vm_map_copy_t *); +extern boolean_t vm_map_coalesce_entry(vm_map_t, vm_map_entry_t); + /* Add or remove machine- dependent attributes from map regions */ extern kern_return_t vm_map_machine_attribute(vm_map_t, vm_offset_t, vm_size_t, -- 2.41.0