From bcb71f00e814d6eb5bb4390fb1d896c0dfc2be00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 9 Jan 2008 18:15:28 +0000 Subject: [PATCH] * My last change to vm_page.cpp made an existing bug much more likely to appear: when freeing a modified page, it wouldn't have a cache anymore, but set_page_state_nolock() depended on it. * To work around this, I added a vm_page_free() function, which the caches that free modified pages have to call (but others may, too). It will correctly maintain the sModifiedTemporaryPages counter in case the cache has already been removed. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23318 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/vm_page.h | 1 + src/system/kernel/vm/vm_cache.cpp | 4 ++-- src/system/kernel/vm/vm_page.cpp | 30 +++++++++++++++++++++++++----- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/headers/private/kernel/vm_page.h b/headers/private/kernel/vm_page.h index 8f0879404a..ac1845fa59 100644 --- a/headers/private/kernel/vm_page.h +++ b/headers/private/kernel/vm_page.h @@ -26,6 +26,7 @@ status_t vm_page_init_post_thread(struct kernel_args *args); status_t vm_mark_page_inuse(addr_t page); status_t vm_mark_page_range_inuse(addr_t startPage, addr_t length); +void vm_page_free(struct vm_cache *cache, struct vm_page *page); status_t vm_page_set_state(struct vm_page *page, int state); void vm_page_requeue(struct vm_page *page, bool tail); diff --git a/src/system/kernel/vm/vm_cache.cpp b/src/system/kernel/vm/vm_cache.cpp index 781ba88604..ca49520886 100644 --- a/src/system/kernel/vm/vm_cache.cpp +++ b/src/system/kernel/vm/vm_cache.cpp @@ -152,7 +152,7 @@ delete_cache(vm_cache *cache) TRACE(("vm_cache_release_ref: freeing page 0x%lx\n", oldPage->physical_page_number)); - vm_page_set_state(oldPage, PAGE_STATE_FREE); + vm_page_free(cache, oldPage); } // remove the ref to the source @@ -514,7 +514,7 @@ vm_cache_resize(vm_cache *cache, off_t newSize) // remove the page and put it into the free queue vm_cache_remove_page(cache, page); - vm_page_set_state(page, PAGE_STATE_FREE); + vm_page_free(cache, page); } page = next; diff --git a/src/system/kernel/vm/vm_page.cpp b/src/system/kernel/vm/vm_page.cpp index 80745cd308..bbd41e189c 100644 --- a/src/system/kernel/vm/vm_page.cpp +++ b/src/system/kernel/vm/vm_page.cpp @@ -656,17 +656,20 @@ set_page_state_nolock(vm_page *page, int pageState) panic("vm_page_set_state: invalid target state %d\n", pageState); } - if (pageState == PAGE_STATE_CLEAR || pageState == PAGE_STATE_FREE || pageState == PAGE_STATE_INACTIVE) { + if (pageState == PAGE_STATE_CLEAR || pageState == PAGE_STATE_FREE + || pageState == PAGE_STATE_INACTIVE) { if (sPageDeficit > 0) sFreePageCondition.NotifyOne(); if (pageState != PAGE_STATE_INACTIVE && page->cache != NULL) panic("to be freed page %p has cache", page); } - if (pageState == PAGE_STATE_MODIFIED && page->cache->temporary) - sModifiedTemporaryPages++; - else if (page->state == PAGE_STATE_MODIFIED && page->cache->temporary) - sModifiedTemporaryPages--; + if (page->cache != NULL) { + if (pageState == PAGE_STATE_MODIFIED && page->cache->temporary) + sModifiedTemporaryPages++; + else if (page->state == PAGE_STATE_MODIFIED && page->cache->temporary) + sModifiedTemporaryPages--; + } #if TRACK_PAGE_ALLOCATIONS if ((pageState == PAGE_STATE_CLEAR || pageState == PAGE_STATE_FREE) @@ -1708,6 +1711,23 @@ vm_lookup_page(addr_t pageNumber) } +/*! Free the page that belonged to a certain cache. + You can use vm_page_set_state() manually if you prefer, but only + if the page does not equal PAGE_STATE_MODIFIED. +*/ +void +vm_page_free(vm_cache *cache, vm_page *page) +{ + InterruptsSpinLocker _(sPageLock); + + if (page->cache == NULL && page->state == PAGE_STATE_MODIFIED + && cache->temporary) + sModifiedTemporaryPages--; + + set_page_state_nolock(page, PAGE_STATE_FREE); +} + + status_t vm_page_set_state(vm_page *page, int pageState) {