diff options
Diffstat (limited to 'vm/vm_object.c')
-rw-r--r-- | vm/vm_object.c | 145 |
1 files changed, 104 insertions, 41 deletions
diff --git a/vm/vm_object.c b/vm/vm_object.c index 0dc3d540..c238cce4 100644 --- a/vm/vm_object.c +++ b/vm/vm_object.c @@ -44,6 +44,7 @@ #include <ipc/ipc_space.h> #include <kern/assert.h> #include <kern/debug.h> +#include <kern/mach.server.h> #include <kern/lock.h> #include <kern/queue.h> #include <kern/xpr.h> @@ -182,7 +183,7 @@ vm_object_t kernel_object = &kernel_object_store; */ queue_head_t vm_object_cached_list; -decl_simple_lock_data(,vm_object_cached_lock_data) +def_simple_lock_data(static,vm_object_cached_lock_data) #define vm_object_cache_lock() \ simple_lock(&vm_object_cached_lock_data) @@ -198,7 +199,7 @@ decl_simple_lock_data(,vm_object_cached_lock_data) */ int vm_object_cached_pages; -decl_simple_lock_data(,vm_object_cached_pages_lock_data) +def_simple_lock_data(static,vm_object_cached_pages_lock_data) /* * Virtual memory objects are initialized from @@ -226,7 +227,7 @@ static void _vm_object_setup( object->size = size; } -vm_object_t _vm_object_allocate( +static vm_object_t _vm_object_allocate( vm_size_t size) { vm_object_t object; @@ -725,7 +726,7 @@ void memory_object_release( * In/out conditions: * The object is locked on entry and exit. */ -void vm_object_abort_activity( +static void vm_object_abort_activity( vm_object_t object) { vm_page_t p; @@ -1288,7 +1289,7 @@ boolean_t vm_object_copy_temporary( * If the return value indicates an error, this parameter * is not valid. */ -kern_return_t vm_object_copy_call( +static kern_return_t vm_object_copy_call( vm_object_t src_object, vm_offset_t src_offset, vm_size_t size, @@ -2686,14 +2687,16 @@ void vm_object_page_remove( /* * Routine: vm_object_coalesce - * Function: Coalesces two objects backing up adjoining - * regions of memory into a single object. - * - * returns TRUE if objects were combined. - * - * NOTE: Only works at the moment if the second object is NULL - - * if it's not, which object do we lock first? - * + * Purpose: + * Tries to coalesce two objects backing up adjoining + * regions of memory into a single object. + * + * NOTE: Only works at the moment if one of the objects + * is NULL or if the objects are the same - otherwise, + * which object do we lock first? + * Returns: + * TRUE if objects have been coalesced. + * FALSE the objects could not be coalesced. * Parameters: * prev_object First object to coalesce * prev_offset Offset into prev_object @@ -2703,8 +2706,14 @@ void vm_object_page_remove( * prev_size Size of reference to prev_object * next_size Size of reference to next_object * + * new_object Resulting colesced object + * new_offset Offset into the resulting object * Conditions: - * The object must *not* be locked. + * The objects must *not* be locked. + * + * If the objects are coalesced successfully, the caller's + * references for both objects are consumed, and the caller + * gains a reference for the new object. */ boolean_t vm_object_coalesce( @@ -2713,28 +2722,60 @@ boolean_t vm_object_coalesce( vm_offset_t prev_offset, vm_offset_t next_offset, vm_size_t prev_size, - vm_size_t next_size) + vm_size_t next_size, + vm_object_t *new_object, /* OUT */ + vm_offset_t *new_offset) /* OUT */ { + vm_object_t object; vm_size_t newsize; - if (next_object != VM_OBJECT_NULL) { + if (prev_object == next_object) { + /* + * If neither object actually exists, + * the offsets don't matter. + */ + if (prev_object == VM_OBJECT_NULL) { + *new_object = VM_OBJECT_NULL; + *new_offset = 0; + return TRUE; + } + + if (prev_offset + prev_size == next_offset) { + *new_object = prev_object; + *new_offset = prev_offset; + /* + * Deallocate one of the two references. + */ + vm_object_deallocate(prev_object); + return TRUE; + } + return FALSE; } - if (prev_object == VM_OBJECT_NULL) { - return TRUE; + if (next_object != VM_OBJECT_NULL) { + /* + * Don't know how to merge two different + * objects yet. + */ + if (prev_object != VM_OBJECT_NULL) + return FALSE; + + object = next_object; + } else { + object = prev_object; } - vm_object_lock(prev_object); + vm_object_lock(object); /* * Try to collapse the object first */ - vm_object_collapse(prev_object); + vm_object_collapse(object); /* * Can't coalesce if pages not mapped to - * prev_entry may be in use anyway: + * the object may be in use anyway: * . more than one reference * . paged out * . shadows another object @@ -2742,33 +2783,55 @@ boolean_t vm_object_coalesce( * . paging references (pages might be in page-list) */ - if ((prev_object->ref_count > 1) || - prev_object->pager_created || - prev_object->used_for_pageout || - (prev_object->shadow != VM_OBJECT_NULL) || - (prev_object->copy != VM_OBJECT_NULL) || - (prev_object->paging_in_progress != 0)) { - vm_object_unlock(prev_object); + if ((object->ref_count > 1) || + object->pager_created || + object->used_for_pageout || + (object->shadow != VM_OBJECT_NULL) || + (object->copy != VM_OBJECT_NULL) || + (object->paging_in_progress != 0)) { + vm_object_unlock(object); return FALSE; } - /* - * Remove any pages that may still be in the object from - * a previous deallocation. - */ - - vm_object_page_remove(prev_object, + if (object == prev_object) { + /* + * Remove any pages that may still be in + * the object from a previous deallocation. + */ + vm_object_page_remove(object, prev_offset + prev_size, prev_offset + prev_size + next_size); + /* + * Extend the object if necessary. + */ + newsize = prev_offset + prev_size + next_size; + if (newsize > object->size) + object->size = newsize; - /* - * Extend the object if necessary. - */ - newsize = prev_offset + prev_size + next_size; - if (newsize > prev_object->size) - prev_object->size = newsize; + *new_offset = prev_offset; + } else { + /* + * Check if we have enough space in the object + * offset space to insert the new mapping before + * the existing one. + */ + if (next_offset < prev_size) { + vm_object_unlock(object); + return FALSE; + } + /* + * Remove any pages that may still be in + * the object from a previous deallocation. + */ + vm_object_page_remove(object, + next_offset - prev_size, + next_offset); - vm_object_unlock(prev_object); + *new_offset = next_offset - prev_size; + } + + vm_object_unlock(object); + *new_object = object; return TRUE; } |