📄 vm_objec.c
字号:
/* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * The Mach Operating System project at Carnegie-Mellon University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)vm_object.c 8.7 (Berkeley) 5/11/95 * * * Copyright (c) 1987, 1990 Carnegie-Mellon University. * All rights reserved. * * Authors: Avadis Tevanian, Jr., Michael Wayne Young * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. *//* * Virtual memory object module. */#include <sys/param.h>#include <sys/systm.h>#include <sys/malloc.h>#include <vm/vm.h>#include <vm/vm_page.h>/* * Virtual memory objects maintain the actual data * associated with allocated virtual memory. A given * page of memory exists within exactly one object. * * An object is only deallocated when all "references" * are given up. Only one "reference" to a given * region of an object should be writeable. * * Associated with each object is a list of all resident * memory pages belonging to that object; this list is * maintained by the "vm_page" module, and locked by the object's * lock. * * Each object also records a "pager" routine which is * used to retrieve (and store) pages to the proper backing * storage. In addition, objects may be backed by other * objects from which they were virtual-copied. * * The only items within the object structure which are * modified after time of creation are: * reference count locked by object's lock * pager routine locked by object's lock * */struct vm_object kernel_object_store;struct vm_object kmem_object_store;#define VM_OBJECT_HASH_COUNT 157int vm_cache_max = 100; /* can patch if necessary */struct vm_object_hash_head vm_object_hashtable[VM_OBJECT_HASH_COUNT];long object_collapses = 0;long object_bypasses = 0;static void _vm_object_allocate __P((vm_size_t, vm_object_t));/* * vm_object_init: * * Initialize the VM objects module. */voidvm_object_init(size) vm_size_t size;{ register int i; TAILQ_INIT(&vm_object_cached_list); TAILQ_INIT(&vm_object_list); vm_object_count = 0; simple_lock_init(&vm_cache_lock); simple_lock_init(&vm_object_list_lock); for (i = 0; i < VM_OBJECT_HASH_COUNT; i++) TAILQ_INIT(&vm_object_hashtable[i]); kernel_object = &kernel_object_store; _vm_object_allocate(size, kernel_object); kmem_object = &kmem_object_store; _vm_object_allocate(VM_KMEM_SIZE + VM_MBUF_SIZE, kmem_object);}/* * vm_object_allocate: * * Returns a new object with the given size. */vm_object_tvm_object_allocate(size) vm_size_t size;{ register vm_object_t result; result = (vm_object_t) malloc((u_long)sizeof *result, M_VMOBJ, M_WAITOK); _vm_object_allocate(size, result); return(result);}static void_vm_object_allocate(size, object) vm_size_t size; register vm_object_t object;{ TAILQ_INIT(&object->memq); vm_object_lock_init(object); object->ref_count = 1; object->resident_page_count = 0; object->size = size; object->flags = OBJ_INTERNAL; /* vm_allocate_with_pager will reset */ object->paging_in_progress = 0; object->copy = NULL; /* * Object starts out read-write, with no pager. */ object->pager = NULL; object->paging_offset = 0; object->shadow = NULL; object->shadow_offset = (vm_offset_t) 0; simple_lock(&vm_object_list_lock); TAILQ_INSERT_TAIL(&vm_object_list, object, object_list); vm_object_count++; cnt.v_nzfod += atop(size); simple_unlock(&vm_object_list_lock);}/* * vm_object_reference: * * Gets another reference to the given object. */voidvm_object_reference(object) register vm_object_t object;{ if (object == NULL) return; vm_object_lock(object); object->ref_count++; vm_object_unlock(object);}/* * vm_object_deallocate: * * Release a reference to the specified object, * gained either through a vm_object_allocate * or a vm_object_reference call. When all references * are gone, storage associated with this object * may be relinquished. * * No object may be locked. */voidvm_object_deallocate(object) register vm_object_t object;{ vm_object_t temp; while (object != NULL) { /* * The cache holds a reference (uncounted) to * the object; we must lock it before removing * the object. */ vm_object_cache_lock(); /* * Lose the reference */ vm_object_lock(object); if (--(object->ref_count) != 0) { /* * If there are still references, then * we are done. */ vm_object_unlock(object); vm_object_cache_unlock(); return; } /* * See if this object can persist. If so, enter * it in the cache, then deactivate all of its * pages. */ if (object->flags & OBJ_CANPERSIST) { TAILQ_INSERT_TAIL(&vm_object_cached_list, object, cached_list); vm_object_cached++; vm_object_cache_unlock(); vm_object_deactivate_pages(object); vm_object_unlock(object); vm_object_cache_trim(); return; } /* * Make sure no one can look us up now. */ vm_object_remove(object->pager); vm_object_cache_unlock(); temp = object->shadow; vm_object_terminate(object); /* unlocks and deallocates object */ object = temp; }}/* * vm_object_terminate actually destroys the specified object, freeing * up all previously used resources. * * The object must be locked. */voidvm_object_terminate(object) register vm_object_t object;{ register vm_page_t p; vm_object_t shadow_object; /* * Detach the object from its shadow if we are the shadow's * copy. */ if ((shadow_object = object->shadow) != NULL) { vm_object_lock(shadow_object); if (shadow_object->copy == object) shadow_object->copy = NULL;#if 0 else if (shadow_object->copy != NULL) panic("vm_object_terminate: copy/shadow inconsistency");#endif vm_object_unlock(shadow_object); } /* * Wait until the pageout daemon is through with the object. */ while (object->paging_in_progress) { vm_object_sleep(object, object, FALSE); vm_object_lock(object); } /* * If not an internal object clean all the pages, removing them * from paging queues as we go. * * XXX need to do something in the event of a cleaning error. */ if ((object->flags & OBJ_INTERNAL) == 0) (void) vm_object_page_clean(object, 0, 0, TRUE, TRUE); /* * Now free the pages. * For internal objects, this also removes them from paging queues. */ while ((p = object->memq.tqh_first) != NULL) { VM_PAGE_CHECK(p); vm_page_lock_queues(); vm_page_free(p); cnt.v_pfree++; vm_page_unlock_queues(); } vm_object_unlock(object); /* * Let the pager know object is dead. */ if (object->pager != NULL) vm_pager_deallocate(object->pager); simple_lock(&vm_object_list_lock); TAILQ_REMOVE(&vm_object_list, object, object_list); vm_object_count--; simple_unlock(&vm_object_list_lock); /* * Free the space for the object. */ free((caddr_t)object, M_VMOBJ);}/* * vm_object_page_clean * * Clean all dirty pages in the specified range of object. * If syncio is TRUE, page cleaning is done synchronously. * If de_queue is TRUE, pages are removed from any paging queue * they were on, otherwise they are left on whatever queue they * were on before the cleaning operation began. * * Odd semantics: if start == end, we clean everything. * * The object must be locked. * * Returns TRUE if all was well, FALSE if there was a pager error * somewhere. We attempt to clean (and dequeue) all pages regardless * of where an error occurs. */boolean_tvm_object_page_clean(object, start, end, syncio, de_queue) register vm_object_t object; register vm_offset_t start; register vm_offset_t end; boolean_t syncio; boolean_t de_queue;{ register vm_page_t p; int onqueue; boolean_t noerror = TRUE; if (object == NULL) return (TRUE); /* * If it is an internal object and there is no pager, attempt to * allocate one. Note that vm_object_collapse may relocate one * from a collapsed object so we must recheck afterward. */ if ((object->flags & OBJ_INTERNAL) && object->pager == NULL) { vm_object_collapse(object); if (object->pager == NULL) { vm_pager_t pager; vm_object_unlock(object); pager = vm_pager_allocate(PG_DFLT, (caddr_t)0, object->size, VM_PROT_ALL, (vm_offset_t)0); if (pager) vm_object_setpager(object, pager, 0, FALSE); vm_object_lock(object); } } if (object->pager == NULL) return (FALSE);again: /* * Wait until the pageout daemon is through with the object. */ while (object->paging_in_progress) { vm_object_sleep(object, object, FALSE); vm_object_lock(object); } /* * Loop through the object page list cleaning as necessary. */ for (p = object->memq.tqh_first; p != NULL; p = p->listq.tqe_next) { if ((start == end || p->offset >= start && p->offset < end) && !(p->flags & PG_FICTITIOUS)) { if ((p->flags & PG_CLEAN) && pmap_is_modified(VM_PAGE_TO_PHYS(p))) p->flags &= ~PG_CLEAN; /* * Remove the page from any paging queue. * This needs to be done if either we have been * explicitly asked to do so or it is about to * be cleaned (see comment below). */ if (de_queue || !(p->flags & PG_CLEAN)) { vm_page_lock_queues(); if (p->flags & PG_ACTIVE) { TAILQ_REMOVE(&vm_page_queue_active, p, pageq); p->flags &= ~PG_ACTIVE; cnt.v_active_count--; onqueue = 1; } else if (p->flags & PG_INACTIVE) { TAILQ_REMOVE(&vm_page_queue_inactive, p, pageq); p->flags &= ~PG_INACTIVE; cnt.v_inactive_count--; onqueue = -1; } else onqueue = 0; vm_page_unlock_queues(); } /* * To ensure the state of the page doesn't change * during the clean operation we do two things. * First we set the busy bit and write-protect all * mappings to ensure that write accesses to the * page block (in vm_fault). Second, we remove * the page from any paging queue to foil the * pageout daemon (vm_pageout_scan). */ pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_READ); if (!(p->flags & PG_CLEAN)) { p->flags |= PG_BUSY; object->paging_in_progress++; vm_object_unlock(object); /* * XXX if put fails we mark the page as * clean to avoid an infinite loop. * Will loose changes to the page. */ if (vm_pager_put(object->pager, p, syncio)) { printf("%s: pager_put error\n", "vm_object_page_clean"); p->flags |= PG_CLEAN; noerror = FALSE; } vm_object_lock(object); object->paging_in_progress--; if (!de_queue && onqueue) { vm_page_lock_queues(); if (onqueue > 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -