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 * 848493Smckusick * %sccs.include.redist.c% 945748Smckusick * 10*52197Smarc * @(#)vm_object.c 7.10 (Berkeley) 01/14/92 1148493Smckusick * 1248493Smckusick * 1348493Smckusick * Copyright (c) 1987, 1990 Carnegie-Mellon University. 1448493Smckusick * All rights reserved. 1548493Smckusick * 1648493Smckusick * Authors: Avadis Tevanian, Jr., Michael Wayne Young 1748493Smckusick * 1848493Smckusick * Permission to use, copy, modify and distribute this software and 1948493Smckusick * its documentation is hereby granted, provided that both the copyright 2048493Smckusick * notice and this permission notice appear in all copies of the 2148493Smckusick * software, derivative works or modified versions, and any portions 2248493Smckusick * thereof, and that both notices appear in supporting documentation. 2348493Smckusick * 2448493Smckusick * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 2548493Smckusick * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 2648493Smckusick * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 2748493Smckusick * 2848493Smckusick * Carnegie Mellon requests users of this software to return to 2948493Smckusick * 3048493Smckusick * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 3148493Smckusick * School of Computer Science 3248493Smckusick * Carnegie Mellon University 3348493Smckusick * Pittsburgh PA 15213-3890 3448493Smckusick * 3548493Smckusick * any improvements or extensions that they make and grant Carnegie the 3648493Smckusick * 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 */ 9151770Smarc void vm_object_init(size) 9251770Smarc vm_size_t size; 9345748Smckusick { 9445748Smckusick register int i; 9545748Smckusick 9645748Smckusick queue_init(&vm_object_cached_list); 9745748Smckusick queue_init(&vm_object_list); 9845748Smckusick vm_object_count = 0; 9945748Smckusick simple_lock_init(&vm_cache_lock); 10045748Smckusick simple_lock_init(&vm_object_list_lock); 10145748Smckusick 10245748Smckusick for (i = 0; i < VM_OBJECT_HASH_COUNT; i++) 10345748Smckusick queue_init(&vm_object_hashtable[i]); 10445748Smckusick 10545748Smckusick kernel_object = &kernel_object_store; 10651770Smarc _vm_object_allocate(size, 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; 14050917Smckusick object->flags = OBJ_INTERNAL; /* vm_allocate_with_pager will reset */ 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->paging_offset = 0; 15048386Skarels object->shadow = NULL; 15145748Smckusick object->shadow_offset = (vm_offset_t) 0; 15245748Smckusick 15345748Smckusick simple_lock(&vm_object_list_lock); 15445748Smckusick queue_enter(&vm_object_list, object, vm_object_t, object_list); 15545748Smckusick vm_object_count++; 15645748Smckusick simple_unlock(&vm_object_list_lock); 15745748Smckusick } 15845748Smckusick 15945748Smckusick /* 16045748Smckusick * vm_object_reference: 16145748Smckusick * 16245748Smckusick * Gets another reference to the given object. 16345748Smckusick */ 16445748Smckusick void vm_object_reference(object) 16545748Smckusick register vm_object_t object; 16645748Smckusick { 16748386Skarels if (object == NULL) 16845748Smckusick return; 16945748Smckusick 17045748Smckusick vm_object_lock(object); 17145748Smckusick object->ref_count++; 17245748Smckusick vm_object_unlock(object); 17345748Smckusick } 17445748Smckusick 17545748Smckusick /* 17645748Smckusick * vm_object_deallocate: 17745748Smckusick * 17845748Smckusick * Release a reference to the specified object, 17945748Smckusick * gained either through a vm_object_allocate 18045748Smckusick * or a vm_object_reference call. When all references 18145748Smckusick * are gone, storage associated with this object 18245748Smckusick * may be relinquished. 18345748Smckusick * 18445748Smckusick * No object may be locked. 18545748Smckusick */ 18645748Smckusick void vm_object_deallocate(object) 18745748Smckusick register vm_object_t object; 18845748Smckusick { 18945748Smckusick vm_object_t temp; 19045748Smckusick 19148386Skarels while (object != NULL) { 19245748Smckusick 19345748Smckusick /* 19445748Smckusick * The cache holds a reference (uncounted) to 19545748Smckusick * the object; we must lock it before removing 19645748Smckusick * the object. 19745748Smckusick */ 19845748Smckusick 19945748Smckusick vm_object_cache_lock(); 20045748Smckusick 20145748Smckusick /* 20245748Smckusick * Lose the reference 20345748Smckusick */ 20445748Smckusick vm_object_lock(object); 20545748Smckusick if (--(object->ref_count) != 0) { 20645748Smckusick 20745748Smckusick /* 20845748Smckusick * If there are still references, then 20945748Smckusick * we are done. 21045748Smckusick */ 21145748Smckusick vm_object_unlock(object); 21245748Smckusick vm_object_cache_unlock(); 21345748Smckusick return; 21445748Smckusick } 21545748Smckusick 21645748Smckusick /* 21745748Smckusick * See if this object can persist. If so, enter 21845748Smckusick * it in the cache, then deactivate all of its 21945748Smckusick * pages. 22045748Smckusick */ 22145748Smckusick 22250917Smckusick if (object->flags & OBJ_CANPERSIST) { 22345748Smckusick 22445748Smckusick queue_enter(&vm_object_cached_list, object, 22545748Smckusick vm_object_t, cached_list); 22645748Smckusick vm_object_cached++; 22745748Smckusick vm_object_cache_unlock(); 22845748Smckusick 22945748Smckusick vm_object_deactivate_pages(object); 23045748Smckusick vm_object_unlock(object); 23145748Smckusick 23245748Smckusick vm_object_cache_trim(); 23345748Smckusick return; 23445748Smckusick } 23545748Smckusick 23645748Smckusick /* 23745748Smckusick * Make sure no one can look us up now. 23845748Smckusick */ 23945748Smckusick vm_object_remove(object->pager); 24045748Smckusick vm_object_cache_unlock(); 24145748Smckusick 24245748Smckusick temp = object->shadow; 24345748Smckusick vm_object_terminate(object); 24445748Smckusick /* unlocks and deallocates object */ 24545748Smckusick object = temp; 24645748Smckusick } 24745748Smckusick } 24845748Smckusick 24945748Smckusick 25045748Smckusick /* 25145748Smckusick * vm_object_terminate actually destroys the specified object, freeing 25245748Smckusick * up all previously used resources. 25345748Smckusick * 25445748Smckusick * The object must be locked. 25545748Smckusick */ 25645748Smckusick void vm_object_terminate(object) 25745748Smckusick register vm_object_t object; 25845748Smckusick { 25945748Smckusick register vm_page_t p; 26045748Smckusick vm_object_t shadow_object; 26145748Smckusick 26245748Smckusick /* 26345748Smckusick * Detach the object from its shadow if we are the shadow's 26445748Smckusick * copy. 26545748Smckusick */ 26648386Skarels if ((shadow_object = object->shadow) != NULL) { 26745748Smckusick vm_object_lock(shadow_object); 26845748Smckusick if (shadow_object->copy == object) 26948386Skarels shadow_object->copy = NULL; 27045748Smckusick #if 0 27148386Skarels else if (shadow_object->copy != NULL) 27245748Smckusick panic("vm_object_terminate: copy/shadow inconsistency"); 27345748Smckusick #endif 27445748Smckusick vm_object_unlock(shadow_object); 27545748Smckusick } 27645748Smckusick 27745748Smckusick /* 27851771Smarc * Wait until the pageout daemon is through with the object. 27945748Smckusick */ 28051771Smarc while (object->paging_in_progress) { 28150856Smckusick vm_object_sleep((int)object, object, FALSE); 28245748Smckusick vm_object_lock(object); 28345748Smckusick } 28445748Smckusick 28545748Smckusick /* 28651771Smarc * If not an internal object clean all the pages, removing them 28751771Smarc * from paging queues as we go. 28845748Smckusick */ 28951771Smarc if ((object->flags & OBJ_INTERNAL) == 0) { 29051771Smarc vm_object_page_clean(object, 0, 0, TRUE); 29151771Smarc vm_object_unlock(object); 29245748Smckusick } 29345748Smckusick 29445748Smckusick /* 29551771Smarc * Now free the pages. 29651771Smarc * For internal objects, this also removes them from paging queues. 29745748Smckusick */ 29845748Smckusick while (!queue_empty(&object->memq)) { 29945748Smckusick p = (vm_page_t) queue_first(&object->memq); 30045748Smckusick VM_PAGE_CHECK(p); 30145748Smckusick vm_page_lock_queues(); 30245748Smckusick vm_page_free(p); 30345748Smckusick vm_page_unlock_queues(); 30445748Smckusick } 30551771Smarc if ((object->flags & OBJ_INTERNAL) == 0) 30651771Smarc vm_object_unlock(object); 30745748Smckusick 30845748Smckusick /* 30951771Smarc * Let the pager know object is dead. 31045748Smckusick */ 31148386Skarels if (object->pager != NULL) 31245748Smckusick vm_pager_deallocate(object->pager); 31345748Smckusick 31445748Smckusick simple_lock(&vm_object_list_lock); 31545748Smckusick queue_remove(&vm_object_list, object, vm_object_t, object_list); 31645748Smckusick vm_object_count--; 31745748Smckusick simple_unlock(&vm_object_list_lock); 31845748Smckusick 31945748Smckusick /* 32051771Smarc * Free the space for the object. 32145748Smckusick */ 32245748Smckusick free((caddr_t)object, M_VMOBJ); 32345748Smckusick } 32445748Smckusick 32545748Smckusick /* 32645748Smckusick * vm_object_page_clean 32745748Smckusick * 32845748Smckusick * Clean all dirty pages in the specified range of object. 329*52197Smarc * If de_queue is TRUE, pages are removed from any paging queue 33051771Smarc * they were on, otherwise they are left on whatever queue they 33151771Smarc * were on before the cleaning operation began. 33245748Smckusick * 33345748Smckusick * Odd semantics: if start == end, we clean everything. 33445748Smckusick * 33545748Smckusick * The object must be locked. 33645748Smckusick */ 337*52197Smarc vm_object_page_clean(object, start, end, de_queue) 33845748Smckusick register vm_object_t object; 33945748Smckusick register vm_offset_t start; 34045748Smckusick register vm_offset_t end; 341*52197Smarc boolean_t de_queue; 34245748Smckusick { 34345748Smckusick register vm_page_t p; 34451771Smarc int onqueue; 34545748Smckusick 34648386Skarels if (object->pager == NULL) 34745748Smckusick return; 34845748Smckusick 34945748Smckusick again: 35051771Smarc /* 35151771Smarc * Wait until the pageout daemon is through with the object. 35251771Smarc */ 35351771Smarc while (object->paging_in_progress) { 35451771Smarc vm_object_sleep((int)object, object, FALSE); 35551771Smarc vm_object_lock(object); 35651771Smarc } 35751771Smarc /* 35851771Smarc * Loop through the object page list cleaning as necessary. 35951771Smarc */ 36045748Smckusick p = (vm_page_t) queue_first(&object->memq); 36145748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 36245748Smckusick if (start == end || 36345748Smckusick p->offset >= start && p->offset < end) { 36445748Smckusick if (p->clean && pmap_is_modified(VM_PAGE_TO_PHYS(p))) 36545748Smckusick p->clean = FALSE; 36651771Smarc /* 36751771Smarc * Remove the page from any paging queue. 36851771Smarc * This needs to be done if either we have been 36951771Smarc * explicitly asked to do so or it is about to 37051771Smarc * be cleaned (see comment below). 37151771Smarc */ 372*52197Smarc if (de_queue || !p->clean) { 37351771Smarc vm_page_lock_queues(); 37451771Smarc if (p->active) { 37551771Smarc queue_remove(&vm_page_queue_active, 37651771Smarc p, vm_page_t, pageq); 37751771Smarc p->active = FALSE; 37851771Smarc cnt.v_active_count--; 37951771Smarc onqueue = 1; 38051771Smarc } else if (p->inactive) { 38151771Smarc queue_remove(&vm_page_queue_inactive, 38251771Smarc p, vm_page_t, pageq); 38351771Smarc p->inactive = FALSE; 38451771Smarc cnt.v_inactive_count--; 38551771Smarc onqueue = -1; 38651771Smarc } else 38751771Smarc onqueue = 0; 38851771Smarc vm_page_unlock_queues(); 38951771Smarc } 39051771Smarc /* 39151771Smarc * To ensure the state of the page doesn't change 39251771Smarc * during the clean operation we do two things. 39351771Smarc * First we set the busy bit and invalidate all 39451771Smarc * mappings to ensure that thread accesses to the 39551771Smarc * page block (in vm_fault). Second, we remove 39651771Smarc * the page from any paging queue to foil the 39751771Smarc * pageout daemon (vm_pageout_scan). 39851771Smarc */ 39949292Shibler pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); 40045748Smckusick if (!p->clean) { 40145748Smckusick p->busy = TRUE; 40245748Smckusick object->paging_in_progress++; 40345748Smckusick vm_object_unlock(object); 40445748Smckusick (void) vm_pager_put(object->pager, p, TRUE); 40545748Smckusick vm_object_lock(object); 40645748Smckusick object->paging_in_progress--; 407*52197Smarc if (!de_queue && onqueue) { 40851771Smarc vm_page_lock_queues(); 40951771Smarc if (onqueue > 0) 41051771Smarc vm_page_activate(p); 41151771Smarc else 41251771Smarc vm_page_deactivate(p); 41351771Smarc vm_page_unlock_queues(); 41451771Smarc } 41545748Smckusick p->busy = FALSE; 41645748Smckusick PAGE_WAKEUP(p); 41745748Smckusick goto again; 41845748Smckusick } 41945748Smckusick } 42045748Smckusick p = (vm_page_t) queue_next(&p->listq); 42145748Smckusick } 42245748Smckusick } 42345748Smckusick 42445748Smckusick /* 42545748Smckusick * vm_object_deactivate_pages 42645748Smckusick * 42745748Smckusick * Deactivate all pages in the specified object. (Keep its pages 42845748Smckusick * in memory even though it is no longer referenced.) 42945748Smckusick * 43045748Smckusick * The object must be locked. 43145748Smckusick */ 43245748Smckusick vm_object_deactivate_pages(object) 43345748Smckusick register vm_object_t object; 43445748Smckusick { 43545748Smckusick register vm_page_t p, next; 43645748Smckusick 43745748Smckusick p = (vm_page_t) queue_first(&object->memq); 43845748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 43945748Smckusick next = (vm_page_t) queue_next(&p->listq); 44045748Smckusick vm_page_lock_queues(); 44145748Smckusick vm_page_deactivate(p); 44245748Smckusick vm_page_unlock_queues(); 44345748Smckusick p = next; 44445748Smckusick } 44545748Smckusick } 44645748Smckusick 44745748Smckusick /* 44845748Smckusick * Trim the object cache to size. 44945748Smckusick */ 45045748Smckusick vm_object_cache_trim() 45145748Smckusick { 45245748Smckusick register vm_object_t object; 45345748Smckusick 45445748Smckusick vm_object_cache_lock(); 45545748Smckusick while (vm_object_cached > vm_cache_max) { 45645748Smckusick object = (vm_object_t) queue_first(&vm_object_cached_list); 45745748Smckusick vm_object_cache_unlock(); 45845748Smckusick 45945748Smckusick if (object != vm_object_lookup(object->pager)) 46045748Smckusick panic("vm_object_deactivate: I'm sooo confused."); 46145748Smckusick 46245748Smckusick pager_cache(object, FALSE); 46345748Smckusick 46445748Smckusick vm_object_cache_lock(); 46545748Smckusick } 46645748Smckusick vm_object_cache_unlock(); 46745748Smckusick } 46845748Smckusick 46945748Smckusick 47045748Smckusick /* 47145748Smckusick * vm_object_shutdown() 47245748Smckusick * 47345748Smckusick * Shut down the object system. Unfortunately, while we 47445748Smckusick * may be trying to do this, init is happily waiting for 47545748Smckusick * processes to exit, and therefore will be causing some objects 47645748Smckusick * to be deallocated. To handle this, we gain a fake reference 47745748Smckusick * to all objects we release paging areas for. This will prevent 47845748Smckusick * a duplicate deallocation. This routine is probably full of 47945748Smckusick * race conditions! 48045748Smckusick */ 48145748Smckusick 48245748Smckusick void vm_object_shutdown() 48345748Smckusick { 48445748Smckusick register vm_object_t object; 48545748Smckusick 48645748Smckusick /* 48745748Smckusick * Clean up the object cache *before* we screw up the reference 48845748Smckusick * counts on all of the objects. 48945748Smckusick */ 49045748Smckusick 49145748Smckusick vm_object_cache_clear(); 49245748Smckusick 49345748Smckusick printf("free paging spaces: "); 49445748Smckusick 49545748Smckusick /* 49645748Smckusick * First we gain a reference to each object so that 49745748Smckusick * no one else will deallocate them. 49845748Smckusick */ 49945748Smckusick 50045748Smckusick simple_lock(&vm_object_list_lock); 50145748Smckusick object = (vm_object_t) queue_first(&vm_object_list); 50245748Smckusick while (!queue_end(&vm_object_list, (queue_entry_t) object)) { 50345748Smckusick vm_object_reference(object); 50445748Smckusick object = (vm_object_t) queue_next(&object->object_list); 50545748Smckusick } 50645748Smckusick simple_unlock(&vm_object_list_lock); 50745748Smckusick 50845748Smckusick /* 50945748Smckusick * Now we deallocate all the paging areas. We don't need 51045748Smckusick * to lock anything because we've reduced to a single 51145748Smckusick * processor while shutting down. This also assumes that 51245748Smckusick * no new objects are being created. 51345748Smckusick */ 51445748Smckusick 51545748Smckusick object = (vm_object_t) queue_first(&vm_object_list); 51645748Smckusick while (!queue_end(&vm_object_list, (queue_entry_t) object)) { 51748386Skarels if (object->pager != NULL) 51845748Smckusick vm_pager_deallocate(object->pager); 51945748Smckusick object = (vm_object_t) queue_next(&object->object_list); 52045748Smckusick printf("."); 52145748Smckusick } 52245748Smckusick printf("done.\n"); 52345748Smckusick } 52445748Smckusick 52545748Smckusick /* 52645748Smckusick * vm_object_pmap_copy: 52745748Smckusick * 52845748Smckusick * Makes all physical pages in the specified 52945748Smckusick * object range copy-on-write. No writeable 53045748Smckusick * references to these pages should remain. 53145748Smckusick * 53245748Smckusick * The object must *not* be locked. 53345748Smckusick */ 53445748Smckusick void vm_object_pmap_copy(object, start, end) 53545748Smckusick register vm_object_t object; 53645748Smckusick register vm_offset_t start; 53745748Smckusick register vm_offset_t end; 53845748Smckusick { 53945748Smckusick register vm_page_t p; 54045748Smckusick 54148386Skarels if (object == NULL) 54245748Smckusick return; 54345748Smckusick 54445748Smckusick vm_object_lock(object); 54545748Smckusick p = (vm_page_t) queue_first(&object->memq); 54645748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 54745748Smckusick if ((start <= p->offset) && (p->offset < end)) { 54849292Shibler pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_READ); 54949292Shibler p->copy_on_write = TRUE; 55045748Smckusick } 55145748Smckusick p = (vm_page_t) queue_next(&p->listq); 55245748Smckusick } 55345748Smckusick vm_object_unlock(object); 55445748Smckusick } 55545748Smckusick 55645748Smckusick /* 55745748Smckusick * vm_object_pmap_remove: 55845748Smckusick * 55945748Smckusick * Removes all physical pages in the specified 56045748Smckusick * object range from all physical maps. 56145748Smckusick * 56245748Smckusick * The object must *not* be locked. 56345748Smckusick */ 56445748Smckusick void vm_object_pmap_remove(object, start, end) 56545748Smckusick register vm_object_t object; 56645748Smckusick register vm_offset_t start; 56745748Smckusick register vm_offset_t end; 56845748Smckusick { 56945748Smckusick register vm_page_t p; 57045748Smckusick 57148386Skarels if (object == NULL) 57245748Smckusick return; 57345748Smckusick 57445748Smckusick vm_object_lock(object); 57545748Smckusick p = (vm_page_t) queue_first(&object->memq); 57645748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 57749292Shibler if ((start <= p->offset) && (p->offset < end)) 57849292Shibler pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); 57945748Smckusick p = (vm_page_t) queue_next(&p->listq); 58045748Smckusick } 58145748Smckusick vm_object_unlock(object); 58245748Smckusick } 58345748Smckusick 58445748Smckusick /* 58545748Smckusick * vm_object_copy: 58645748Smckusick * 58745748Smckusick * Create a new object which is a copy of an existing 58845748Smckusick * object, and mark all of the pages in the existing 58945748Smckusick * object 'copy-on-write'. The new object has one reference. 59045748Smckusick * Returns the new object. 59145748Smckusick * 59245748Smckusick * May defer the copy until later if the object is not backed 59345748Smckusick * up by a non-default pager. 59445748Smckusick */ 59545748Smckusick void vm_object_copy(src_object, src_offset, size, 59645748Smckusick dst_object, dst_offset, src_needs_copy) 59745748Smckusick register vm_object_t src_object; 59845748Smckusick vm_offset_t src_offset; 59945748Smckusick vm_size_t size; 60045748Smckusick vm_object_t *dst_object; /* OUT */ 60145748Smckusick vm_offset_t *dst_offset; /* OUT */ 60245748Smckusick boolean_t *src_needs_copy; /* OUT */ 60345748Smckusick { 60445748Smckusick register vm_object_t new_copy; 60545748Smckusick register vm_object_t old_copy; 60645748Smckusick vm_offset_t new_start, new_end; 60745748Smckusick 60845748Smckusick register vm_page_t p; 60945748Smckusick 61048386Skarels if (src_object == NULL) { 61145748Smckusick /* 61245748Smckusick * Nothing to copy 61345748Smckusick */ 61448386Skarels *dst_object = NULL; 61545748Smckusick *dst_offset = 0; 61645748Smckusick *src_needs_copy = FALSE; 61745748Smckusick return; 61845748Smckusick } 61945748Smckusick 62045748Smckusick /* 62145748Smckusick * If the object's pager is null_pager or the 62245748Smckusick * default pager, we don't have to make a copy 62345748Smckusick * of it. Instead, we set the needs copy flag and 62445748Smckusick * make a shadow later. 62545748Smckusick */ 62645748Smckusick 62745748Smckusick vm_object_lock(src_object); 62848386Skarels if (src_object->pager == NULL || 62950917Smckusick (src_object->flags & OBJ_INTERNAL)) { 63045748Smckusick 63145748Smckusick /* 63245748Smckusick * Make another reference to the object 63345748Smckusick */ 63445748Smckusick src_object->ref_count++; 63545748Smckusick 63645748Smckusick /* 63745748Smckusick * Mark all of the pages copy-on-write. 63845748Smckusick */ 63945748Smckusick for (p = (vm_page_t) queue_first(&src_object->memq); 64045748Smckusick !queue_end(&src_object->memq, (queue_entry_t)p); 64145748Smckusick p = (vm_page_t) queue_next(&p->listq)) { 64245748Smckusick if (src_offset <= p->offset && 64345748Smckusick p->offset < src_offset + size) 64445748Smckusick p->copy_on_write = TRUE; 64545748Smckusick } 64645748Smckusick vm_object_unlock(src_object); 64745748Smckusick 64845748Smckusick *dst_object = src_object; 64945748Smckusick *dst_offset = src_offset; 65045748Smckusick 65145748Smckusick /* 65245748Smckusick * Must make a shadow when write is desired 65345748Smckusick */ 65445748Smckusick *src_needs_copy = TRUE; 65545748Smckusick return; 65645748Smckusick } 65745748Smckusick 65845748Smckusick /* 65945748Smckusick * Try to collapse the object before copying it. 66045748Smckusick */ 66145748Smckusick vm_object_collapse(src_object); 66245748Smckusick 66345748Smckusick /* 66445748Smckusick * If the object has a pager, the pager wants to 66545748Smckusick * see all of the changes. We need a copy-object 66645748Smckusick * for the changed pages. 66745748Smckusick * 66845748Smckusick * If there is a copy-object, and it is empty, 66945748Smckusick * no changes have been made to the object since the 67045748Smckusick * copy-object was made. We can use the same copy- 67145748Smckusick * object. 67245748Smckusick */ 67345748Smckusick 67445748Smckusick Retry1: 67545748Smckusick old_copy = src_object->copy; 67648386Skarels if (old_copy != NULL) { 67745748Smckusick /* 67845748Smckusick * Try to get the locks (out of order) 67945748Smckusick */ 68045748Smckusick if (!vm_object_lock_try(old_copy)) { 68145748Smckusick vm_object_unlock(src_object); 68245748Smckusick 68345748Smckusick /* should spin a bit here... */ 68445748Smckusick vm_object_lock(src_object); 68545748Smckusick goto Retry1; 68645748Smckusick } 68745748Smckusick 68845748Smckusick if (old_copy->resident_page_count == 0 && 68948386Skarels old_copy->pager == NULL) { 69045748Smckusick /* 69145748Smckusick * Return another reference to 69245748Smckusick * the existing copy-object. 69345748Smckusick */ 69445748Smckusick old_copy->ref_count++; 69545748Smckusick vm_object_unlock(old_copy); 69645748Smckusick vm_object_unlock(src_object); 69745748Smckusick *dst_object = old_copy; 69845748Smckusick *dst_offset = src_offset; 69945748Smckusick *src_needs_copy = FALSE; 70045748Smckusick return; 70145748Smckusick } 70245748Smckusick vm_object_unlock(old_copy); 70345748Smckusick } 70445748Smckusick vm_object_unlock(src_object); 70545748Smckusick 70645748Smckusick /* 70745748Smckusick * If the object has a pager, the pager wants 70845748Smckusick * to see all of the changes. We must make 70945748Smckusick * a copy-object and put the changed pages there. 71045748Smckusick * 71145748Smckusick * The copy-object is always made large enough to 71245748Smckusick * completely shadow the original object, since 71345748Smckusick * it may have several users who want to shadow 71445748Smckusick * the original object at different points. 71545748Smckusick */ 71645748Smckusick 71745748Smckusick new_copy = vm_object_allocate(src_object->size); 71845748Smckusick 71945748Smckusick Retry2: 72045748Smckusick vm_object_lock(src_object); 72145748Smckusick /* 72245748Smckusick * Copy object may have changed while we were unlocked 72345748Smckusick */ 72445748Smckusick old_copy = src_object->copy; 72548386Skarels if (old_copy != NULL) { 72645748Smckusick /* 72745748Smckusick * Try to get the locks (out of order) 72845748Smckusick */ 72945748Smckusick if (!vm_object_lock_try(old_copy)) { 73045748Smckusick vm_object_unlock(src_object); 73145748Smckusick goto Retry2; 73245748Smckusick } 73345748Smckusick 73445748Smckusick /* 73545748Smckusick * Consistency check 73645748Smckusick */ 73745748Smckusick if (old_copy->shadow != src_object || 73845748Smckusick old_copy->shadow_offset != (vm_offset_t) 0) 73945748Smckusick panic("vm_object_copy: copy/shadow inconsistency"); 74045748Smckusick 74145748Smckusick /* 74245748Smckusick * Make the old copy-object shadow the new one. 74345748Smckusick * It will receive no more pages from the original 74445748Smckusick * object. 74545748Smckusick */ 74645748Smckusick 74745748Smckusick src_object->ref_count--; /* remove ref. from old_copy */ 74845748Smckusick old_copy->shadow = new_copy; 74945748Smckusick new_copy->ref_count++; /* locking not needed - we 75045748Smckusick have the only pointer */ 75145748Smckusick vm_object_unlock(old_copy); /* done with old_copy */ 75245748Smckusick } 75345748Smckusick 75445748Smckusick new_start = (vm_offset_t) 0; /* always shadow original at 0 */ 75545748Smckusick new_end = (vm_offset_t) new_copy->size; /* for the whole object */ 75645748Smckusick 75745748Smckusick /* 75845748Smckusick * Point the new copy at the existing object. 75945748Smckusick */ 76045748Smckusick 76145748Smckusick new_copy->shadow = src_object; 76245748Smckusick new_copy->shadow_offset = new_start; 76345748Smckusick src_object->ref_count++; 76445748Smckusick src_object->copy = new_copy; 76545748Smckusick 76645748Smckusick /* 76745748Smckusick * Mark all the affected pages of the existing object 76845748Smckusick * copy-on-write. 76945748Smckusick */ 77045748Smckusick p = (vm_page_t) queue_first(&src_object->memq); 77145748Smckusick while (!queue_end(&src_object->memq, (queue_entry_t) p)) { 77249292Shibler if ((new_start <= p->offset) && (p->offset < new_end)) 77345748Smckusick p->copy_on_write = TRUE; 77445748Smckusick p = (vm_page_t) queue_next(&p->listq); 77545748Smckusick } 77645748Smckusick 77745748Smckusick vm_object_unlock(src_object); 77845748Smckusick 77945748Smckusick *dst_object = new_copy; 78045748Smckusick *dst_offset = src_offset - new_start; 78145748Smckusick *src_needs_copy = FALSE; 78245748Smckusick } 78345748Smckusick 78445748Smckusick /* 78545748Smckusick * vm_object_shadow: 78645748Smckusick * 78745748Smckusick * Create a new object which is backed by the 78845748Smckusick * specified existing object range. The source 78945748Smckusick * object reference is deallocated. 79045748Smckusick * 79145748Smckusick * The new object and offset into that object 79245748Smckusick * are returned in the source parameters. 79345748Smckusick */ 79445748Smckusick 79545748Smckusick void vm_object_shadow(object, offset, length) 79645748Smckusick vm_object_t *object; /* IN/OUT */ 79745748Smckusick vm_offset_t *offset; /* IN/OUT */ 79845748Smckusick vm_size_t length; 79945748Smckusick { 80045748Smckusick register vm_object_t source; 80145748Smckusick register vm_object_t result; 80245748Smckusick 80345748Smckusick source = *object; 80445748Smckusick 80545748Smckusick /* 80645748Smckusick * Allocate a new object with the given length 80745748Smckusick */ 80845748Smckusick 80948386Skarels if ((result = vm_object_allocate(length)) == NULL) 81045748Smckusick panic("vm_object_shadow: no object for shadowing"); 81145748Smckusick 81245748Smckusick /* 81345748Smckusick * The new object shadows the source object, adding 81445748Smckusick * a reference to it. Our caller changes his reference 81545748Smckusick * to point to the new object, removing a reference to 81645748Smckusick * the source object. Net result: no change of reference 81745748Smckusick * count. 81845748Smckusick */ 81945748Smckusick result->shadow = source; 82045748Smckusick 82145748Smckusick /* 82245748Smckusick * Store the offset into the source object, 82345748Smckusick * and fix up the offset into the new object. 82445748Smckusick */ 82545748Smckusick 82645748Smckusick result->shadow_offset = *offset; 82745748Smckusick 82845748Smckusick /* 82945748Smckusick * Return the new things 83045748Smckusick */ 83145748Smckusick 83245748Smckusick *offset = 0; 83345748Smckusick *object = result; 83445748Smckusick } 83545748Smckusick 83645748Smckusick /* 83745748Smckusick * Set the specified object's pager to the specified pager. 83845748Smckusick */ 83945748Smckusick 84045748Smckusick void vm_object_setpager(object, pager, paging_offset, 84145748Smckusick read_only) 84245748Smckusick vm_object_t object; 84345748Smckusick vm_pager_t pager; 84445748Smckusick vm_offset_t paging_offset; 84545748Smckusick boolean_t read_only; 84645748Smckusick { 84745748Smckusick #ifdef lint 84845748Smckusick read_only++; /* No longer used */ 84945748Smckusick #endif lint 85045748Smckusick 85145748Smckusick vm_object_lock(object); /* XXX ? */ 85245748Smckusick object->pager = pager; 85345748Smckusick object->paging_offset = paging_offset; 85445748Smckusick vm_object_unlock(object); /* XXX ? */ 85545748Smckusick } 85645748Smckusick 85745748Smckusick /* 85845748Smckusick * vm_object_hash hashes the pager/id pair. 85945748Smckusick */ 86045748Smckusick 86145748Smckusick #define vm_object_hash(pager) \ 86245748Smckusick (((unsigned)pager)%VM_OBJECT_HASH_COUNT) 86345748Smckusick 86445748Smckusick /* 86545748Smckusick * vm_object_lookup looks in the object cache for an object with the 86645748Smckusick * specified pager and paging id. 86745748Smckusick */ 86845748Smckusick 86945748Smckusick vm_object_t vm_object_lookup(pager) 87045748Smckusick vm_pager_t pager; 87145748Smckusick { 87245748Smckusick register queue_t bucket; 87345748Smckusick register vm_object_hash_entry_t entry; 87445748Smckusick vm_object_t object; 87545748Smckusick 87645748Smckusick bucket = &vm_object_hashtable[vm_object_hash(pager)]; 87745748Smckusick 87845748Smckusick vm_object_cache_lock(); 87945748Smckusick 88045748Smckusick entry = (vm_object_hash_entry_t) queue_first(bucket); 88145748Smckusick while (!queue_end(bucket, (queue_entry_t) entry)) { 88245748Smckusick object = entry->object; 88345748Smckusick if (object->pager == pager) { 88445748Smckusick vm_object_lock(object); 88545748Smckusick if (object->ref_count == 0) { 88645748Smckusick queue_remove(&vm_object_cached_list, object, 88745748Smckusick vm_object_t, cached_list); 88845748Smckusick vm_object_cached--; 88945748Smckusick } 89045748Smckusick object->ref_count++; 89145748Smckusick vm_object_unlock(object); 89245748Smckusick vm_object_cache_unlock(); 89345748Smckusick return(object); 89445748Smckusick } 89545748Smckusick entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links); 89645748Smckusick } 89745748Smckusick 89845748Smckusick vm_object_cache_unlock(); 89948386Skarels return(NULL); 90045748Smckusick } 90145748Smckusick 90245748Smckusick /* 90345748Smckusick * vm_object_enter enters the specified object/pager/id into 90445748Smckusick * the hash table. 90545748Smckusick */ 90645748Smckusick 90745748Smckusick void vm_object_enter(object, pager) 90845748Smckusick vm_object_t object; 90945748Smckusick vm_pager_t pager; 91045748Smckusick { 91145748Smckusick register queue_t bucket; 91245748Smckusick register vm_object_hash_entry_t entry; 91345748Smckusick 91445748Smckusick /* 91545748Smckusick * We don't cache null objects, and we can't cache 91645748Smckusick * objects with the null pager. 91745748Smckusick */ 91845748Smckusick 91948386Skarels if (object == NULL) 92045748Smckusick return; 92148386Skarels if (pager == NULL) 92245748Smckusick return; 92345748Smckusick 92445748Smckusick bucket = &vm_object_hashtable[vm_object_hash(pager)]; 92545748Smckusick entry = (vm_object_hash_entry_t) 92645748Smckusick malloc((u_long)sizeof *entry, M_VMOBJHASH, M_WAITOK); 92745748Smckusick entry->object = object; 92850917Smckusick object->flags |= OBJ_CANPERSIST; 92945748Smckusick 93045748Smckusick vm_object_cache_lock(); 93145748Smckusick queue_enter(bucket, entry, vm_object_hash_entry_t, hash_links); 93245748Smckusick vm_object_cache_unlock(); 93345748Smckusick } 93445748Smckusick 93545748Smckusick /* 93645748Smckusick * vm_object_remove: 93745748Smckusick * 93845748Smckusick * Remove the pager from the hash table. 93945748Smckusick * Note: This assumes that the object cache 94045748Smckusick * is locked. XXX this should be fixed 94145748Smckusick * by reorganizing vm_object_deallocate. 94245748Smckusick */ 94345748Smckusick vm_object_remove(pager) 94445748Smckusick register vm_pager_t pager; 94545748Smckusick { 94645748Smckusick register queue_t bucket; 94745748Smckusick register vm_object_hash_entry_t entry; 94845748Smckusick register vm_object_t object; 94945748Smckusick 95045748Smckusick bucket = &vm_object_hashtable[vm_object_hash(pager)]; 95145748Smckusick 95245748Smckusick entry = (vm_object_hash_entry_t) queue_first(bucket); 95345748Smckusick while (!queue_end(bucket, (queue_entry_t) entry)) { 95445748Smckusick object = entry->object; 95545748Smckusick if (object->pager == pager) { 95645748Smckusick queue_remove(bucket, entry, vm_object_hash_entry_t, 95745748Smckusick hash_links); 95845748Smckusick free((caddr_t)entry, M_VMOBJHASH); 95945748Smckusick break; 96045748Smckusick } 96145748Smckusick entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links); 96245748Smckusick } 96345748Smckusick } 96445748Smckusick 96545748Smckusick /* 96645748Smckusick * vm_object_cache_clear removes all objects from the cache. 96745748Smckusick * 96845748Smckusick */ 96945748Smckusick 97045748Smckusick void vm_object_cache_clear() 97145748Smckusick { 97245748Smckusick register vm_object_t object; 97345748Smckusick 97445748Smckusick /* 97545748Smckusick * Remove each object in the cache by scanning down the 97645748Smckusick * list of cached objects. 97745748Smckusick */ 97845748Smckusick vm_object_cache_lock(); 97945748Smckusick while (!queue_empty(&vm_object_cached_list)) { 98045748Smckusick object = (vm_object_t) queue_first(&vm_object_cached_list); 98145748Smckusick vm_object_cache_unlock(); 98245748Smckusick 98345748Smckusick /* 98445748Smckusick * Note: it is important that we use vm_object_lookup 98545748Smckusick * to gain a reference, and not vm_object_reference, because 98645748Smckusick * the logic for removing an object from the cache lies in 98745748Smckusick * lookup. 98845748Smckusick */ 98945748Smckusick if (object != vm_object_lookup(object->pager)) 99045748Smckusick panic("vm_object_cache_clear: I'm sooo confused."); 99145748Smckusick pager_cache(object, FALSE); 99245748Smckusick 99345748Smckusick vm_object_cache_lock(); 99445748Smckusick } 99545748Smckusick vm_object_cache_unlock(); 99645748Smckusick } 99745748Smckusick 99845748Smckusick boolean_t vm_object_collapse_allowed = TRUE; 99945748Smckusick /* 100045748Smckusick * vm_object_collapse: 100145748Smckusick * 100245748Smckusick * Collapse an object with the object backing it. 100345748Smckusick * Pages in the backing object are moved into the 100445748Smckusick * parent, and the backing object is deallocated. 100545748Smckusick * 100645748Smckusick * Requires that the object be locked and the page 100745748Smckusick * queues be unlocked. 100845748Smckusick * 100945748Smckusick */ 101045748Smckusick void vm_object_collapse(object) 101145748Smckusick register vm_object_t object; 101245748Smckusick 101345748Smckusick { 101445748Smckusick register vm_object_t backing_object; 101545748Smckusick register vm_offset_t backing_offset; 101645748Smckusick register vm_size_t size; 101745748Smckusick register vm_offset_t new_offset; 101845748Smckusick register vm_page_t p, pp; 101945748Smckusick 102045748Smckusick if (!vm_object_collapse_allowed) 102145748Smckusick return; 102245748Smckusick 102345748Smckusick while (TRUE) { 102445748Smckusick /* 102545748Smckusick * Verify that the conditions are right for collapse: 102645748Smckusick * 102745748Smckusick * The object exists and no pages in it are currently 102845748Smckusick * being paged out (or have ever been paged out). 102945748Smckusick */ 103048386Skarels if (object == NULL || 103145748Smckusick object->paging_in_progress != 0 || 103248386Skarels object->pager != NULL) 103345748Smckusick return; 103445748Smckusick 103545748Smckusick /* 103645748Smckusick * There is a backing object, and 103745748Smckusick */ 103845748Smckusick 103948386Skarels if ((backing_object = object->shadow) == NULL) 104045748Smckusick return; 104145748Smckusick 104245748Smckusick vm_object_lock(backing_object); 104345748Smckusick /* 104445748Smckusick * ... 104545748Smckusick * The backing object is not read_only, 104645748Smckusick * and no pages in the backing object are 104745748Smckusick * currently being paged out. 104845748Smckusick * The backing object is internal. 104945748Smckusick */ 105045748Smckusick 105150917Smckusick if ((backing_object->flags & OBJ_INTERNAL) == 0 || 105245748Smckusick backing_object->paging_in_progress != 0) { 105345748Smckusick vm_object_unlock(backing_object); 105445748Smckusick return; 105545748Smckusick } 105645748Smckusick 105745748Smckusick /* 105845748Smckusick * The backing object can't be a copy-object: 105945748Smckusick * the shadow_offset for the copy-object must stay 106045748Smckusick * as 0. Furthermore (for the 'we have all the 106145748Smckusick * pages' case), if we bypass backing_object and 106245748Smckusick * just shadow the next object in the chain, old 106345748Smckusick * pages from that object would then have to be copied 106445748Smckusick * BOTH into the (former) backing_object and into the 106545748Smckusick * parent object. 106645748Smckusick */ 106748386Skarels if (backing_object->shadow != NULL && 106848386Skarels backing_object->shadow->copy != NULL) { 106945748Smckusick vm_object_unlock(backing_object); 107045748Smckusick return; 107145748Smckusick } 107245748Smckusick 107345748Smckusick /* 107445748Smckusick * We know that we can either collapse the backing 107545748Smckusick * object (if the parent is the only reference to 107645748Smckusick * it) or (perhaps) remove the parent's reference 107745748Smckusick * to it. 107845748Smckusick */ 107945748Smckusick 108045748Smckusick backing_offset = object->shadow_offset; 108145748Smckusick size = object->size; 108245748Smckusick 108345748Smckusick /* 108445748Smckusick * If there is exactly one reference to the backing 108545748Smckusick * object, we can collapse it into the parent. 108645748Smckusick */ 108745748Smckusick 108845748Smckusick if (backing_object->ref_count == 1) { 108945748Smckusick 109045748Smckusick /* 109145748Smckusick * We can collapse the backing object. 109245748Smckusick * 109345748Smckusick * Move all in-memory pages from backing_object 109445748Smckusick * to the parent. Pages that have been paged out 109545748Smckusick * will be overwritten by any of the parent's 109645748Smckusick * pages that shadow them. 109745748Smckusick */ 109845748Smckusick 109945748Smckusick while (!queue_empty(&backing_object->memq)) { 110045748Smckusick 110145748Smckusick p = (vm_page_t) 110245748Smckusick queue_first(&backing_object->memq); 110345748Smckusick 110445748Smckusick new_offset = (p->offset - backing_offset); 110545748Smckusick 110645748Smckusick /* 110745748Smckusick * If the parent has a page here, or if 110845748Smckusick * this page falls outside the parent, 110945748Smckusick * dispose of it. 111045748Smckusick * 111145748Smckusick * Otherwise, move it as planned. 111245748Smckusick */ 111345748Smckusick 111445748Smckusick if (p->offset < backing_offset || 111545748Smckusick new_offset >= size) { 111645748Smckusick vm_page_lock_queues(); 111745748Smckusick vm_page_free(p); 111845748Smckusick vm_page_unlock_queues(); 111945748Smckusick } else { 112045748Smckusick pp = vm_page_lookup(object, new_offset); 112148386Skarels if (pp != NULL && !pp->fake) { 112245748Smckusick vm_page_lock_queues(); 112345748Smckusick vm_page_free(p); 112445748Smckusick vm_page_unlock_queues(); 112545748Smckusick } 112645748Smckusick else { 112745748Smckusick if (pp) { 112845748Smckusick /* may be someone waiting for it */ 112945748Smckusick PAGE_WAKEUP(pp); 113045748Smckusick vm_page_lock_queues(); 113145748Smckusick vm_page_free(pp); 113245748Smckusick vm_page_unlock_queues(); 113345748Smckusick } 113445748Smckusick vm_page_rename(p, object, new_offset); 113545748Smckusick } 113645748Smckusick } 113745748Smckusick } 113845748Smckusick 113945748Smckusick /* 114045748Smckusick * Move the pager from backing_object to object. 114145748Smckusick * 114245748Smckusick * XXX We're only using part of the paging space 114345748Smckusick * for keeps now... we ought to discard the 114445748Smckusick * unused portion. 114545748Smckusick */ 114645748Smckusick 114745748Smckusick object->pager = backing_object->pager; 114845748Smckusick object->paging_offset += backing_offset; 114945748Smckusick 115048386Skarels backing_object->pager = NULL; 115145748Smckusick 115245748Smckusick /* 115345748Smckusick * Object now shadows whatever backing_object did. 115445748Smckusick * Note that the reference to backing_object->shadow 115545748Smckusick * moves from within backing_object to within object. 115645748Smckusick */ 115745748Smckusick 115845748Smckusick object->shadow = backing_object->shadow; 115945748Smckusick object->shadow_offset += backing_object->shadow_offset; 116048386Skarels if (object->shadow != NULL && 116148386Skarels object->shadow->copy != NULL) { 116245748Smckusick panic("vm_object_collapse: we collapsed a copy-object!"); 116345748Smckusick } 116445748Smckusick /* 116545748Smckusick * Discard backing_object. 116645748Smckusick * 116745748Smckusick * Since the backing object has no pages, no 116845748Smckusick * pager left, and no object references within it, 116945748Smckusick * all that is necessary is to dispose of it. 117045748Smckusick */ 117145748Smckusick 117245748Smckusick vm_object_unlock(backing_object); 117345748Smckusick 117445748Smckusick simple_lock(&vm_object_list_lock); 117545748Smckusick queue_remove(&vm_object_list, backing_object, 117645748Smckusick vm_object_t, object_list); 117745748Smckusick vm_object_count--; 117845748Smckusick simple_unlock(&vm_object_list_lock); 117945748Smckusick 118045748Smckusick free((caddr_t)backing_object, M_VMOBJ); 118145748Smckusick 118245748Smckusick object_collapses++; 118345748Smckusick } 118445748Smckusick else { 118545748Smckusick /* 118645748Smckusick * If all of the pages in the backing object are 118745748Smckusick * shadowed by the parent object, the parent 118845748Smckusick * object no longer has to shadow the backing 118945748Smckusick * object; it can shadow the next one in the 119045748Smckusick * chain. 119145748Smckusick * 119245748Smckusick * The backing object must not be paged out - we'd 119345748Smckusick * have to check all of the paged-out pages, as 119445748Smckusick * well. 119545748Smckusick */ 119645748Smckusick 119748386Skarels if (backing_object->pager != NULL) { 119845748Smckusick vm_object_unlock(backing_object); 119945748Smckusick return; 120045748Smckusick } 120145748Smckusick 120245748Smckusick /* 120345748Smckusick * Should have a check for a 'small' number 120445748Smckusick * of pages here. 120545748Smckusick */ 120645748Smckusick 120745748Smckusick p = (vm_page_t) queue_first(&backing_object->memq); 120845748Smckusick while (!queue_end(&backing_object->memq, 120945748Smckusick (queue_entry_t) p)) { 121045748Smckusick 121145748Smckusick new_offset = (p->offset - backing_offset); 121245748Smckusick 121345748Smckusick /* 121445748Smckusick * If the parent has a page here, or if 121545748Smckusick * this page falls outside the parent, 121645748Smckusick * keep going. 121745748Smckusick * 121845748Smckusick * Otherwise, the backing_object must be 121945748Smckusick * left in the chain. 122045748Smckusick */ 122145748Smckusick 122245748Smckusick if (p->offset >= backing_offset && 122345748Smckusick new_offset <= size && 122445748Smckusick ((pp = vm_page_lookup(object, new_offset)) 122548386Skarels == NULL || 122645748Smckusick pp->fake)) { 122745748Smckusick /* 122845748Smckusick * Page still needed. 122945748Smckusick * Can't go any further. 123045748Smckusick */ 123145748Smckusick vm_object_unlock(backing_object); 123245748Smckusick return; 123345748Smckusick } 123445748Smckusick p = (vm_page_t) queue_next(&p->listq); 123545748Smckusick } 123645748Smckusick 123745748Smckusick /* 123845748Smckusick * Make the parent shadow the next object 123945748Smckusick * in the chain. Deallocating backing_object 124045748Smckusick * will not remove it, since its reference 124145748Smckusick * count is at least 2. 124245748Smckusick */ 124345748Smckusick 124445748Smckusick vm_object_reference(object->shadow = backing_object->shadow); 124545748Smckusick object->shadow_offset += backing_object->shadow_offset; 124645748Smckusick 124745748Smckusick /* Drop the reference count on backing_object. 124845748Smckusick * Since its ref_count was at least 2, it 124945748Smckusick * will not vanish; so we don't need to call 125045748Smckusick * vm_object_deallocate. 125145748Smckusick */ 125245748Smckusick backing_object->ref_count--; 125345748Smckusick vm_object_unlock(backing_object); 125445748Smckusick 125545748Smckusick object_bypasses ++; 125645748Smckusick 125745748Smckusick } 125845748Smckusick 125945748Smckusick /* 126045748Smckusick * Try again with this object's new backing object. 126145748Smckusick */ 126245748Smckusick } 126345748Smckusick } 126445748Smckusick 126545748Smckusick /* 126645748Smckusick * vm_object_page_remove: [internal] 126745748Smckusick * 126845748Smckusick * Removes all physical pages in the specified 126945748Smckusick * object range from the object's list of pages. 127045748Smckusick * 127145748Smckusick * The object must be locked. 127245748Smckusick */ 127345748Smckusick void vm_object_page_remove(object, start, end) 127445748Smckusick register vm_object_t object; 127545748Smckusick register vm_offset_t start; 127645748Smckusick register vm_offset_t end; 127745748Smckusick { 127845748Smckusick register vm_page_t p, next; 127945748Smckusick 128048386Skarels if (object == NULL) 128145748Smckusick return; 128245748Smckusick 128345748Smckusick p = (vm_page_t) queue_first(&object->memq); 128445748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 128545748Smckusick next = (vm_page_t) queue_next(&p->listq); 128645748Smckusick if ((start <= p->offset) && (p->offset < end)) { 128749292Shibler pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); 128845748Smckusick vm_page_lock_queues(); 128945748Smckusick vm_page_free(p); 129045748Smckusick vm_page_unlock_queues(); 129145748Smckusick } 129245748Smckusick p = next; 129345748Smckusick } 129445748Smckusick } 129545748Smckusick 129645748Smckusick /* 129745748Smckusick * Routine: vm_object_coalesce 129845748Smckusick * Function: Coalesces two objects backing up adjoining 129945748Smckusick * regions of memory into a single object. 130045748Smckusick * 130145748Smckusick * returns TRUE if objects were combined. 130245748Smckusick * 130345748Smckusick * NOTE: Only works at the moment if the second object is NULL - 130445748Smckusick * if it's not, which object do we lock first? 130545748Smckusick * 130645748Smckusick * Parameters: 130745748Smckusick * prev_object First object to coalesce 130845748Smckusick * prev_offset Offset into prev_object 130945748Smckusick * next_object Second object into coalesce 131045748Smckusick * next_offset Offset into next_object 131145748Smckusick * 131245748Smckusick * prev_size Size of reference to prev_object 131345748Smckusick * next_size Size of reference to next_object 131445748Smckusick * 131545748Smckusick * Conditions: 131645748Smckusick * The object must *not* be locked. 131745748Smckusick */ 131845748Smckusick boolean_t vm_object_coalesce(prev_object, next_object, 131945748Smckusick prev_offset, next_offset, 132045748Smckusick prev_size, next_size) 132145748Smckusick 132245748Smckusick register vm_object_t prev_object; 132345748Smckusick vm_object_t next_object; 132445748Smckusick vm_offset_t prev_offset, next_offset; 132545748Smckusick vm_size_t prev_size, next_size; 132645748Smckusick { 132745748Smckusick vm_size_t newsize; 132845748Smckusick 132945748Smckusick #ifdef lint 133045748Smckusick next_offset++; 133145748Smckusick #endif lint 133245748Smckusick 133348386Skarels if (next_object != NULL) { 133445748Smckusick return(FALSE); 133545748Smckusick } 133645748Smckusick 133748386Skarels if (prev_object == NULL) { 133845748Smckusick return(TRUE); 133945748Smckusick } 134045748Smckusick 134145748Smckusick vm_object_lock(prev_object); 134245748Smckusick 134345748Smckusick /* 134445748Smckusick * Try to collapse the object first 134545748Smckusick */ 134645748Smckusick vm_object_collapse(prev_object); 134745748Smckusick 134845748Smckusick /* 134945748Smckusick * Can't coalesce if: 135045748Smckusick * . more than one reference 135145748Smckusick * . paged out 135245748Smckusick * . shadows another object 135345748Smckusick * . has a copy elsewhere 135445748Smckusick * (any of which mean that the pages not mapped to 135545748Smckusick * prev_entry may be in use anyway) 135645748Smckusick */ 135745748Smckusick 135845748Smckusick if (prev_object->ref_count > 1 || 135948386Skarels prev_object->pager != NULL || 136048386Skarels prev_object->shadow != NULL || 136148386Skarels prev_object->copy != NULL) { 136245748Smckusick vm_object_unlock(prev_object); 136345748Smckusick return(FALSE); 136445748Smckusick } 136545748Smckusick 136645748Smckusick /* 136745748Smckusick * Remove any pages that may still be in the object from 136845748Smckusick * a previous deallocation. 136945748Smckusick */ 137045748Smckusick 137145748Smckusick vm_object_page_remove(prev_object, 137245748Smckusick prev_offset + prev_size, 137345748Smckusick prev_offset + prev_size + next_size); 137445748Smckusick 137545748Smckusick /* 137645748Smckusick * Extend the object if necessary. 137745748Smckusick */ 137845748Smckusick newsize = prev_offset + prev_size + next_size; 137945748Smckusick if (newsize > prev_object->size) 138045748Smckusick prev_object->size = newsize; 138145748Smckusick 138245748Smckusick vm_object_unlock(prev_object); 138345748Smckusick return(TRUE); 138445748Smckusick } 138545748Smckusick 138645748Smckusick /* 138745748Smckusick * vm_object_print: [ debug ] 138845748Smckusick */ 138945748Smckusick void vm_object_print(object, full) 139045748Smckusick vm_object_t object; 139145748Smckusick boolean_t full; 139245748Smckusick { 139345748Smckusick register vm_page_t p; 139445748Smckusick extern indent; 139545748Smckusick 139645748Smckusick register int count; 139745748Smckusick 139848386Skarels if (object == NULL) 139945748Smckusick return; 140045748Smckusick 140145748Smckusick iprintf("Object 0x%x: size=0x%x, res=%d, ref=%d, ", 140245748Smckusick (int) object, (int) object->size, 140345748Smckusick object->resident_page_count, object->ref_count); 140445748Smckusick printf("pager=0x%x+0x%x, shadow=(0x%x)+0x%x\n", 140545748Smckusick (int) object->pager, (int) object->paging_offset, 140645748Smckusick (int) object->shadow, (int) object->shadow_offset); 140745748Smckusick printf("cache: next=0x%x, prev=0x%x\n", 140845748Smckusick object->cached_list.next, object->cached_list.prev); 140945748Smckusick 141045748Smckusick if (!full) 141145748Smckusick return; 141245748Smckusick 141345748Smckusick indent += 2; 141445748Smckusick count = 0; 141545748Smckusick p = (vm_page_t) queue_first(&object->memq); 141645748Smckusick while (!queue_end(&object->memq, (queue_entry_t) p)) { 141745748Smckusick if (count == 0) 141845748Smckusick iprintf("memory:="); 141945748Smckusick else if (count == 6) { 142045748Smckusick printf("\n"); 142145748Smckusick iprintf(" ..."); 142245748Smckusick count = 0; 142345748Smckusick } else 142445748Smckusick printf(","); 142545748Smckusick count++; 142645748Smckusick 142745748Smckusick printf("(off=0x%x,page=0x%x)", p->offset, VM_PAGE_TO_PHYS(p)); 142845748Smckusick p = (vm_page_t) queue_next(&p->listq); 142945748Smckusick } 143045748Smckusick if (count != 0) 143145748Smckusick printf("\n"); 143245748Smckusick indent -= 2; 143345748Smckusick } 1434