📄 vm_objec.c
字号:
vm_page_activate(p); else vm_page_deactivate(p); vm_page_unlock_queues(); } p->flags &= ~PG_BUSY; PAGE_WAKEUP(p); goto again; } } } return (noerror);}/* * vm_object_deactivate_pages * * Deactivate all pages in the specified object. (Keep its pages * in memory even though it is no longer referenced.) * * The object must be locked. */voidvm_object_deactivate_pages(object) register vm_object_t object;{ register vm_page_t p, next; for (p = object->memq.tqh_first; p != NULL; p = next) { next = p->listq.tqe_next; vm_page_lock_queues(); vm_page_deactivate(p); vm_page_unlock_queues(); }}/* * Trim the object cache to size. */voidvm_object_cache_trim(){ register vm_object_t object; vm_object_cache_lock(); while (vm_object_cached > vm_cache_max) { object = vm_object_cached_list.tqh_first; vm_object_cache_unlock(); if (object != vm_object_lookup(object->pager)) panic("vm_object_deactivate: I'm sooo confused."); pager_cache(object, FALSE); vm_object_cache_lock(); } vm_object_cache_unlock();}/* * vm_object_pmap_copy: * * Makes all physical pages in the specified * object range copy-on-write. No writeable * references to these pages should remain. * * The object must *not* be locked. */voidvm_object_pmap_copy(object, start, end) register vm_object_t object; register vm_offset_t start; register vm_offset_t end;{ register vm_page_t p; if (object == NULL) return; vm_object_lock(object); for (p = object->memq.tqh_first; p != NULL; p = p->listq.tqe_next) { if ((start <= p->offset) && (p->offset < end)) { pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_READ); p->flags |= PG_COPYONWRITE; } } vm_object_unlock(object);}/* * vm_object_pmap_remove: * * Removes all physical pages in the specified * object range from all physical maps. * * The object must *not* be locked. */voidvm_object_pmap_remove(object, start, end) register vm_object_t object; register vm_offset_t start; register vm_offset_t end;{ register vm_page_t p; if (object == NULL) return; vm_object_lock(object); for (p = object->memq.tqh_first; p != NULL; p = p->listq.tqe_next) if ((start <= p->offset) && (p->offset < end)) pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); vm_object_unlock(object);}/* * vm_object_copy: * * Create a new object which is a copy of an existing * object, and mark all of the pages in the existing * object 'copy-on-write'. The new object has one reference. * Returns the new object. * * May defer the copy until later if the object is not backed * up by a non-default pager. */voidvm_object_copy(src_object, src_offset, size, dst_object, dst_offset, src_needs_copy) register vm_object_t src_object; vm_offset_t src_offset; vm_size_t size; vm_object_t *dst_object; /* OUT */ vm_offset_t *dst_offset; /* OUT */ boolean_t *src_needs_copy; /* OUT */{ register vm_object_t new_copy; register vm_object_t old_copy; vm_offset_t new_start, new_end; register vm_page_t p; if (src_object == NULL) { /* * Nothing to copy */ *dst_object = NULL; *dst_offset = 0; *src_needs_copy = FALSE; return; } /* * If the object's pager is null_pager or the * default pager, we don't have to make a copy * of it. Instead, we set the needs copy flag and * make a shadow later. */ vm_object_lock(src_object); if (src_object->pager == NULL || (src_object->flags & OBJ_INTERNAL)) { /* * Make another reference to the object */ src_object->ref_count++; /* * Mark all of the pages copy-on-write. */ for (p = src_object->memq.tqh_first; p; p = p->listq.tqe_next) if (src_offset <= p->offset && p->offset < src_offset + size) p->flags |= PG_COPYONWRITE; vm_object_unlock(src_object); *dst_object = src_object; *dst_offset = src_offset; /* * Must make a shadow when write is desired */ *src_needs_copy = TRUE; return; } /* * Try to collapse the object before copying it. */ vm_object_collapse(src_object); /* * If the object has a pager, the pager wants to * see all of the changes. We need a copy-object * for the changed pages. * * If there is a copy-object, and it is empty, * no changes have been made to the object since the * copy-object was made. We can use the same copy- * object. */ Retry1: old_copy = src_object->copy; if (old_copy != NULL) { /* * Try to get the locks (out of order) */ if (!vm_object_lock_try(old_copy)) { vm_object_unlock(src_object); /* should spin a bit here... */ vm_object_lock(src_object); goto Retry1; } if (old_copy->resident_page_count == 0 && old_copy->pager == NULL) { /* * Return another reference to * the existing copy-object. */ old_copy->ref_count++; vm_object_unlock(old_copy); vm_object_unlock(src_object); *dst_object = old_copy; *dst_offset = src_offset; *src_needs_copy = FALSE; return; } vm_object_unlock(old_copy); } vm_object_unlock(src_object); /* * If the object has a pager, the pager wants * to see all of the changes. We must make * a copy-object and put the changed pages there. * * The copy-object is always made large enough to * completely shadow the original object, since * it may have several users who want to shadow * the original object at different points. */ new_copy = vm_object_allocate(src_object->size); Retry2: vm_object_lock(src_object); /* * Copy object may have changed while we were unlocked */ old_copy = src_object->copy; if (old_copy != NULL) { /* * Try to get the locks (out of order) */ if (!vm_object_lock_try(old_copy)) { vm_object_unlock(src_object); goto Retry2; } /* * Consistency check */ if (old_copy->shadow != src_object || old_copy->shadow_offset != (vm_offset_t) 0) panic("vm_object_copy: copy/shadow inconsistency"); /* * Make the old copy-object shadow the new one. * It will receive no more pages from the original * object. */ src_object->ref_count--; /* remove ref. from old_copy */ old_copy->shadow = new_copy; new_copy->ref_count++; /* locking not needed - we have the only pointer */ vm_object_unlock(old_copy); /* done with old_copy */ } new_start = (vm_offset_t) 0; /* always shadow original at 0 */ new_end = (vm_offset_t) new_copy->size; /* for the whole object */ /* * Point the new copy at the existing object. */ new_copy->shadow = src_object; new_copy->shadow_offset = new_start; src_object->ref_count++; src_object->copy = new_copy; /* * Mark all the affected pages of the existing object * copy-on-write. */ for (p = src_object->memq.tqh_first; p != NULL; p = p->listq.tqe_next) if ((new_start <= p->offset) && (p->offset < new_end)) p->flags |= PG_COPYONWRITE; vm_object_unlock(src_object); *dst_object = new_copy; *dst_offset = src_offset - new_start; *src_needs_copy = FALSE;}/* * vm_object_shadow: * * Create a new object which is backed by the * specified existing object range. The source * object reference is deallocated. * * The new object and offset into that object * are returned in the source parameters. */voidvm_object_shadow(object, offset, length) vm_object_t *object; /* IN/OUT */ vm_offset_t *offset; /* IN/OUT */ vm_size_t length;{ register vm_object_t source; register vm_object_t result; source = *object; /* * Allocate a new object with the given length */ if ((result = vm_object_allocate(length)) == NULL) panic("vm_object_shadow: no object for shadowing"); /* * The new object shadows the source object, adding * a reference to it. Our caller changes his reference * to point to the new object, removing a reference to * the source object. Net result: no change of reference * count. */ result->shadow = source; /* * Store the offset into the source object, * and fix up the offset into the new object. */ result->shadow_offset = *offset; /* * Return the new things */ *offset = 0; *object = result;}/* * Set the specified object's pager to the specified pager. */voidvm_object_setpager(object, pager, paging_offset, read_only) vm_object_t object; vm_pager_t pager; vm_offset_t paging_offset; boolean_t read_only;{#ifdef lint read_only++; /* No longer used */#endif vm_object_lock(object); /* XXX ? */ object->pager = pager; object->paging_offset = paging_offset; vm_object_unlock(object); /* XXX ? */}/* * vm_object_hash hashes the pager/id pair. */#define vm_object_hash(pager) \ (((unsigned long)pager)%VM_OBJECT_HASH_COUNT)/* * vm_object_lookup looks in the object cache for an object with the * specified pager and paging id. */vm_object_tvm_object_lookup(pager) vm_pager_t pager;{ register vm_object_hash_entry_t entry; vm_object_t object; vm_object_cache_lock(); for (entry = vm_object_hashtable[vm_object_hash(pager)].tqh_first; entry != NULL; entry = entry->hash_links.tqe_next) { object = entry->object; if (object->pager == pager) { vm_object_lock(object); if (object->ref_count == 0) { TAILQ_REMOVE(&vm_object_cached_list, object, cached_list); vm_object_cached--; } object->ref_count++; vm_object_unlock(object); vm_object_cache_unlock(); return(object); } } vm_object_cache_unlock(); return(NULL);}/* * vm_object_enter enters the specified object/pager/id into * the hash table. */voidvm_object_enter(object, pager) vm_object_t object; vm_pager_t pager;{ struct vm_object_hash_head *bucket; register vm_object_hash_entry_t entry; /* * We don't cache null objects, and we can't cache * objects with the null pager. */ if (object == NULL) return; if (pager == NULL) return; bucket = &vm_object_hashtable[vm_object_hash(pager)]; entry = (vm_object_hash_entry_t) malloc((u_long)sizeof *entry, M_VMOBJHASH, M_WAITOK); entry->object = object; object->flags |= OBJ_CANPERSIST; vm_object_cache_lock(); TAILQ_INSERT_TAIL(bucket, entry, hash_links); vm_object_cache_unlock();}/* * vm_object_remove: * * Remove the pager from the hash table. * Note: This assumes that the object cache * is locked. XXX this should be fixed * by reorganizing vm_object_deallocate. */voidvm_object_remove(pager) register vm_pager_t pager;{ struct vm_object_hash_head *bucket; register vm_object_hash_entry_t entry; register vm_object_t object; bucket = &vm_object_hashtable[vm_object_hash(pager)]; for (entry = bucket->tqh_first; entry != NULL; entry = entry->hash_links.tqe_next) { object = entry->object;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -