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
This commit is contained in:
Axel Dörfler
2006-03-06 22:28:40 +00:00
parent 0353f98bc3
commit b4499305c7
+8 -5
View File
@@ -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);