* 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
This commit is contained in:
Axel Dörfler 2008-01-09 18:15:28 +00:00
parent e3145a8d8d
commit bcb71f00e8
3 changed files with 28 additions and 7 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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)
{