diff options
author | alc <alc@FreeBSD.org> | 2007-10-27 00:09:30 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2007-10-27 00:09:30 +0000 |
commit | acb713befafd577c0e580cec96826de8d50e3ce9 (patch) | |
tree | fe9c37be33dfc1d8c0d6dfe1e7eaa470db773f14 /sys/vm/vm_page.c | |
parent | 4eb58f88d1889098568e9f9ca175b5a46eccee3b (diff) | |
download | FreeBSD-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/vm/vm_page.c')
-rw-r--r-- | sys/vm/vm_page.c | 30 |
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); } |