145748Smckusick /* 245748Smckusick * Copyright (c) 1991 Regents of the University of California. 345748Smckusick * All rights reserved. 445748Smckusick * 545748Smckusick * This code is derived from software contributed to Berkeley by 645748Smckusick * The Mach Operating System project at Carnegie-Mellon University. 745748Smckusick * 8*48493Smckusick * %sccs.include.redist.c% 945748Smckusick * 10*48493Smckusick * @(#)vm_object.c 7.3 (Berkeley) 04/21/91 11*48493Smckusick * 12*48493Smckusick * 13*48493Smckusick * Copyright (c) 1987, 1990 Carnegie-Mellon University. 14*48493Smckusick * All rights reserved. 15*48493Smckusick * 16*48493Smckusick * Authors: Avadis Tevanian, Jr., Michael Wayne Young 17*48493Smckusick * 18*48493Smckusick * Permission to use, copy, modify and distribute this software and 19*48493Smckusick * its documentation is hereby granted, provided that both the copyright 20*48493Smckusick * notice and this permission notice appear in all copies of the 21*48493Smckusick * software, derivative works or modified versions, and any portions 22*48493Smckusick * thereof, and that both notices appear in supporting documentation. 23*48493Smckusick * 24*48493Smckusick * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 25*48493Smckusick * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 26*48493Smckusick * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 27*48493Smckusick * 28*48493Smckusick * Carnegie Mellon requests users of this software to return to 29*48493Smckusick * 30*48493Smckusick * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 31*48493Smckusick * School of Computer Science 32*48493Smckusick * Carnegie Mellon University 33*48493Smckusick * Pittsburgh PA 15213-3890 34*48493Smckusick * 35*48493Smckusick * any improvements or extensions that they make and grant Carnegie the 36*48493Smckusick * rights to redistribute these changes. 3745748Smckusick */ 3845748Smckusick 3945748Smckusick /* 4045748Smckusick * Virtual memory object module. 4145748Smckusick */ 4245748Smckusick 4345748Smckusick #include "param.h" 4445748Smckusick #include "malloc.h" 4545748Smckusick 4648386Skarels #include "vm.h" 4748386Skarels #include "vm_page.h" 4848386Skarels 4945748Smckusick /* 5045748Smckusick * Virtual memory objects maintain the actual data 5145748Smckusick * associated with allocated virtual memory. A given 5245748Smckusick * page of memory exists within exactly one object. 5345748Smckusick * 5445748Smckusick * An object is only deallocated when all "references" 5545748Smckusick * are given up. Only one "reference" to a given 5645748Smckusick * region of an object should be writeable. 5745748Smckusick * 5845748Smckusick * Associated with each object is a list of all resident 5945748Smckusick * memory pages belonging to that object; this list is 6045748Smckusick * maintained by the "vm_page" module, and locked by the object's 6145748Smckusick * lock. 6245748Smckusick * 6345748Smckusick * Each object also records a "pager" routine which is 6445748Smckusick * used to retrieve (and store) pages to the proper backing 6545748Smckusick * storage. In addition, objects may be backed by other 6645748Smckusick * objects from which they were virtual-copied. 6745748Smckusick * 6845748Smckusick * The only items within the object structure which are 6945748Smckusick * modified after time of creation are: 7045748Smckusick * reference count locked by object's lock 7145748Smckusick * pager routine locked by object's lock 7245748Smckusick * 7345748Smckusick */ 7445748Smckusick 7545748Smckusick struct vm_object kernel_object_store; 7645748Smckusick struct vm_object kmem_object_store; 7745748Smckusick 7845748Smckusick #define VM_OBJECT_HASH_COUNT 157 7945748Smckusick 8045748Smckusick int vm_cache_max = 100; /* can patch if necessary */ 8145748Smckusick queue_head_t vm_object_hashtable[VM_OBJECT_HASH_COUNT]; 8245748Smckusick 8345748Smckusick long object_collapses = 0; 8445748Smckusick long object_bypasses = 0; 8545748Smckusick 8645748Smckusick /* 8745748Smckusick * vm_object_init: 8845748Smckusick * 8945748Smckusick * Initialize the VM objects module. 9045748Smckusick */ 9145748Smckusick void vm_object_init() 9245748Smckusick { 9345748Smckusick register int i; 9445748Smckusick 9545748Smckusick queue_init(&vm_object_cached_list); 9645748Smckusick queue_init(&vm_object_list); 9745748Smckusick vm_object_count = 0; 9845748Smckusick simple_lock_init(&vm_cache_lock); 9945748Smckusick simple_lock_init(&vm_object_list_lock); 10045748Smckusick 10145748Smckusick for (i = 0; i < VM_OBJECT_HASH_COUNT; i++) 10245748Smckusick queue_init(&vm_object_hashtable[i]); 10345748Smckusick 10445748Smckusick kernel_object = &kernel_object_store; 10545748Smckusick _vm_object_allocate(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS, 10645748Smckusick kernel_object); 10745748Smckusick 10845748Smckusick kmem_object = &kmem_object_store; 10945748Smckusick _vm_object_allocate(VM_KMEM_SIZE + VM_MBUF_SIZE, kmem_object); 11045748Smckusick } 11145748Smckusick 11245748Smckusick /* 11345748Smckusick * vm_object_allocate: 11445748Smckusick * 11545748Smckusick * Returns a new object with the given size. 11645748Smckusick */ 11745748Smckusick 11845748Smckusick vm_object_t vm_object_allocate(size) 11945748Smckusick vm_size_t size; 12045748Smckusick { 12145748Smckusick register vm_object_t result; 12245748Smckusick 12345748Smckusick result = (vm_object_t) 12445748Smckusick malloc((u_long)sizeof *result, M_VMOBJ, M_WAITOK); 12545748Smckusick 12645748Smckusick _vm_object_allocate(size, result); 12745748Smckusick 12845748Smckusick return(result); 12945748Smckusick } 13045748Smckusick 13145748Smckusick _vm_object_allocate(size, object) 13245748Smckusick vm_size_t size; 13345748Smckusick register vm_object_t object; 13445748Smckusick { 13545748Smckusick queue_init(&object->memq); 13645748Smckusick vm_object_lock_init(object); 13745748Smckusick object->ref_count = 1; 13845748Smckusick object->resident_page_count = 0; 13945748Smckusick object->size = size; 14045748Smckusick object->can_persist = FALSE; 14145748Smckusick object->paging_in_progress = 0; 14248386Skarels object->copy = NULL; 14345748Smckusick 14445748Smckusick /* 14545748Smckusick * Object starts out read-write, with no pager. 14645748Smckusick */ 14745748Smckusick 14848386Skarels object->pager = NULL; 14945748Smckusick object->pager_ready = FALSE; 15045748Smckusick object->internal = TRUE; /* vm_allocate_with_pager will reset */ 15145748Smckusick object->paging_offset = 0; 15248386Skarels object->shadow = NULL; 15345748Smckusick object->shadow_offset = (vm_offset_t) 0; 15445748Smckusick 15545748Smckusick simple_lock(&vm_object_list_lock); 15645748Smckusick queue_enter(&vm_object_list, object, vm_object_t, object_list); 15745748Smckusick vm_object_count++; 15845748Smckusick simple_unlock(&vm_object_list_lock); 15945748Smckusick } 16045748Smckusick 16145748Smckusick /* 16245748Smckusick * vm_object_reference: 16345748Smckusick * 16445748Smckusick * Gets another reference to the given object. 16545748Smckusick */ 16645748Smckusick void vm_object_reference(object) 16745748Smckusick register vm_object_t object; 16845748Smckusick { 16948386Skarels if (object == NULL) 17045748Smckusick return; 17145748Smckusick 17245748Smckusick vm_object_lock(object); 17345748Smckusick object->ref_count++; 17445748Smckusick vm_object_unlock(object); 17545748Smckusick } 17645748Smckusick 17745748Smckusick /* 17845748Smckusick * vm_object_deallocate: 17945748Smckusick * 18045748Smckusick * Release a reference to the specified object, 18145748Smckusick * gained either through a vm_object_allocate 18245748Smckusick * or a vm_object_reference call. When all references 18345748Smckusick * are gone, storage associated with this object 18445748Smckusick * may be relinquished. 18545748Smckusick * 18645748Smckusick * No object may be locked. 18745748Smckusick */ 18845748Smckusick void vm_object_deallocate(object) 18945748Smckusick register vm_object_t object; 19045748Smckusick { 19145748Smckusick vm_object_t temp; 19245748Smckusick 19348386Skarels while (object != NULL) { 19445748Smckusick 19545748Smckusick /* 19645748Smckusick * The cache holds a reference (uncounted) to 19745748Smckusick * the object; we must lock it before removing 19845748Smckusick * the object. 19945748Smckusick */ 20045748Smckusick 20145748Smckusick vm_object_cache_lock(); 20245748Smckusick 20345748Smckusick /* 20445748Smckusick * Lose the reference 20545748Smckusick */ 20645748Smckusick vm_object_lock(object); 20745748Smckusick if (--(object->ref_count) != 0) { 20845748Smckusick 20945748Smckusick /* 21045748Smckusick * If there are still references, then 21145748Smckusick * we are done. 21245748Smckusick */ 21345748Smckusick vm_object_unlock(object); 21445748Smckusick vm_object_cache_unlock(); 21545748Smckusick return; 21645748Smckusick } 21745748Smckusick 21845748Smckusick /* 21945748Smckusick * See if this object can persist. If so, enter 22045748Smckusick * it in the cache, then deactivate all of its 22145748Smckusick * pages. 22245748Smckusick */ 22345748Smckusick 22445748Smckusick if (object->can_persist) { 22545748Smckusick 22645748Smckusick queue_enter(&vm_object_cached_list, object, 22745748Smckusick vm_object_t, cached_list); 22845748Smckusick vm_object_cached++; 22945748Smckusick vm_object_cache_unlock(); 23045748Smckusick 23145748Smckusick vm_object_deactivate_pages(object); 23245748Smckusick vm_object_unlock(object); 23345748Smckusick 23445748Smckusick vm_object_cache_trim(); 23545748Smckusick return; 23645748Smckusick } 23745748Smckusick 23845748Smckusick /* 23945748Smckusick * Make sure no one can look us up now. 24045748Smckusick */ 24145748Smckusick vm_object_remove(object->pager); 24245748Smckusick vm_object_cache_unlock(); 24345748Smckusick 24445748Smckusick temp = object->shadow; 24545748Smckusick vm_object_terminate(object); 24645748Smckusick /* unlocks and deallocates object */ 24745748Smckusick object = temp; 24845748Smckusick } 24945748Smckusick } 25045748Smckusick 25145748Smckusick 25245748Smckusick /* 25345748Smckusick * vm_object_terminate actually destroys the specified object, freeing 25445748Smckusick * up all previously used resources. 25545748Smckusick * 25645748Smckusick * The object must be locked. 25745748Smckusick */ 25845748Smckusick void vm_object_terminate(object) 25945748Smckusick register vm_object_t object; 26045748Smckusick { 26145748Smckusick register vm_page_t p; 26245748Smckusick vm_object_t shadow_object; 26345748Smckusick 26445748Smckusick /* 26545748Smckusick * Detach the object from its shadow if we are the shadow's 26645748Smckusick * copy. 26745748Smckusick */ 26848386Skarels if ((shadow_object = object->shadow) != NULL) { 26945748Smckusick vm_object_lock(shadow_object); 27045748Smckusick if (shadow_object->copy == object) 27148386Skarels shadow_object->copy = NULL; 27245748Smckusick #if 0 27348386Skarels else if (shadow_object->copy != NULL) 27445748Smckusick panic("vm_object_terminate: copy/shadow inconsistency"); 27545748Smckusick #endif 27645748Smckusick vm_object_unlock(shadow_object); 27745748Smckusick } 27845748Smckusick 27945748Smckusick /* 28045748Smckusick * Wait until the pageout daemon is through 28145748Smckusick * with the object. 28245748Smckusick */ 28345748Smckusick 28445748Smckusick while (object->paging_in_progress != 0) { 28545748Smckusick vm_object_sleep(object, object, FALSE); 28645748Smckusick vm_object_lock(object); 28745748Smckusick } 28845748Smckusick 28945748Smckusick 29045748Smckusick /* 29145748Smckusick * While the paging system is locked, 29245748Smckusick * pull the object's pages off the active 29345748Smckusick * and inactive queues. This keeps the 29445748Smckusick * pageout daemon from playing with them 29545748Smckusick * during vm_pager_deallocate. 29645748Smckusick * 29745748Smckusick * We can't free the pages yet, because the 29845748Smckusick * object's pager may have to write them out 29945748Smckusick * before deallocating the paging space. 30045748Smckusick */ 30145748Smckusick 30245748Smckusick p = (vm_page_t) queue_first(&object->memq); 30345748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 30445748Smckusick VM_PAGE_CHECK(p); 30545748Smckusick 30645748Smckusick vm_page_lock_queues(); 30745748Smckusick if (p->active) { 30845748Smckusick queue_remove(&vm_page_queue_active, p, vm_page_t, 30945748Smckusick pageq); 31045748Smckusick p->active = FALSE; 31145748Smckusick vm_page_active_count--; 31245748Smckusick } 31345748Smckusick 31445748Smckusick if (p->inactive) { 31545748Smckusick queue_remove(&vm_page_queue_inactive, p, vm_page_t, 31645748Smckusick pageq); 31745748Smckusick p->inactive = FALSE; 31845748Smckusick vm_page_inactive_count--; 31945748Smckusick } 32045748Smckusick vm_page_unlock_queues(); 32145748Smckusick p = (vm_page_t) queue_next(&p->listq); 32245748Smckusick } 32345748Smckusick 32445748Smckusick vm_object_unlock(object); 32545748Smckusick 32645748Smckusick if (object->paging_in_progress != 0) 32745748Smckusick panic("vm_object_deallocate: pageout in progress"); 32845748Smckusick 32945748Smckusick /* 33045748Smckusick * Clean and free the pages, as appropriate. 33145748Smckusick * All references to the object are gone, 33245748Smckusick * so we don't need to lock it. 33345748Smckusick */ 33445748Smckusick 33545748Smckusick if (!object->internal) { 33645748Smckusick vm_object_lock(object); 33745748Smckusick vm_object_page_clean(object, 0, 0); 33845748Smckusick vm_object_unlock(object); 33945748Smckusick } 34045748Smckusick while (!queue_empty(&object->memq)) { 34145748Smckusick p = (vm_page_t) queue_first(&object->memq); 34245748Smckusick 34345748Smckusick VM_PAGE_CHECK(p); 34445748Smckusick 34545748Smckusick vm_page_lock_queues(); 34645748Smckusick vm_page_free(p); 34745748Smckusick vm_page_unlock_queues(); 34845748Smckusick } 34945748Smckusick 35045748Smckusick /* 35145748Smckusick * Let the pager know object is dead. 35245748Smckusick */ 35345748Smckusick 35448386Skarels if (object->pager != NULL) 35545748Smckusick vm_pager_deallocate(object->pager); 35645748Smckusick 35745748Smckusick 35845748Smckusick simple_lock(&vm_object_list_lock); 35945748Smckusick queue_remove(&vm_object_list, object, vm_object_t, object_list); 36045748Smckusick vm_object_count--; 36145748Smckusick simple_unlock(&vm_object_list_lock); 36245748Smckusick 36345748Smckusick /* 36445748Smckusick * Free the space for the object. 36545748Smckusick */ 36645748Smckusick 36745748Smckusick free((caddr_t)object, M_VMOBJ); 36845748Smckusick } 36945748Smckusick 37045748Smckusick /* 37145748Smckusick * vm_object_page_clean 37245748Smckusick * 37345748Smckusick * Clean all dirty pages in the specified range of object. 37445748Smckusick * Leaves page on whatever queue it is currently on. 37545748Smckusick * 37645748Smckusick * Odd semantics: if start == end, we clean everything. 37745748Smckusick * 37845748Smckusick * The object must be locked. 37945748Smckusick */ 38045748Smckusick vm_object_page_clean(object, start, end) 38145748Smckusick register vm_object_t object; 38245748Smckusick register vm_offset_t start; 38345748Smckusick register vm_offset_t end; 38445748Smckusick { 38545748Smckusick register vm_page_t p; 38645748Smckusick 38748386Skarels if (object->pager == NULL) 38845748Smckusick return; 38945748Smckusick 39045748Smckusick again: 39145748Smckusick p = (vm_page_t) queue_first(&object->memq); 39245748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 39345748Smckusick if (start == end || 39445748Smckusick p->offset >= start && p->offset < end) { 39545748Smckusick if (p->clean && pmap_is_modified(VM_PAGE_TO_PHYS(p))) 39645748Smckusick p->clean = FALSE; 39745748Smckusick pmap_remove_all(VM_PAGE_TO_PHYS(p)); 39845748Smckusick if (!p->clean) { 39945748Smckusick p->busy = TRUE; 40045748Smckusick object->paging_in_progress++; 40145748Smckusick vm_object_unlock(object); 40245748Smckusick (void) vm_pager_put(object->pager, p, TRUE); 40345748Smckusick vm_object_lock(object); 40445748Smckusick object->paging_in_progress--; 40545748Smckusick p->busy = FALSE; 40645748Smckusick PAGE_WAKEUP(p); 40745748Smckusick goto again; 40845748Smckusick } 40945748Smckusick } 41045748Smckusick p = (vm_page_t) queue_next(&p->listq); 41145748Smckusick } 41245748Smckusick } 41345748Smckusick 41445748Smckusick /* 41545748Smckusick * vm_object_deactivate_pages 41645748Smckusick * 41745748Smckusick * Deactivate all pages in the specified object. (Keep its pages 41845748Smckusick * in memory even though it is no longer referenced.) 41945748Smckusick * 42045748Smckusick * The object must be locked. 42145748Smckusick */ 42245748Smckusick vm_object_deactivate_pages(object) 42345748Smckusick register vm_object_t object; 42445748Smckusick { 42545748Smckusick register vm_page_t p, next; 42645748Smckusick 42745748Smckusick p = (vm_page_t) queue_first(&object->memq); 42845748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 42945748Smckusick next = (vm_page_t) queue_next(&p->listq); 43045748Smckusick vm_page_lock_queues(); 43145748Smckusick vm_page_deactivate(p); 43245748Smckusick vm_page_unlock_queues(); 43345748Smckusick p = next; 43445748Smckusick } 43545748Smckusick } 43645748Smckusick 43745748Smckusick /* 43845748Smckusick * Trim the object cache to size. 43945748Smckusick */ 44045748Smckusick vm_object_cache_trim() 44145748Smckusick { 44245748Smckusick register vm_object_t object; 44345748Smckusick 44445748Smckusick vm_object_cache_lock(); 44545748Smckusick while (vm_object_cached > vm_cache_max) { 44645748Smckusick object = (vm_object_t) queue_first(&vm_object_cached_list); 44745748Smckusick vm_object_cache_unlock(); 44845748Smckusick 44945748Smckusick if (object != vm_object_lookup(object->pager)) 45045748Smckusick panic("vm_object_deactivate: I'm sooo confused."); 45145748Smckusick 45245748Smckusick pager_cache(object, FALSE); 45345748Smckusick 45445748Smckusick vm_object_cache_lock(); 45545748Smckusick } 45645748Smckusick vm_object_cache_unlock(); 45745748Smckusick } 45845748Smckusick 45945748Smckusick 46045748Smckusick /* 46145748Smckusick * vm_object_shutdown() 46245748Smckusick * 46345748Smckusick * Shut down the object system. Unfortunately, while we 46445748Smckusick * may be trying to do this, init is happily waiting for 46545748Smckusick * processes to exit, and therefore will be causing some objects 46645748Smckusick * to be deallocated. To handle this, we gain a fake reference 46745748Smckusick * to all objects we release paging areas for. This will prevent 46845748Smckusick * a duplicate deallocation. This routine is probably full of 46945748Smckusick * race conditions! 47045748Smckusick */ 47145748Smckusick 47245748Smckusick void vm_object_shutdown() 47345748Smckusick { 47445748Smckusick register vm_object_t object; 47545748Smckusick 47645748Smckusick /* 47745748Smckusick * Clean up the object cache *before* we screw up the reference 47845748Smckusick * counts on all of the objects. 47945748Smckusick */ 48045748Smckusick 48145748Smckusick vm_object_cache_clear(); 48245748Smckusick 48345748Smckusick printf("free paging spaces: "); 48445748Smckusick 48545748Smckusick /* 48645748Smckusick * First we gain a reference to each object so that 48745748Smckusick * no one else will deallocate them. 48845748Smckusick */ 48945748Smckusick 49045748Smckusick simple_lock(&vm_object_list_lock); 49145748Smckusick object = (vm_object_t) queue_first(&vm_object_list); 49245748Smckusick while (!queue_end(&vm_object_list, (queue_entry_t) object)) { 49345748Smckusick vm_object_reference(object); 49445748Smckusick object = (vm_object_t) queue_next(&object->object_list); 49545748Smckusick } 49645748Smckusick simple_unlock(&vm_object_list_lock); 49745748Smckusick 49845748Smckusick /* 49945748Smckusick * Now we deallocate all the paging areas. We don't need 50045748Smckusick * to lock anything because we've reduced to a single 50145748Smckusick * processor while shutting down. This also assumes that 50245748Smckusick * no new objects are being created. 50345748Smckusick */ 50445748Smckusick 50545748Smckusick object = (vm_object_t) queue_first(&vm_object_list); 50645748Smckusick while (!queue_end(&vm_object_list, (queue_entry_t) object)) { 50748386Skarels if (object->pager != NULL) 50845748Smckusick vm_pager_deallocate(object->pager); 50945748Smckusick object = (vm_object_t) queue_next(&object->object_list); 51045748Smckusick printf("."); 51145748Smckusick } 51245748Smckusick printf("done.\n"); 51345748Smckusick } 51445748Smckusick 51545748Smckusick /* 51645748Smckusick * vm_object_pmap_copy: 51745748Smckusick * 51845748Smckusick * Makes all physical pages in the specified 51945748Smckusick * object range copy-on-write. No writeable 52045748Smckusick * references to these pages should remain. 52145748Smckusick * 52245748Smckusick * The object must *not* be locked. 52345748Smckusick */ 52445748Smckusick void vm_object_pmap_copy(object, start, end) 52545748Smckusick register vm_object_t object; 52645748Smckusick register vm_offset_t start; 52745748Smckusick register vm_offset_t end; 52845748Smckusick { 52945748Smckusick register vm_page_t p; 53045748Smckusick 53148386Skarels if (object == NULL) 53245748Smckusick return; 53345748Smckusick 53445748Smckusick vm_object_lock(object); 53545748Smckusick p = (vm_page_t) queue_first(&object->memq); 53645748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 53745748Smckusick if ((start <= p->offset) && (p->offset < end)) { 53845748Smckusick if (!p->copy_on_write) { 53945748Smckusick pmap_copy_on_write(VM_PAGE_TO_PHYS(p)); 54045748Smckusick p->copy_on_write = TRUE; 54145748Smckusick } 54245748Smckusick } 54345748Smckusick p = (vm_page_t) queue_next(&p->listq); 54445748Smckusick } 54545748Smckusick vm_object_unlock(object); 54645748Smckusick } 54745748Smckusick 54845748Smckusick /* 54945748Smckusick * vm_object_pmap_remove: 55045748Smckusick * 55145748Smckusick * Removes all physical pages in the specified 55245748Smckusick * object range from all physical maps. 55345748Smckusick * 55445748Smckusick * The object must *not* be locked. 55545748Smckusick */ 55645748Smckusick void vm_object_pmap_remove(object, start, end) 55745748Smckusick register vm_object_t object; 55845748Smckusick register vm_offset_t start; 55945748Smckusick register vm_offset_t end; 56045748Smckusick { 56145748Smckusick register vm_page_t p; 56245748Smckusick 56348386Skarels if (object == NULL) 56445748Smckusick return; 56545748Smckusick 56645748Smckusick vm_object_lock(object); 56745748Smckusick p = (vm_page_t) queue_first(&object->memq); 56845748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 56945748Smckusick if ((start <= p->offset) && (p->offset < end)) { 57045748Smckusick pmap_remove_all(VM_PAGE_TO_PHYS(p)); 57145748Smckusick } 57245748Smckusick p = (vm_page_t) queue_next(&p->listq); 57345748Smckusick } 57445748Smckusick vm_object_unlock(object); 57545748Smckusick } 57645748Smckusick 57745748Smckusick /* 57845748Smckusick * vm_object_copy: 57945748Smckusick * 58045748Smckusick * Create a new object which is a copy of an existing 58145748Smckusick * object, and mark all of the pages in the existing 58245748Smckusick * object 'copy-on-write'. The new object has one reference. 58345748Smckusick * Returns the new object. 58445748Smckusick * 58545748Smckusick * May defer the copy until later if the object is not backed 58645748Smckusick * up by a non-default pager. 58745748Smckusick */ 58845748Smckusick void vm_object_copy(src_object, src_offset, size, 58945748Smckusick dst_object, dst_offset, src_needs_copy) 59045748Smckusick register vm_object_t src_object; 59145748Smckusick vm_offset_t src_offset; 59245748Smckusick vm_size_t size; 59345748Smckusick vm_object_t *dst_object; /* OUT */ 59445748Smckusick vm_offset_t *dst_offset; /* OUT */ 59545748Smckusick boolean_t *src_needs_copy; /* OUT */ 59645748Smckusick { 59745748Smckusick register vm_object_t new_copy; 59845748Smckusick register vm_object_t old_copy; 59945748Smckusick vm_offset_t new_start, new_end; 60045748Smckusick 60145748Smckusick register vm_page_t p; 60245748Smckusick 60348386Skarels if (src_object == NULL) { 60445748Smckusick /* 60545748Smckusick * Nothing to copy 60645748Smckusick */ 60748386Skarels *dst_object = NULL; 60845748Smckusick *dst_offset = 0; 60945748Smckusick *src_needs_copy = FALSE; 61045748Smckusick return; 61145748Smckusick } 61245748Smckusick 61345748Smckusick /* 61445748Smckusick * If the object's pager is null_pager or the 61545748Smckusick * default pager, we don't have to make a copy 61645748Smckusick * of it. Instead, we set the needs copy flag and 61745748Smckusick * make a shadow later. 61845748Smckusick */ 61945748Smckusick 62045748Smckusick vm_object_lock(src_object); 62148386Skarels if (src_object->pager == NULL || 62245748Smckusick src_object->internal) { 62345748Smckusick 62445748Smckusick /* 62545748Smckusick * Make another reference to the object 62645748Smckusick */ 62745748Smckusick src_object->ref_count++; 62845748Smckusick 62945748Smckusick /* 63045748Smckusick * Mark all of the pages copy-on-write. 63145748Smckusick */ 63245748Smckusick for (p = (vm_page_t) queue_first(&src_object->memq); 63345748Smckusick !queue_end(&src_object->memq, (queue_entry_t)p); 63445748Smckusick p = (vm_page_t) queue_next(&p->listq)) { 63545748Smckusick if (src_offset <= p->offset && 63645748Smckusick p->offset < src_offset + size) 63745748Smckusick p->copy_on_write = TRUE; 63845748Smckusick } 63945748Smckusick vm_object_unlock(src_object); 64045748Smckusick 64145748Smckusick *dst_object = src_object; 64245748Smckusick *dst_offset = src_offset; 64345748Smckusick 64445748Smckusick /* 64545748Smckusick * Must make a shadow when write is desired 64645748Smckusick */ 64745748Smckusick *src_needs_copy = TRUE; 64845748Smckusick return; 64945748Smckusick } 65045748Smckusick 65145748Smckusick /* 65245748Smckusick * Try to collapse the object before copying it. 65345748Smckusick */ 65445748Smckusick vm_object_collapse(src_object); 65545748Smckusick 65645748Smckusick /* 65745748Smckusick * If the object has a pager, the pager wants to 65845748Smckusick * see all of the changes. We need a copy-object 65945748Smckusick * for the changed pages. 66045748Smckusick * 66145748Smckusick * If there is a copy-object, and it is empty, 66245748Smckusick * no changes have been made to the object since the 66345748Smckusick * copy-object was made. We can use the same copy- 66445748Smckusick * object. 66545748Smckusick */ 66645748Smckusick 66745748Smckusick Retry1: 66845748Smckusick old_copy = src_object->copy; 66948386Skarels if (old_copy != NULL) { 67045748Smckusick /* 67145748Smckusick * Try to get the locks (out of order) 67245748Smckusick */ 67345748Smckusick if (!vm_object_lock_try(old_copy)) { 67445748Smckusick vm_object_unlock(src_object); 67545748Smckusick 67645748Smckusick /* should spin a bit here... */ 67745748Smckusick vm_object_lock(src_object); 67845748Smckusick goto Retry1; 67945748Smckusick } 68045748Smckusick 68145748Smckusick if (old_copy->resident_page_count == 0 && 68248386Skarels old_copy->pager == NULL) { 68345748Smckusick /* 68445748Smckusick * Return another reference to 68545748Smckusick * the existing copy-object. 68645748Smckusick */ 68745748Smckusick old_copy->ref_count++; 68845748Smckusick vm_object_unlock(old_copy); 68945748Smckusick vm_object_unlock(src_object); 69045748Smckusick *dst_object = old_copy; 69145748Smckusick *dst_offset = src_offset; 69245748Smckusick *src_needs_copy = FALSE; 69345748Smckusick return; 69445748Smckusick } 69545748Smckusick vm_object_unlock(old_copy); 69645748Smckusick } 69745748Smckusick vm_object_unlock(src_object); 69845748Smckusick 69945748Smckusick /* 70045748Smckusick * If the object has a pager, the pager wants 70145748Smckusick * to see all of the changes. We must make 70245748Smckusick * a copy-object and put the changed pages there. 70345748Smckusick * 70445748Smckusick * The copy-object is always made large enough to 70545748Smckusick * completely shadow the original object, since 70645748Smckusick * it may have several users who want to shadow 70745748Smckusick * the original object at different points. 70845748Smckusick */ 70945748Smckusick 71045748Smckusick new_copy = vm_object_allocate(src_object->size); 71145748Smckusick 71245748Smckusick Retry2: 71345748Smckusick vm_object_lock(src_object); 71445748Smckusick /* 71545748Smckusick * Copy object may have changed while we were unlocked 71645748Smckusick */ 71745748Smckusick old_copy = src_object->copy; 71848386Skarels if (old_copy != NULL) { 71945748Smckusick /* 72045748Smckusick * Try to get the locks (out of order) 72145748Smckusick */ 72245748Smckusick if (!vm_object_lock_try(old_copy)) { 72345748Smckusick vm_object_unlock(src_object); 72445748Smckusick goto Retry2; 72545748Smckusick } 72645748Smckusick 72745748Smckusick /* 72845748Smckusick * Consistency check 72945748Smckusick */ 73045748Smckusick if (old_copy->shadow != src_object || 73145748Smckusick old_copy->shadow_offset != (vm_offset_t) 0) 73245748Smckusick panic("vm_object_copy: copy/shadow inconsistency"); 73345748Smckusick 73445748Smckusick /* 73545748Smckusick * Make the old copy-object shadow the new one. 73645748Smckusick * It will receive no more pages from the original 73745748Smckusick * object. 73845748Smckusick */ 73945748Smckusick 74045748Smckusick src_object->ref_count--; /* remove ref. from old_copy */ 74145748Smckusick old_copy->shadow = new_copy; 74245748Smckusick new_copy->ref_count++; /* locking not needed - we 74345748Smckusick have the only pointer */ 74445748Smckusick vm_object_unlock(old_copy); /* done with old_copy */ 74545748Smckusick } 74645748Smckusick 74745748Smckusick new_start = (vm_offset_t) 0; /* always shadow original at 0 */ 74845748Smckusick new_end = (vm_offset_t) new_copy->size; /* for the whole object */ 74945748Smckusick 75045748Smckusick /* 75145748Smckusick * Point the new copy at the existing object. 75245748Smckusick */ 75345748Smckusick 75445748Smckusick new_copy->shadow = src_object; 75545748Smckusick new_copy->shadow_offset = new_start; 75645748Smckusick src_object->ref_count++; 75745748Smckusick src_object->copy = new_copy; 75845748Smckusick 75945748Smckusick /* 76045748Smckusick * Mark all the affected pages of the existing object 76145748Smckusick * copy-on-write. 76245748Smckusick */ 76345748Smckusick p = (vm_page_t) queue_first(&src_object->memq); 76445748Smckusick while (!queue_end(&src_object->memq, (queue_entry_t) p)) { 76545748Smckusick if ((new_start <= p->offset) && (p->offset < new_end)) { 76645748Smckusick p->copy_on_write = TRUE; 76745748Smckusick } 76845748Smckusick p = (vm_page_t) queue_next(&p->listq); 76945748Smckusick } 77045748Smckusick 77145748Smckusick vm_object_unlock(src_object); 77245748Smckusick 77345748Smckusick *dst_object = new_copy; 77445748Smckusick *dst_offset = src_offset - new_start; 77545748Smckusick *src_needs_copy = FALSE; 77645748Smckusick } 77745748Smckusick 77845748Smckusick /* 77945748Smckusick * vm_object_shadow: 78045748Smckusick * 78145748Smckusick * Create a new object which is backed by the 78245748Smckusick * specified existing object range. The source 78345748Smckusick * object reference is deallocated. 78445748Smckusick * 78545748Smckusick * The new object and offset into that object 78645748Smckusick * are returned in the source parameters. 78745748Smckusick */ 78845748Smckusick 78945748Smckusick void vm_object_shadow(object, offset, length) 79045748Smckusick vm_object_t *object; /* IN/OUT */ 79145748Smckusick vm_offset_t *offset; /* IN/OUT */ 79245748Smckusick vm_size_t length; 79345748Smckusick { 79445748Smckusick register vm_object_t source; 79545748Smckusick register vm_object_t result; 79645748Smckusick 79745748Smckusick source = *object; 79845748Smckusick 79945748Smckusick /* 80045748Smckusick * Allocate a new object with the given length 80145748Smckusick */ 80245748Smckusick 80348386Skarels if ((result = vm_object_allocate(length)) == NULL) 80445748Smckusick panic("vm_object_shadow: no object for shadowing"); 80545748Smckusick 80645748Smckusick /* 80745748Smckusick * The new object shadows the source object, adding 80845748Smckusick * a reference to it. Our caller changes his reference 80945748Smckusick * to point to the new object, removing a reference to 81045748Smckusick * the source object. Net result: no change of reference 81145748Smckusick * count. 81245748Smckusick */ 81345748Smckusick result->shadow = source; 81445748Smckusick 81545748Smckusick /* 81645748Smckusick * Store the offset into the source object, 81745748Smckusick * and fix up the offset into the new object. 81845748Smckusick */ 81945748Smckusick 82045748Smckusick result->shadow_offset = *offset; 82145748Smckusick 82245748Smckusick /* 82345748Smckusick * Return the new things 82445748Smckusick */ 82545748Smckusick 82645748Smckusick *offset = 0; 82745748Smckusick *object = result; 82845748Smckusick } 82945748Smckusick 83045748Smckusick /* 83145748Smckusick * Set the specified object's pager to the specified pager. 83245748Smckusick */ 83345748Smckusick 83445748Smckusick void vm_object_setpager(object, pager, paging_offset, 83545748Smckusick read_only) 83645748Smckusick vm_object_t object; 83745748Smckusick vm_pager_t pager; 83845748Smckusick vm_offset_t paging_offset; 83945748Smckusick boolean_t read_only; 84045748Smckusick { 84145748Smckusick #ifdef lint 84245748Smckusick read_only++; /* No longer used */ 84345748Smckusick #endif lint 84445748Smckusick 84545748Smckusick vm_object_lock(object); /* XXX ? */ 84645748Smckusick object->pager = pager; 84745748Smckusick object->paging_offset = paging_offset; 84845748Smckusick vm_object_unlock(object); /* XXX ? */ 84945748Smckusick } 85045748Smckusick 85145748Smckusick /* 85245748Smckusick * vm_object_hash hashes the pager/id pair. 85345748Smckusick */ 85445748Smckusick 85545748Smckusick #define vm_object_hash(pager) \ 85645748Smckusick (((unsigned)pager)%VM_OBJECT_HASH_COUNT) 85745748Smckusick 85845748Smckusick /* 85945748Smckusick * vm_object_lookup looks in the object cache for an object with the 86045748Smckusick * specified pager and paging id. 86145748Smckusick */ 86245748Smckusick 86345748Smckusick vm_object_t vm_object_lookup(pager) 86445748Smckusick vm_pager_t pager; 86545748Smckusick { 86645748Smckusick register queue_t bucket; 86745748Smckusick register vm_object_hash_entry_t entry; 86845748Smckusick vm_object_t object; 86945748Smckusick 87045748Smckusick bucket = &vm_object_hashtable[vm_object_hash(pager)]; 87145748Smckusick 87245748Smckusick vm_object_cache_lock(); 87345748Smckusick 87445748Smckusick entry = (vm_object_hash_entry_t) queue_first(bucket); 87545748Smckusick while (!queue_end(bucket, (queue_entry_t) entry)) { 87645748Smckusick object = entry->object; 87745748Smckusick if (object->pager == pager) { 87845748Smckusick vm_object_lock(object); 87945748Smckusick if (object->ref_count == 0) { 88045748Smckusick queue_remove(&vm_object_cached_list, object, 88145748Smckusick vm_object_t, cached_list); 88245748Smckusick vm_object_cached--; 88345748Smckusick } 88445748Smckusick object->ref_count++; 88545748Smckusick vm_object_unlock(object); 88645748Smckusick vm_object_cache_unlock(); 88745748Smckusick return(object); 88845748Smckusick } 88945748Smckusick entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links); 89045748Smckusick } 89145748Smckusick 89245748Smckusick vm_object_cache_unlock(); 89348386Skarels return(NULL); 89445748Smckusick } 89545748Smckusick 89645748Smckusick /* 89745748Smckusick * vm_object_enter enters the specified object/pager/id into 89845748Smckusick * the hash table. 89945748Smckusick */ 90045748Smckusick 90145748Smckusick void vm_object_enter(object, pager) 90245748Smckusick vm_object_t object; 90345748Smckusick vm_pager_t pager; 90445748Smckusick { 90545748Smckusick register queue_t bucket; 90645748Smckusick register vm_object_hash_entry_t entry; 90745748Smckusick 90845748Smckusick /* 90945748Smckusick * We don't cache null objects, and we can't cache 91045748Smckusick * objects with the null pager. 91145748Smckusick */ 91245748Smckusick 91348386Skarels if (object == NULL) 91445748Smckusick return; 91548386Skarels if (pager == NULL) 91645748Smckusick return; 91745748Smckusick 91845748Smckusick bucket = &vm_object_hashtable[vm_object_hash(pager)]; 91945748Smckusick entry = (vm_object_hash_entry_t) 92045748Smckusick malloc((u_long)sizeof *entry, M_VMOBJHASH, M_WAITOK); 92145748Smckusick entry->object = object; 92245748Smckusick object->can_persist = TRUE; 92345748Smckusick 92445748Smckusick vm_object_cache_lock(); 92545748Smckusick queue_enter(bucket, entry, vm_object_hash_entry_t, hash_links); 92645748Smckusick vm_object_cache_unlock(); 92745748Smckusick } 92845748Smckusick 92945748Smckusick /* 93045748Smckusick * vm_object_remove: 93145748Smckusick * 93245748Smckusick * Remove the pager from the hash table. 93345748Smckusick * Note: This assumes that the object cache 93445748Smckusick * is locked. XXX this should be fixed 93545748Smckusick * by reorganizing vm_object_deallocate. 93645748Smckusick */ 93745748Smckusick vm_object_remove(pager) 93845748Smckusick register vm_pager_t pager; 93945748Smckusick { 94045748Smckusick register queue_t bucket; 94145748Smckusick register vm_object_hash_entry_t entry; 94245748Smckusick register vm_object_t object; 94345748Smckusick 94445748Smckusick bucket = &vm_object_hashtable[vm_object_hash(pager)]; 94545748Smckusick 94645748Smckusick entry = (vm_object_hash_entry_t) queue_first(bucket); 94745748Smckusick while (!queue_end(bucket, (queue_entry_t) entry)) { 94845748Smckusick object = entry->object; 94945748Smckusick if (object->pager == pager) { 95045748Smckusick queue_remove(bucket, entry, vm_object_hash_entry_t, 95145748Smckusick hash_links); 95245748Smckusick free((caddr_t)entry, M_VMOBJHASH); 95345748Smckusick break; 95445748Smckusick } 95545748Smckusick entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links); 95645748Smckusick } 95745748Smckusick } 95845748Smckusick 95945748Smckusick /* 96045748Smckusick * vm_object_cache_clear removes all objects from the cache. 96145748Smckusick * 96245748Smckusick */ 96345748Smckusick 96445748Smckusick void vm_object_cache_clear() 96545748Smckusick { 96645748Smckusick register vm_object_t object; 96745748Smckusick 96845748Smckusick /* 96945748Smckusick * Remove each object in the cache by scanning down the 97045748Smckusick * list of cached objects. 97145748Smckusick */ 97245748Smckusick vm_object_cache_lock(); 97345748Smckusick while (!queue_empty(&vm_object_cached_list)) { 97445748Smckusick object = (vm_object_t) queue_first(&vm_object_cached_list); 97545748Smckusick vm_object_cache_unlock(); 97645748Smckusick 97745748Smckusick /* 97845748Smckusick * Note: it is important that we use vm_object_lookup 97945748Smckusick * to gain a reference, and not vm_object_reference, because 98045748Smckusick * the logic for removing an object from the cache lies in 98145748Smckusick * lookup. 98245748Smckusick */ 98345748Smckusick if (object != vm_object_lookup(object->pager)) 98445748Smckusick panic("vm_object_cache_clear: I'm sooo confused."); 98545748Smckusick pager_cache(object, FALSE); 98645748Smckusick 98745748Smckusick vm_object_cache_lock(); 98845748Smckusick } 98945748Smckusick vm_object_cache_unlock(); 99045748Smckusick } 99145748Smckusick 99245748Smckusick boolean_t vm_object_collapse_allowed = TRUE; 99345748Smckusick /* 99445748Smckusick * vm_object_collapse: 99545748Smckusick * 99645748Smckusick * Collapse an object with the object backing it. 99745748Smckusick * Pages in the backing object are moved into the 99845748Smckusick * parent, and the backing object is deallocated. 99945748Smckusick * 100045748Smckusick * Requires that the object be locked and the page 100145748Smckusick * queues be unlocked. 100245748Smckusick * 100345748Smckusick */ 100445748Smckusick void vm_object_collapse(object) 100545748Smckusick register vm_object_t object; 100645748Smckusick 100745748Smckusick { 100845748Smckusick register vm_object_t backing_object; 100945748Smckusick register vm_offset_t backing_offset; 101045748Smckusick register vm_size_t size; 101145748Smckusick register vm_offset_t new_offset; 101245748Smckusick register vm_page_t p, pp; 101345748Smckusick 101445748Smckusick if (!vm_object_collapse_allowed) 101545748Smckusick return; 101645748Smckusick 101745748Smckusick while (TRUE) { 101845748Smckusick /* 101945748Smckusick * Verify that the conditions are right for collapse: 102045748Smckusick * 102145748Smckusick * The object exists and no pages in it are currently 102245748Smckusick * being paged out (or have ever been paged out). 102345748Smckusick */ 102448386Skarels if (object == NULL || 102545748Smckusick object->paging_in_progress != 0 || 102648386Skarels object->pager != NULL) 102745748Smckusick return; 102845748Smckusick 102945748Smckusick /* 103045748Smckusick * There is a backing object, and 103145748Smckusick */ 103245748Smckusick 103348386Skarels if ((backing_object = object->shadow) == NULL) 103445748Smckusick return; 103545748Smckusick 103645748Smckusick vm_object_lock(backing_object); 103745748Smckusick /* 103845748Smckusick * ... 103945748Smckusick * The backing object is not read_only, 104045748Smckusick * and no pages in the backing object are 104145748Smckusick * currently being paged out. 104245748Smckusick * The backing object is internal. 104345748Smckusick */ 104445748Smckusick 104545748Smckusick if (!backing_object->internal || 104645748Smckusick backing_object->paging_in_progress != 0) { 104745748Smckusick vm_object_unlock(backing_object); 104845748Smckusick return; 104945748Smckusick } 105045748Smckusick 105145748Smckusick /* 105245748Smckusick * The backing object can't be a copy-object: 105345748Smckusick * the shadow_offset for the copy-object must stay 105445748Smckusick * as 0. Furthermore (for the 'we have all the 105545748Smckusick * pages' case), if we bypass backing_object and 105645748Smckusick * just shadow the next object in the chain, old 105745748Smckusick * pages from that object would then have to be copied 105845748Smckusick * BOTH into the (former) backing_object and into the 105945748Smckusick * parent object. 106045748Smckusick */ 106148386Skarels if (backing_object->shadow != NULL && 106248386Skarels backing_object->shadow->copy != NULL) { 106345748Smckusick vm_object_unlock(backing_object); 106445748Smckusick return; 106545748Smckusick } 106645748Smckusick 106745748Smckusick /* 106845748Smckusick * We know that we can either collapse the backing 106945748Smckusick * object (if the parent is the only reference to 107045748Smckusick * it) or (perhaps) remove the parent's reference 107145748Smckusick * to it. 107245748Smckusick */ 107345748Smckusick 107445748Smckusick backing_offset = object->shadow_offset; 107545748Smckusick size = object->size; 107645748Smckusick 107745748Smckusick /* 107845748Smckusick * If there is exactly one reference to the backing 107945748Smckusick * object, we can collapse it into the parent. 108045748Smckusick */ 108145748Smckusick 108245748Smckusick if (backing_object->ref_count == 1) { 108345748Smckusick 108445748Smckusick /* 108545748Smckusick * We can collapse the backing object. 108645748Smckusick * 108745748Smckusick * Move all in-memory pages from backing_object 108845748Smckusick * to the parent. Pages that have been paged out 108945748Smckusick * will be overwritten by any of the parent's 109045748Smckusick * pages that shadow them. 109145748Smckusick */ 109245748Smckusick 109345748Smckusick while (!queue_empty(&backing_object->memq)) { 109445748Smckusick 109545748Smckusick p = (vm_page_t) 109645748Smckusick queue_first(&backing_object->memq); 109745748Smckusick 109845748Smckusick new_offset = (p->offset - backing_offset); 109945748Smckusick 110045748Smckusick /* 110145748Smckusick * If the parent has a page here, or if 110245748Smckusick * this page falls outside the parent, 110345748Smckusick * dispose of it. 110445748Smckusick * 110545748Smckusick * Otherwise, move it as planned. 110645748Smckusick */ 110745748Smckusick 110845748Smckusick if (p->offset < backing_offset || 110945748Smckusick new_offset >= size) { 111045748Smckusick vm_page_lock_queues(); 111145748Smckusick vm_page_free(p); 111245748Smckusick vm_page_unlock_queues(); 111345748Smckusick } else { 111445748Smckusick pp = vm_page_lookup(object, new_offset); 111548386Skarels if (pp != NULL && !pp->fake) { 111645748Smckusick vm_page_lock_queues(); 111745748Smckusick vm_page_free(p); 111845748Smckusick vm_page_unlock_queues(); 111945748Smckusick } 112045748Smckusick else { 112145748Smckusick if (pp) { 112245748Smckusick /* may be someone waiting for it */ 112345748Smckusick PAGE_WAKEUP(pp); 112445748Smckusick vm_page_lock_queues(); 112545748Smckusick vm_page_free(pp); 112645748Smckusick vm_page_unlock_queues(); 112745748Smckusick } 112845748Smckusick vm_page_rename(p, object, new_offset); 112945748Smckusick } 113045748Smckusick } 113145748Smckusick } 113245748Smckusick 113345748Smckusick /* 113445748Smckusick * Move the pager from backing_object to object. 113545748Smckusick * 113645748Smckusick * XXX We're only using part of the paging space 113745748Smckusick * for keeps now... we ought to discard the 113845748Smckusick * unused portion. 113945748Smckusick */ 114045748Smckusick 114145748Smckusick object->pager = backing_object->pager; 114245748Smckusick object->paging_offset += backing_offset; 114345748Smckusick 114448386Skarels backing_object->pager = NULL; 114545748Smckusick 114645748Smckusick /* 114745748Smckusick * Object now shadows whatever backing_object did. 114845748Smckusick * Note that the reference to backing_object->shadow 114945748Smckusick * moves from within backing_object to within object. 115045748Smckusick */ 115145748Smckusick 115245748Smckusick object->shadow = backing_object->shadow; 115345748Smckusick object->shadow_offset += backing_object->shadow_offset; 115448386Skarels if (object->shadow != NULL && 115548386Skarels object->shadow->copy != NULL) { 115645748Smckusick panic("vm_object_collapse: we collapsed a copy-object!"); 115745748Smckusick } 115845748Smckusick /* 115945748Smckusick * Discard backing_object. 116045748Smckusick * 116145748Smckusick * Since the backing object has no pages, no 116245748Smckusick * pager left, and no object references within it, 116345748Smckusick * all that is necessary is to dispose of it. 116445748Smckusick */ 116545748Smckusick 116645748Smckusick vm_object_unlock(backing_object); 116745748Smckusick 116845748Smckusick simple_lock(&vm_object_list_lock); 116945748Smckusick queue_remove(&vm_object_list, backing_object, 117045748Smckusick vm_object_t, object_list); 117145748Smckusick vm_object_count--; 117245748Smckusick simple_unlock(&vm_object_list_lock); 117345748Smckusick 117445748Smckusick free((caddr_t)backing_object, M_VMOBJ); 117545748Smckusick 117645748Smckusick object_collapses++; 117745748Smckusick } 117845748Smckusick else { 117945748Smckusick /* 118045748Smckusick * If all of the pages in the backing object are 118145748Smckusick * shadowed by the parent object, the parent 118245748Smckusick * object no longer has to shadow the backing 118345748Smckusick * object; it can shadow the next one in the 118445748Smckusick * chain. 118545748Smckusick * 118645748Smckusick * The backing object must not be paged out - we'd 118745748Smckusick * have to check all of the paged-out pages, as 118845748Smckusick * well. 118945748Smckusick */ 119045748Smckusick 119148386Skarels if (backing_object->pager != NULL) { 119245748Smckusick vm_object_unlock(backing_object); 119345748Smckusick return; 119445748Smckusick } 119545748Smckusick 119645748Smckusick /* 119745748Smckusick * Should have a check for a 'small' number 119845748Smckusick * of pages here. 119945748Smckusick */ 120045748Smckusick 120145748Smckusick p = (vm_page_t) queue_first(&backing_object->memq); 120245748Smckusick while (!queue_end(&backing_object->memq, 120345748Smckusick (queue_entry_t) p)) { 120445748Smckusick 120545748Smckusick new_offset = (p->offset - backing_offset); 120645748Smckusick 120745748Smckusick /* 120845748Smckusick * If the parent has a page here, or if 120945748Smckusick * this page falls outside the parent, 121045748Smckusick * keep going. 121145748Smckusick * 121245748Smckusick * Otherwise, the backing_object must be 121345748Smckusick * left in the chain. 121445748Smckusick */ 121545748Smckusick 121645748Smckusick if (p->offset >= backing_offset && 121745748Smckusick new_offset <= size && 121845748Smckusick ((pp = vm_page_lookup(object, new_offset)) 121948386Skarels == NULL || 122045748Smckusick pp->fake)) { 122145748Smckusick /* 122245748Smckusick * Page still needed. 122345748Smckusick * Can't go any further. 122445748Smckusick */ 122545748Smckusick vm_object_unlock(backing_object); 122645748Smckusick return; 122745748Smckusick } 122845748Smckusick p = (vm_page_t) queue_next(&p->listq); 122945748Smckusick } 123045748Smckusick 123145748Smckusick /* 123245748Smckusick * Make the parent shadow the next object 123345748Smckusick * in the chain. Deallocating backing_object 123445748Smckusick * will not remove it, since its reference 123545748Smckusick * count is at least 2. 123645748Smckusick */ 123745748Smckusick 123845748Smckusick vm_object_reference(object->shadow = backing_object->shadow); 123945748Smckusick object->shadow_offset += backing_object->shadow_offset; 124045748Smckusick 124145748Smckusick /* Drop the reference count on backing_object. 124245748Smckusick * Since its ref_count was at least 2, it 124345748Smckusick * will not vanish; so we don't need to call 124445748Smckusick * vm_object_deallocate. 124545748Smckusick */ 124645748Smckusick backing_object->ref_count--; 124745748Smckusick vm_object_unlock(backing_object); 124845748Smckusick 124945748Smckusick object_bypasses ++; 125045748Smckusick 125145748Smckusick } 125245748Smckusick 125345748Smckusick /* 125445748Smckusick * Try again with this object's new backing object. 125545748Smckusick */ 125645748Smckusick } 125745748Smckusick } 125845748Smckusick 125945748Smckusick /* 126045748Smckusick * vm_object_page_remove: [internal] 126145748Smckusick * 126245748Smckusick * Removes all physical pages in the specified 126345748Smckusick * object range from the object's list of pages. 126445748Smckusick * 126545748Smckusick * The object must be locked. 126645748Smckusick */ 126745748Smckusick void vm_object_page_remove(object, start, end) 126845748Smckusick register vm_object_t object; 126945748Smckusick register vm_offset_t start; 127045748Smckusick register vm_offset_t end; 127145748Smckusick { 127245748Smckusick register vm_page_t p, next; 127345748Smckusick 127448386Skarels if (object == NULL) 127545748Smckusick return; 127645748Smckusick 127745748Smckusick p = (vm_page_t) queue_first(&object->memq); 127845748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 127945748Smckusick next = (vm_page_t) queue_next(&p->listq); 128045748Smckusick if ((start <= p->offset) && (p->offset < end)) { 128145748Smckusick pmap_remove_all(VM_PAGE_TO_PHYS(p)); 128245748Smckusick vm_page_lock_queues(); 128345748Smckusick vm_page_free(p); 128445748Smckusick vm_page_unlock_queues(); 128545748Smckusick } 128645748Smckusick p = next; 128745748Smckusick } 128845748Smckusick } 128945748Smckusick 129045748Smckusick /* 129145748Smckusick * Routine: vm_object_coalesce 129245748Smckusick * Function: Coalesces two objects backing up adjoining 129345748Smckusick * regions of memory into a single object. 129445748Smckusick * 129545748Smckusick * returns TRUE if objects were combined. 129645748Smckusick * 129745748Smckusick * NOTE: Only works at the moment if the second object is NULL - 129845748Smckusick * if it's not, which object do we lock first? 129945748Smckusick * 130045748Smckusick * Parameters: 130145748Smckusick * prev_object First object to coalesce 130245748Smckusick * prev_offset Offset into prev_object 130345748Smckusick * next_object Second object into coalesce 130445748Smckusick * next_offset Offset into next_object 130545748Smckusick * 130645748Smckusick * prev_size Size of reference to prev_object 130745748Smckusick * next_size Size of reference to next_object 130845748Smckusick * 130945748Smckusick * Conditions: 131045748Smckusick * The object must *not* be locked. 131145748Smckusick */ 131245748Smckusick boolean_t vm_object_coalesce(prev_object, next_object, 131345748Smckusick prev_offset, next_offset, 131445748Smckusick prev_size, next_size) 131545748Smckusick 131645748Smckusick register vm_object_t prev_object; 131745748Smckusick vm_object_t next_object; 131845748Smckusick vm_offset_t prev_offset, next_offset; 131945748Smckusick vm_size_t prev_size, next_size; 132045748Smckusick { 132145748Smckusick vm_size_t newsize; 132245748Smckusick 132345748Smckusick #ifdef lint 132445748Smckusick next_offset++; 132545748Smckusick #endif lint 132645748Smckusick 132748386Skarels if (next_object != NULL) { 132845748Smckusick return(FALSE); 132945748Smckusick } 133045748Smckusick 133148386Skarels if (prev_object == NULL) { 133245748Smckusick return(TRUE); 133345748Smckusick } 133445748Smckusick 133545748Smckusick vm_object_lock(prev_object); 133645748Smckusick 133745748Smckusick /* 133845748Smckusick * Try to collapse the object first 133945748Smckusick */ 134045748Smckusick vm_object_collapse(prev_object); 134145748Smckusick 134245748Smckusick /* 134345748Smckusick * Can't coalesce if: 134445748Smckusick * . more than one reference 134545748Smckusick * . paged out 134645748Smckusick * . shadows another object 134745748Smckusick * . has a copy elsewhere 134845748Smckusick * (any of which mean that the pages not mapped to 134945748Smckusick * prev_entry may be in use anyway) 135045748Smckusick */ 135145748Smckusick 135245748Smckusick if (prev_object->ref_count > 1 || 135348386Skarels prev_object->pager != NULL || 135448386Skarels prev_object->shadow != NULL || 135548386Skarels prev_object->copy != NULL) { 135645748Smckusick vm_object_unlock(prev_object); 135745748Smckusick return(FALSE); 135845748Smckusick } 135945748Smckusick 136045748Smckusick /* 136145748Smckusick * Remove any pages that may still be in the object from 136245748Smckusick * a previous deallocation. 136345748Smckusick */ 136445748Smckusick 136545748Smckusick vm_object_page_remove(prev_object, 136645748Smckusick prev_offset + prev_size, 136745748Smckusick prev_offset + prev_size + next_size); 136845748Smckusick 136945748Smckusick /* 137045748Smckusick * Extend the object if necessary. 137145748Smckusick */ 137245748Smckusick newsize = prev_offset + prev_size + next_size; 137345748Smckusick if (newsize > prev_object->size) 137445748Smckusick prev_object->size = newsize; 137545748Smckusick 137645748Smckusick vm_object_unlock(prev_object); 137745748Smckusick return(TRUE); 137845748Smckusick } 137945748Smckusick 138045748Smckusick /* 138145748Smckusick * vm_object_print: [ debug ] 138245748Smckusick */ 138345748Smckusick void vm_object_print(object, full) 138445748Smckusick vm_object_t object; 138545748Smckusick boolean_t full; 138645748Smckusick { 138745748Smckusick register vm_page_t p; 138845748Smckusick extern indent; 138945748Smckusick 139045748Smckusick register int count; 139145748Smckusick 139248386Skarels if (object == NULL) 139345748Smckusick return; 139445748Smckusick 139545748Smckusick iprintf("Object 0x%x: size=0x%x, res=%d, ref=%d, ", 139645748Smckusick (int) object, (int) object->size, 139745748Smckusick object->resident_page_count, object->ref_count); 139845748Smckusick printf("pager=0x%x+0x%x, shadow=(0x%x)+0x%x\n", 139945748Smckusick (int) object->pager, (int) object->paging_offset, 140045748Smckusick (int) object->shadow, (int) object->shadow_offset); 140145748Smckusick printf("cache: next=0x%x, prev=0x%x\n", 140245748Smckusick object->cached_list.next, object->cached_list.prev); 140345748Smckusick 140445748Smckusick if (!full) 140545748Smckusick return; 140645748Smckusick 140745748Smckusick indent += 2; 140845748Smckusick count = 0; 140945748Smckusick p = (vm_page_t) queue_first(&object->memq); 141045748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 141145748Smckusick if (count == 0) 141245748Smckusick iprintf("memory:="); 141345748Smckusick else if (count == 6) { 141445748Smckusick printf("\n"); 141545748Smckusick iprintf(" ..."); 141645748Smckusick count = 0; 141745748Smckusick } else 141845748Smckusick printf(","); 141945748Smckusick count++; 142045748Smckusick 142145748Smckusick printf("(off=0x%x,page=0x%x)", p->offset, VM_PAGE_TO_PHYS(p)); 142245748Smckusick p = (vm_page_t) queue_next(&p->listq); 142345748Smckusick } 142445748Smckusick if (count != 0) 142545748Smckusick printf("\n"); 142645748Smckusick indent -= 2; 142745748Smckusick } 1428