From b4499305c7d5ef4c80254ea8c33e0cd84fa34f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 6 Mar 2006 22:28:40 +0000 Subject: [PATCH] vm_cache_resize() could remove one page too many, and thus eventually free a modified page that mustn't be removed. This fixes bug #110. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16613 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/vm/vm_cache.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/system/kernel/vm/vm_cache.c b/src/system/kernel/vm/vm_cache.c index cabf1fec94..35f88871b0 100644 --- a/src/system/kernel/vm/vm_cache.c +++ b/src/system/kernel/vm/vm_cache.c @@ -348,6 +348,8 @@ vm_cache_set_minimal_commitment(vm_cache_ref *ref, off_t commitment) /** This function updates the size field of the vm_cache structure. * If needed, it will free up all pages that don't belong to the cache anymore. * The vm_cache_ref lock must be held when you call it. + * Since removed pages don't belong to the cache any longer, they are not + * written back before they will be removed. */ status_t @@ -355,7 +357,7 @@ vm_cache_resize(vm_cache_ref *cacheRef, off_t newSize) { vm_cache *cache = cacheRef->cache; status_t status; - off_t oldSize; + uint32 oldPageCount, newPageCount; ASSERT_LOCKED_MUTEX(&cacheRef->lock); @@ -363,16 +365,17 @@ vm_cache_resize(vm_cache_ref *cacheRef, off_t newSize) if (status != B_OK) return status; - oldSize = cache->virtual_size; - if (newSize < oldSize) { + oldPageCount = (uint32)((cache->virtual_size + B_PAGE_SIZE - 1) >> PAGE_SHIFT); + newPageCount = (uint32)((newSize + B_PAGE_SIZE - 1) >> PAGE_SHIFT); + + if (newPageCount < oldPageCount) { // we need to remove all pages in the cache outside of the new virtual size - uint32 lastOffset = (uint32)(newSize >> PAGE_SHIFT); vm_page *page, *next; for (page = cache->page_list; page; page = next) { next = page->cache_next; - if (page->cache_offset >= lastOffset) { + if (page->cache_offset >= newPageCount) { // remove the page and put it into the free queue vm_cache_remove_page(cacheRef, page); vm_page_set_state(page, PAGE_STATE_FREE);