summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2007-10-27 00:09:30 +0000
committeralc <alc@FreeBSD.org>2007-10-27 00:09:30 +0000
commitacb713befafd577c0e580cec96826de8d50e3ce9 (patch)
treefe9c37be33dfc1d8c0d6dfe1e7eaa470db773f14 /sys
parent4eb58f88d1889098568e9f9ca175b5a46eccee3b (diff)
downloadFreeBSD-src-acb713befafd577c0e580cec96826de8d50e3ce9.zip
FreeBSD-src-acb713befafd577c0e580cec96826de8d50e3ce9.tar.gz
Change vm_page_cache_transfer() such that it does not transfer pages
that would have an offset beyond the end of the target object. Such pages should remain in the source object. MFC after: 3 days Diagnosed and reviewed by: Kostik Belousov Reported and tested by: Peter Holm
Diffstat (limited to 'sys')
-rw-r--r--sys/vm/vm_page.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index e34b066..28771cb 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -916,7 +916,9 @@ vm_page_cache_remove(vm_page_t m)
/*
* Transfer all of the cached pages with offset greater than or
* equal to 'offidxstart' from the original object's cache to the
- * new object's cache. Initially, the new object's cache must be
+ * new object's cache. However, any cached pages with offset
+ * greater than or equal to the new object's size are kept in the
+ * original object. Initially, the new object's cache must be
* empty. Offset 'offidxstart' in the original object must
* correspond to offset zero in the new object.
*
@@ -954,17 +956,21 @@ vm_page_cache_transfer(vm_object_t orig_object, vm_pindex_t offidxstart,
new_object->cache = m;
m->left = NULL;
}
- KASSERT(new_object->cache == NULL ||
- new_object->type == OBJT_SWAP,
- ("vm_page_cache_transfer: object %p's type is incompatible"
- " with cached pages", new_object));
-
- /*
- * Update the object and offset of each page that was
- * transferred to the new object's cache.
- */
while ((m = new_object->cache) != NULL) {
+ if ((m->pindex - offidxstart) >= new_object->size) {
+ /*
+ * Return all of the cached pages with
+ * offset greater than or equal to the
+ * new object's size to the original
+ * object's cache.
+ */
+ new_object->cache = m->left;
+ m->left = orig_object->cache;
+ orig_object->cache = m;
+ break;
+ }
m_next = vm_page_splay(m->pindex, m->right);
+ /* Update the page's object and offset. */
m->object = new_object;
m->pindex -= offidxstart;
if (m_next == NULL)
@@ -973,6 +979,10 @@ vm_page_cache_transfer(vm_object_t orig_object, vm_pindex_t offidxstart,
m_next->left = m;
new_object->cache = m_next;
}
+ KASSERT(new_object->cache == NULL ||
+ new_object->type == OBJT_SWAP,
+ ("vm_page_cache_transfer: object %p's type is incompatible"
+ " with cached pages", new_object));
}
mtx_unlock(&vm_page_queue_free_mtx);
}
OpenPOWER on IntegriCloud