diff options
Diffstat (limited to 'sys/vm/vm_object.c')
| -rw-r--r-- | sys/vm/vm_object.c | 566 |
1 files changed, 362 insertions, 204 deletions
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 56c9bd954d9e..5c463f64d6c5 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -34,10 +34,9 @@ * SUCH DAMAGE. * * from: @(#)vm_object.c 7.4 (Berkeley) 5/7/91 - * $Id: vm_object.c,v 1.6.2.1 1993/11/14 21:20:24 rgrimes Exp $ - */ - -/* + * $Id: vm_object.c,v 1.21.2.1 1994/03/07 02:22:13 rgrimes Exp $ + * + * * Copyright (c) 1987, 1990 Carnegie-Mellon University. * All rights reserved. * @@ -69,12 +68,19 @@ */ #include "ddb.h" - #include "param.h" #include "malloc.h" +#include "systm.h" #include "vm.h" #include "vm_page.h" +#include "proc.h" + + +static void _vm_object_allocate(vm_size_t, vm_object_t); +void vm_object_deactivate_pages(vm_object_t); +static void vm_object_cache_trim(void); +static void vm_object_remove(vm_pager_t); /* * Virtual memory objects maintain the actual data @@ -102,23 +108,69 @@ * */ + +queue_head_t vm_object_cached_list; /* list of objects persisting */ +int vm_object_cached; /* size of cached list */ +simple_lock_data_t vm_cache_lock; /* lock for object cache */ + +queue_head_t vm_object_list; /* list of allocated objects */ +long vm_object_count; /* count of all objects */ +simple_lock_data_t vm_object_list_lock; + /* lock for object list and count */ + +vm_object_t kernel_object; /* the single kernel object */ +vm_object_t kmem_object; /* the kernel malloc object */ struct vm_object kernel_object_store; struct vm_object kmem_object_store; -#define VM_OBJECT_HASH_COUNT 157 +extern int vm_cache_max; +#define VM_OBJECT_HASH_COUNT 127 -int vm_cache_max = 100; /* can patch if necessary */ queue_head_t vm_object_hashtable[VM_OBJECT_HASH_COUNT]; long object_collapses = 0; long object_bypasses = 0; /* + * internal version of vm_object_allocate + */ +static inline void +_vm_object_allocate(size, object) + vm_size_t size; + register vm_object_t object; +{ + queue_init(&object->memq); + vm_object_lock_init(object); + object->ref_count = 1; + object->resident_page_count = 0; + object->size = size; + object->can_persist = FALSE; + object->paging_in_progress = 0; + object->copy = NULL; + + /* + * Object starts out read-write, with no pager. + */ + + object->pager = NULL; + object->internal = TRUE; /* vm_allocate_with_pager will reset */ + object->paging_offset = 0; + object->shadow = NULL; + object->shadow_offset = (vm_offset_t) 0; + + simple_lock(&vm_object_list_lock); + queue_enter(&vm_object_list, object, vm_object_t, object_list); + vm_object_count++; + simple_unlock(&vm_object_list_lock); +} + +/* * vm_object_init: * * Initialize the VM objects module. */ -void vm_object_init() +void +vm_object_init() { register int i; @@ -136,7 +188,8 @@ void vm_object_init() kernel_object); kmem_object = &kmem_object_store; - _vm_object_allocate(VM_KMEM_SIZE + VM_MBUF_SIZE, kmem_object); + _vm_object_allocate(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS, + kmem_object); } /* @@ -145,55 +198,30 @@ void vm_object_init() * Returns a new object with the given size. */ -vm_object_t vm_object_allocate(size) +vm_object_t +vm_object_allocate(size) vm_size_t size; { register vm_object_t result; + int s; result = (vm_object_t) malloc((u_long)sizeof *result, M_VMOBJ, M_WAITOK); + _vm_object_allocate(size, result); return(result); } -_vm_object_allocate(size, object) - vm_size_t size; - register vm_object_t object; -{ - queue_init(&object->memq); - vm_object_lock_init(object); - object->ref_count = 1; - object->resident_page_count = 0; - object->size = size; - object->can_persist = FALSE; - object->paging_in_progress = 0; - object->copy = NULL; - - /* - * Object starts out read-write, with no pager. - */ - - object->pager = NULL; - object->pager_ready = FALSE; - object->internal = TRUE; /* vm_allocate_with_pager will reset */ - object->paging_offset = 0; - object->shadow = NULL; - object->shadow_offset = (vm_offset_t) 0; - - simple_lock(&vm_object_list_lock); - queue_enter(&vm_object_list, object, vm_object_t, object_list); - vm_object_count++; - simple_unlock(&vm_object_list_lock); -} /* * vm_object_reference: * * Gets another reference to the given object. */ -void vm_object_reference(object) +inline void +vm_object_reference(object) register vm_object_t object; { if (object == NULL) @@ -215,8 +243,9 @@ void vm_object_reference(object) * * No object may be locked. */ -void vm_object_deallocate(object) - register vm_object_t object; +void +vm_object_deallocate(object) + vm_object_t object; { vm_object_t temp; @@ -236,11 +265,11 @@ void vm_object_deallocate(object) vm_object_lock(object); if (--(object->ref_count) != 0) { + vm_object_unlock(object); /* * If there are still references, then * we are done. */ - vm_object_unlock(object); vm_object_cache_unlock(); return; } @@ -252,48 +281,25 @@ void vm_object_deallocate(object) */ if (object->can_persist) { -#ifdef DIAGNOSTIC - register vm_page_t p; - - /* - * Check for dirty pages in object - * Print warning as this may signify kernel bugs - * pk@cs.few.eur.nl - 4/15/93 - */ - p = (vm_page_t) queue_first(&object->memq); - while (!queue_end(&object->memq, (queue_entry_t) p)) { - VM_PAGE_CHECK(p); - - if (pmap_is_modified(VM_PAGE_TO_PHYS(p)) || - !p->clean) { - - printf("vm_object_dealloc: persistent object %x isn't clean\n", object); - goto cant_persist; - } - - p = (vm_page_t) queue_next(&p->listq); - } -#endif /* DIAGNOSTIC */ queue_enter(&vm_object_cached_list, object, vm_object_t, cached_list); vm_object_cached++; vm_object_cache_unlock(); - vm_object_deactivate_pages(object); + /* vm_object_deactivate_pages(object); */ vm_object_unlock(object); vm_object_cache_trim(); return; } - cant_persist:; /* * 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 */ @@ -301,18 +307,19 @@ void vm_object_deallocate(object) } } - /* * vm_object_terminate actually destroys the specified object, freeing * up all previously used resources. * * The object must be locked. */ -void vm_object_terminate(object) +void +vm_object_terminate(object) register vm_object_t object; { register vm_page_t p; vm_object_t shadow_object; + int s; /* * Detach the object from its shadow if we are the shadow's @@ -322,14 +329,52 @@ void vm_object_terminate(object) 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); } /* + * optim: get rid of any pages that we can right now + * so the pageout daemon can't get any more to page + * out at rundown. + */ +#if 0 + p = (vm_page_t) queue_first(&object->memq); + while (!queue_end(&object->memq, (queue_entry_t) p)) { + vm_page_t next = (vm_page_t) queue_next(&p->listq); + VM_PAGE_CHECK(p); + vm_page_lock_queues(); + + if (p->flags & PG_BUSY) { + p = next; + vm_page_unlock_queues(); + continue; + } + if (!object->internal) { + if ((p->flags & PG_CLEAN) == 0) { + p = next; + vm_page_unlock_queues(); + continue; + } + + if (pmap_is_modified(VM_PAGE_TO_PHYS(p))) { + p->flags &= ~PG_CLEAN; + p = next; + vm_page_unlock_queues(); + continue; + } + } + + vm_page_free(p); + vm_page_unlock_queues(); + p = next; + } +#endif + + /* * Wait until the pageout daemon is through * with the object. */ @@ -339,7 +384,6 @@ void vm_object_terminate(object) vm_object_lock(object); } - /* * While the paging system is locked, * pull the object's pages off the active @@ -357,19 +401,21 @@ void vm_object_terminate(object) VM_PAGE_CHECK(p); vm_page_lock_queues(); - if (p->active) { + s = vm_disable_intr(); + if (p->flags & PG_ACTIVE) { queue_remove(&vm_page_queue_active, p, vm_page_t, pageq); - p->active = FALSE; + p->flags &= ~PG_ACTIVE; vm_page_active_count--; } - if (p->inactive) { + if (p->flags & PG_INACTIVE) { queue_remove(&vm_page_queue_inactive, p, vm_page_t, pageq); - p->inactive = FALSE; + p->flags &= ~PG_INACTIVE; vm_page_inactive_count--; } + vm_set_intr(s); vm_page_unlock_queues(); p = (vm_page_t) queue_next(&p->listq); } @@ -390,6 +436,7 @@ void vm_object_terminate(object) vm_object_page_clean(object, 0, 0); vm_object_unlock(object); } + while (!queue_empty(&object->memq)) { p = (vm_page_t) queue_first(&object->memq); @@ -404,8 +451,9 @@ void vm_object_terminate(object) * Let the pager know object is dead. */ - if (object->pager != NULL) + if (object->pager != NULL) { vm_pager_deallocate(object->pager); + } simple_lock(&vm_object_list_lock); @@ -430,38 +478,58 @@ void vm_object_terminate(object) * * The object must be locked. */ +void vm_object_page_clean(object, start, end) register vm_object_t object; register vm_offset_t start; register vm_offset_t end; { register vm_page_t p; + int s; + int size; if (object->pager == NULL) return; + if (start != end) { + start = trunc_page(start); + end = round_page(end); + } + size = end - start; + again: p = (vm_page_t) queue_first(&object->memq); - while (!queue_end(&object->memq, (queue_entry_t) p)) { - if (start == end || - p->offset >= start && p->offset < end) { - if (p->clean && pmap_is_modified(VM_PAGE_TO_PHYS(p))) - p->clean = FALSE; - pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); - if (!p->clean) { - p->busy = TRUE; + while (!queue_end(&object->memq, (queue_entry_t) p) && ((start == end) || (size != 0) ) ) { + if (start == end || (p->offset >= start && p->offset < end)) { + if (p->flags & PG_BUSY) + goto next; + + size -= PAGE_SIZE; + + if ((p->flags & PG_CLEAN) + && pmap_is_modified(VM_PAGE_TO_PHYS(p))) + p->flags &= ~PG_CLEAN; + + if (p->flags & PG_ACTIVE) + vm_page_deactivate(p); + + if ((p->flags & PG_CLEAN) == 0) { + p->flags |= PG_BUSY; object->paging_in_progress++; vm_object_unlock(object); (void) vm_pager_put(object->pager, p, TRUE); vm_object_lock(object); object->paging_in_progress--; - p->busy = FALSE; + if (object->paging_in_progress == 0) + wakeup((caddr_t) object); PAGE_WAKEUP(p); goto again; } } +next: p = (vm_page_t) queue_next(&p->listq); } + wakeup((caddr_t)object); } /* @@ -472,6 +540,7 @@ again: * * The object must be locked. */ +void vm_object_deactivate_pages(object) register vm_object_t object; { @@ -481,7 +550,8 @@ vm_object_deactivate_pages(object) while (!queue_end(&object->memq, (queue_entry_t) p)) { next = (vm_page_t) queue_next(&p->listq); vm_page_lock_queues(); - if (!p->busy) + if ((p->flags & (PG_INACTIVE|PG_BUSY)) == 0 && + p->wire_count == 0) vm_page_deactivate(p); /* optimisation from mach 3.0 - * andrew@werple.apana.org.au, * Feb '93 @@ -494,6 +564,7 @@ vm_object_deactivate_pages(object) /* * Trim the object cache to size. */ +void vm_object_cache_trim() { register vm_object_t object; @@ -513,7 +584,6 @@ vm_object_cache_trim() vm_object_cache_unlock(); } - /* * vm_object_shutdown() * @@ -526,7 +596,9 @@ vm_object_cache_trim() * race conditions! */ -void vm_object_shutdown() +#if 0 +void +vm_object_shutdown() { register vm_object_t object; @@ -537,7 +609,6 @@ void vm_object_shutdown() vm_object_cache_clear(); - printf("free paging spaces: "); /* * First we gain a reference to each object so that @@ -568,7 +639,7 @@ void vm_object_shutdown() } printf("done.\n"); } - +#endif /* * vm_object_pmap_copy: * @@ -578,12 +649,19 @@ void vm_object_shutdown() * * The object must *not* be locked. */ -void vm_object_pmap_copy(object, start, end) +void +vm_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; + vm_offset_t amount; + + start = trunc_page(start); + end = round_page(end); + + amount = ((end - start) + PAGE_SIZE - 1) / PAGE_SIZE; if (object == NULL) return; @@ -593,7 +671,10 @@ void vm_object_pmap_copy(object, start, end) while (!queue_end(&object->memq, (queue_entry_t) p)) { if ((start <= p->offset) && (p->offset < end)) { pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_READ); - p->copy_on_write = TRUE; + p->flags |= PG_COPY_ON_WRITE; + amount -= 1; + if (amount <= 0) + break; } p = (vm_page_t) queue_next(&p->listq); } @@ -608,21 +689,34 @@ void vm_object_pmap_copy(object, start, end) * * The object must *not* be locked. */ -void vm_object_pmap_remove(object, start, end) +void +vm_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; + vm_offset_t size; if (object == NULL) return; vm_object_lock(object); +again: + size = ((end - start) + PAGE_SIZE - 1) / PAGE_SIZE; p = (vm_page_t) queue_first(&object->memq); while (!queue_end(&object->memq, (queue_entry_t) p)) { - if ((start <= p->offset) && (p->offset < end)) + if ((start <= p->offset) && (p->offset < end)) { + if (p->flags & PG_BUSY) { + p->flags |= PG_WANTED; + tsleep((caddr_t) p, PVM, "vmopmr", 0); + goto again; + } pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); + if ((p->flags & PG_CLEAN) == 0) + p->flags |= PG_LAUNDRY; + if (--size <= 0) break; + } p = (vm_page_t) queue_next(&p->listq); } vm_object_unlock(object); @@ -639,8 +733,8 @@ void vm_object_pmap_remove(object, start, end) * May defer the copy until later if the object is not backed * up by a non-default pager. */ -void vm_object_copy(src_object, src_offset, size, - dst_object, dst_offset, src_needs_copy) +void +vm_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; @@ -651,6 +745,8 @@ void vm_object_copy(src_object, src_offset, size, register vm_object_t new_copy; register vm_object_t old_copy; vm_offset_t new_start, new_end; + vm_offset_t src_offset_end; + vm_offset_t tmpsize; register vm_page_t p; @@ -669,10 +765,19 @@ void vm_object_copy(src_object, src_offset, size, * default pager, we don't have to make a copy * of it. Instead, we set the needs copy flag and * make a shadow later. + * DYSON: check for swap(default) pager too.... */ vm_object_lock(src_object); + + /* + * Try to collapse the object before copying it. + */ + + vm_object_collapse(src_object); + if (src_object->pager == NULL || + src_object->pager->pg_type == PG_SWAP || src_object->internal) { /* @@ -683,12 +788,16 @@ void vm_object_copy(src_object, src_offset, size, /* * Mark all of the pages copy-on-write. */ + tmpsize = size; + src_offset_end = src_offset + size; for (p = (vm_page_t) queue_first(&src_object->memq); - !queue_end(&src_object->memq, (queue_entry_t)p); + !queue_end(&src_object->memq, (queue_entry_t)p) && tmpsize > 0; p = (vm_page_t) queue_next(&p->listq)) { if (src_offset <= p->offset && - p->offset < src_offset + size) - p->copy_on_write = TRUE; + p->offset < src_offset_end) { + p->flags |= PG_COPY_ON_WRITE; + tmpsize -= PAGE_SIZE; + } } vm_object_unlock(src_object); @@ -703,11 +812,6 @@ void vm_object_copy(src_object, src_offset, size, } /* - * 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. @@ -814,10 +918,13 @@ void vm_object_copy(src_object, src_offset, size, * Mark all the affected pages of the existing object * copy-on-write. */ + tmpsize = size; p = (vm_page_t) queue_first(&src_object->memq); - while (!queue_end(&src_object->memq, (queue_entry_t) p)) { - if ((new_start <= p->offset) && (p->offset < new_end)) - p->copy_on_write = TRUE; + while (!queue_end(&src_object->memq, (queue_entry_t) p) && tmpsize > 0) { + if ((new_start <= p->offset) && (p->offset < new_end)) { + p->flags |= PG_COPY_ON_WRITE; + tmpsize -= PAGE_SIZE; + } p = (vm_page_t) queue_next(&p->listq); } @@ -839,7 +946,8 @@ void vm_object_copy(src_object, src_offset, size, * are returned in the source parameters. */ -void vm_object_shadow(object, offset, length) +void +vm_object_shadow(object, offset, length) vm_object_t *object; /* IN/OUT */ vm_offset_t *offset; /* IN/OUT */ vm_size_t length; @@ -884,7 +992,8 @@ void vm_object_shadow(object, offset, length) * Set the specified object's pager to the specified pager. */ -void vm_object_setpager(object, pager, paging_offset, +void +vm_object_setpager(object, pager, paging_offset, read_only) vm_object_t object; vm_pager_t pager; @@ -896,6 +1005,9 @@ void vm_object_setpager(object, pager, paging_offset, #endif lint vm_object_lock(object); /* XXX ? */ + if (object->pager && object->pager != pager) { + panic("!!!pager already allocated!!!\n"); + } object->pager = pager; object->paging_offset = paging_offset; vm_object_unlock(object); /* XXX ? */ @@ -906,14 +1018,15 @@ void vm_object_setpager(object, pager, paging_offset, */ #define vm_object_hash(pager) \ - (((unsigned)pager)%VM_OBJECT_HASH_COUNT) + ((((unsigned)pager) >> 5)%VM_OBJECT_HASH_COUNT) /* * vm_object_lookup looks in the object cache for an object with the * specified pager and paging id. */ -vm_object_t vm_object_lookup(pager) +vm_object_t +vm_object_lookup(pager) vm_pager_t pager; { register queue_t bucket; @@ -951,7 +1064,8 @@ vm_object_t vm_object_lookup(pager) * the hash table. */ -void vm_object_enter(object, pager) +void +vm_object_enter(object, pager) vm_object_t object; vm_pager_t pager; { @@ -987,6 +1101,7 @@ void vm_object_enter(object, pager) * is locked. XXX this should be fixed * by reorganizing vm_object_deallocate. */ +void vm_object_remove(pager) register vm_pager_t pager; { @@ -1013,8 +1128,8 @@ vm_object_remove(pager) * vm_object_cache_clear removes all objects from the cache. * */ - -void vm_object_cache_clear() +void +vm_object_cache_clear() { register vm_object_t object; @@ -1053,8 +1168,12 @@ boolean_t vm_object_collapse_allowed = TRUE; * Requires that the object be locked and the page * queues be unlocked. * + * This routine has significant changes by John S. Dyson + * to fix some swap memory leaks. 18 Dec 93 + * */ -void vm_object_collapse(object) +void +vm_object_collapse(object) register vm_object_t object; { @@ -1072,11 +1191,10 @@ void vm_object_collapse(object) * Verify that the conditions are right for collapse: * * The object exists and no pages in it are currently - * being paged out (or have ever been paged out). + * being paged out. */ if (object == NULL || - object->paging_in_progress != 0 || - object->pager != NULL) + object->paging_in_progress != 0) return; /* @@ -1096,7 +1214,7 @@ void vm_object_collapse(object) */ if (!backing_object->internal || - backing_object->paging_in_progress != 0) { + backing_object->paging_in_progress != 0 ) { vm_object_unlock(backing_object); return; } @@ -1112,10 +1230,22 @@ void vm_object_collapse(object) * parent object. */ if (backing_object->shadow != NULL && - backing_object->shadow->copy != NULL) { + backing_object->shadow->copy == backing_object) { + vm_object_unlock(backing_object); + return; + } + + /* + * we can deal only with the swap pager + */ + if ((object->pager && + object->pager->pg_type != PG_SWAP) || + (backing_object->pager && + backing_object->pager->pg_type != PG_SWAP)) { vm_object_unlock(backing_object); return; } + /* * We know that we can either collapse the backing @@ -1165,36 +1295,12 @@ void vm_object_collapse(object) vm_page_unlock_queues(); } else { pp = vm_page_lookup(object, new_offset); - if (pp != NULL && !pp->fake) { + if (pp != NULL || (object->pager && vm_pager_has_page(object->pager, + object->paging_offset + new_offset))) { vm_page_lock_queues(); vm_page_free(p); vm_page_unlock_queues(); - } - else { - if (pp) { -#if 1 - /* - * This should never happen -- the - * parent cannot have ever had an - * external memory object, and thus - * cannot have absent pages. - */ - panic("vm_object_collapse: bad case"); - /* andrew@werple.apana.org.au - from - mach 3.0 VM */ -#else - /* may be someone waiting for it */ - PAGE_WAKEUP(pp); - vm_page_lock_queues(); - vm_page_free(pp); - vm_page_unlock_queues(); -#endif - } - /* - * Parent now has no page. - * Move the backing object's page - * up. - */ + } else { vm_page_rename(p, object, new_offset); } } @@ -1202,46 +1308,49 @@ void vm_object_collapse(object) /* * Move the pager from backing_object to object. - * - * XXX We're only using part of the paging space - * for keeps now... we ought to discard the - * unused portion. - */ - - /* - * Remove backing_object from the object hashtable now. - * This is necessary since its pager is going away - * and therefore it is not going to be removed from - * hashtable in vm_object_deallocate(). - * - * NOTE - backing_object can only get at this stage if - * it has an internal pager. It is not normally on the - * hashtable unless it was put there by eg. vm_mmap() - * - * XXX - Need I worry here about *named* ANON pagers ? */ if (backing_object->pager) { - vm_object_remove(backing_object->pager); + backing_object->paging_in_progress++; + if (object->pager) { + vm_pager_t bopager; + object->paging_in_progress++; + /* + * copy shadow object pages into ours + * and destroy unneeded pages in shadow object. + */ + bopager = backing_object->pager; + backing_object->pager = NULL; + vm_object_remove(backing_object->pager); + swap_pager_copy( + bopager, backing_object->paging_offset, + object->pager, object->paging_offset, + object->shadow_offset); + object->paging_in_progress--; + if (object->paging_in_progress == 0) + wakeup((caddr_t)object); + } else { + object->paging_in_progress++; + /* + * grab the shadow objects pager + */ + object->pager = backing_object->pager; + object->paging_offset = backing_object->paging_offset + backing_offset; + vm_object_remove(backing_object->pager); + backing_object->pager = NULL; + /* + * free unnecessary blocks + */ + swap_pager_freespace(object->pager, 0, object->paging_offset); + object->paging_in_progress--; + if (object->paging_in_progress == 0) + wakeup((caddr_t)object); + } + backing_object->paging_in_progress--; + if (backing_object->paging_in_progress == 0) + wakeup((caddr_t)backing_object); } - object->pager = backing_object->pager; -#if 1 - /* Mach 3.0 code */ - /* andrew@werple.apana.org.au, 12 Feb 1993 */ - /* - * If there is no pager, leave paging-offset alone. - */ - if (object->pager) - object->paging_offset = - backing_object->paging_offset + - backing_offset; -#else - /* old VM 2.5 version */ - object->paging_offset += backing_offset; -#endif - - backing_object->pager = NULL; /* * Object now shadows whatever backing_object did. @@ -1315,9 +1424,8 @@ void vm_object_collapse(object) if (p->offset >= backing_offset && new_offset <= size && - ((pp = vm_page_lookup(object, new_offset)) - == NULL || - pp->fake)) { + ((pp = vm_page_lookup(object, new_offset)) == NULL || (pp->flags & PG_FAKE)) && + (!object->pager || !vm_pager_has_page(object->pager, object->paging_offset+new_offset))) { /* * Page still needed. * Can't go any further. @@ -1355,6 +1463,8 @@ void vm_object_collapse(object) * will not vanish; so we don't need to call * vm_object_deallocate. */ + if (backing_object->ref_count == 1) + printf("should have called obj deallocate\n"); backing_object->ref_count--; vm_object_unlock(backing_object); @@ -1376,26 +1486,58 @@ void vm_object_collapse(object) * * The object must be locked. */ -void vm_object_page_remove(object, start, end) +void +vm_object_page_remove(object, start, end) register vm_object_t object; register vm_offset_t start; register vm_offset_t end; { register vm_page_t p, next; + vm_offset_t size; + int cnt; + int s; if (object == NULL) return; - p = (vm_page_t) queue_first(&object->memq); - while (!queue_end(&object->memq, (queue_entry_t) p)) { - next = (vm_page_t) queue_next(&p->listq); - if ((start <= p->offset) && (p->offset < end)) { - pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); - vm_page_lock_queues(); - vm_page_free(p); - vm_page_unlock_queues(); + start = trunc_page(start); + end = round_page(end); +again: + size = end-start; + if (size > 4*PAGE_SIZE || size >= object->size/4) { + p = (vm_page_t) queue_first(&object->memq); + while (!queue_end(&object->memq, (queue_entry_t) p) && size > 0) { + next = (vm_page_t) queue_next(&p->listq); + if ((start <= p->offset) && (p->offset < end)) { + if (p->flags & PG_BUSY) { + p->flags |= PG_WANTED; + tsleep((caddr_t) p, PVM, "vmopar", 0); + goto again; + } + pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); + vm_page_lock_queues(); + vm_page_free(p); + vm_page_unlock_queues(); + size -= PAGE_SIZE; + } + p = next; + } + } else { + while (size > 0) { + while (p = vm_page_lookup(object, start)) { + if (p->flags & PG_BUSY) { + p->flags |= PG_WANTED; + tsleep((caddr_t) p, PVM, "vmopar", 0); + goto again; + } + pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE); + vm_page_lock_queues(); + vm_page_free(p); + vm_page_unlock_queues(); + } + start += PAGE_SIZE; + size -= PAGE_SIZE; } - p = next; } } @@ -1421,10 +1563,8 @@ void vm_object_page_remove(object, start, end) * Conditions: * The object must *not* be locked. */ -boolean_t vm_object_coalesce(prev_object, next_object, - prev_offset, next_offset, - prev_size, next_size) - +boolean_t +vm_object_coalesce(prev_object, next_object, prev_offset, next_offset, prev_size, next_size) register vm_object_t prev_object; vm_object_t next_object; vm_offset_t prev_offset, next_offset; @@ -1460,7 +1600,6 @@ boolean_t vm_object_coalesce(prev_object, next_object, * (any of which mean that the pages not mapped to * prev_entry may be in use anyway) */ - if (prev_object->ref_count > 1 || prev_object->pager != NULL || prev_object->shadow != NULL || @@ -1473,7 +1612,6 @@ boolean_t vm_object_coalesce(prev_object, next_object, * Remove any pages that may still be in the object from * a previous deallocation. */ - vm_object_page_remove(prev_object, prev_offset + prev_size, prev_offset + prev_size + next_size); @@ -1489,11 +1627,31 @@ boolean_t vm_object_coalesce(prev_object, next_object, return(TRUE); } +/* + * returns page after looking up in shadow chain + */ + +vm_page_t +vm_object_page_lookup(object, offset) + vm_object_t object; + vm_offset_t offset; +{ + vm_page_t m; + if (!(m=vm_page_lookup(object, offset))) { + if (!object->shadow) + return 0; + else + return vm_object_page_lookup(object->shadow, offset + object->shadow_offset); + } + return m; +} + #if defined(DEBUG) || (NDDB > 0) /* * vm_object_print: [ debug ] */ -void vm_object_print(object, full) +void +vm_object_print(object, full) vm_object_t object; boolean_t full; { |
