aboutsummaryrefslogtreecommitdiff
path: root/sys/vm/vm_object.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vm/vm_object.c')
-rw-r--r--sys/vm/vm_object.c566
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;
{