VMCache: Factor out a _FreePageRange method.

The code in the Resize and Rebase methods was identical except for the
iterator.

Change-Id: I9f6b3c2c09af0c26778215bd627fed030c4d46f1
Reviewed-on: https://review.haiku-os.org/c/haiku/+/2835
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Michael Lotz
2020-05-30 01:47:40 +00:00
committed by waddlesplash
parent 57656b93b6
commit 428bc69ab8
2 changed files with 52 additions and 67 deletions
+3
View File
@@ -215,6 +215,9 @@ private:
void _MergeWithOnlyConsumer(); void _MergeWithOnlyConsumer();
void _RemoveConsumer(VMCache* consumer); void _RemoveConsumer(VMCache* consumer);
bool _FreePageRange(VMCachePagesTree::Iterator it,
page_num_t* toPage);
private: private:
int32 fRefCount; int32 fRefCount;
mutex fLock; mutex fLock;
+49 -67
View File
@@ -1111,6 +1111,46 @@ VMCache::SetMinimalCommitment(off_t commitment, int priority)
} }
bool
VMCache::_FreePageRange(VMCachePagesTree::Iterator it,
page_num_t* toPage = NULL)
{
for (vm_page* page = it.Next();
page != NULL && (toPage == NULL || page->cache_offset < *toPage);
page = it.Next()) {
if (page->busy) {
if (page->busy_writing) {
// We cannot wait for the page to become available
// as we might cause a deadlock this way
page->busy_writing = false;
// this will notify the writer to free the page
continue;
}
// wait for page to become unbusy
WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true);
return true;
}
// remove the page and put it into the free queue
DEBUG_PAGE_ACCESS_START(page);
vm_remove_all_page_mappings(page);
ASSERT(page->WiredCount() == 0);
// TODO: Find a real solution! If the page is wired
// temporarily (e.g. by lock_memory()), we actually must not
// unmap it!
RemovePage(page);
// Note: When iterating through a IteratableSplayTree
// removing the current node is safe.
vm_page_free(this, page);
}
return false;
}
/*! This function updates the size field of the cache. /*! This function updates the size field of the cache.
If needed, it will free up all pages that don't belong to the cache anymore. If needed, it will free up all pages that don't belong to the cache anymore.
The cache lock must be held when you call it. The cache lock must be held when you call it.
@@ -1133,44 +1173,16 @@ VMCache::Resize(off_t newSize, int priority)
if (status != B_OK) if (status != B_OK)
return status; return status;
uint32 oldPageCount = (uint32)((virtual_end + B_PAGE_SIZE - 1) page_num_t oldPageCount = (page_num_t)((virtual_end + B_PAGE_SIZE - 1)
>> PAGE_SHIFT);
page_num_t newPageCount = (page_num_t)((newSize + B_PAGE_SIZE - 1)
>> PAGE_SHIFT); >> PAGE_SHIFT);
uint32 newPageCount = (uint32)((newSize + B_PAGE_SIZE - 1) >> PAGE_SHIFT);
if (newPageCount < oldPageCount) { if (newPageCount < oldPageCount) {
// we need to remove all pages in the cache outside of the new virtual // we need to remove all pages in the cache outside of the new virtual
// size // size
for (VMCachePagesTree::Iterator it while (_FreePageRange(pages.GetIterator(newPageCount, true, true)))
= pages.GetIterator(newPageCount, true, true); ;
vm_page* page = it.Next();) {
if (page->busy) {
if (page->busy_writing) {
// We cannot wait for the page to become available
// as we might cause a deadlock this way
page->busy_writing = false;
// this will notify the writer to free the page
} else {
// wait for page to become unbusy
WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true);
// restart from the start of the list
it = pages.GetIterator(newPageCount, true, true);
}
continue;
}
// remove the page and put it into the free queue
DEBUG_PAGE_ACCESS_START(page);
vm_remove_all_page_mappings(page);
ASSERT(page->WiredCount() == 0);
// TODO: Find a real solution! If the page is wired
// temporarily (e.g. by lock_memory()), we actually must not
// unmap it!
RemovePage(page);
vm_page_free(this, page);
// Note: When iterating through a IteratableSplayTree
// removing the current node is safe.
}
} }
virtual_end = newSize; virtual_end = newSize;
@@ -1199,43 +1211,13 @@ VMCache::Rebase(off_t newBase, int priority)
if (status != B_OK) if (status != B_OK)
return status; return status;
uint32 basePage = (uint32)(newBase >> PAGE_SHIFT); page_num_t basePage = (page_num_t)(newBase >> PAGE_SHIFT);
if (newBase > virtual_base) { if (newBase > virtual_base) {
// we need to remove all pages in the cache outside of the new virtual // we need to remove all pages in the cache outside of the new virtual
// size // base
VMCachePagesTree::Iterator it = pages.GetIterator(); while (_FreePageRange(pages.GetIterator(), &basePage))
for (vm_page* page = it.Next(); ;
page != NULL && page->cache_offset < basePage;
page = it.Next()) {
if (page->busy) {
if (page->busy_writing) {
// We cannot wait for the page to become available
// as we might cause a deadlock this way
page->busy_writing = false;
// this will notify the writer to free the page
} else {
// wait for page to become unbusy
WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true);
// restart from the start of the list
it = pages.GetIterator();
}
continue;
}
// remove the page and put it into the free queue
DEBUG_PAGE_ACCESS_START(page);
vm_remove_all_page_mappings(page);
ASSERT(page->WiredCount() == 0);
// TODO: Find a real solution! If the page is wired
// temporarily (e.g. by lock_memory()), we actually must not
// unmap it!
RemovePage(page);
vm_page_free(this, page);
// Note: When iterating through a IteratableSplayTree
// removing the current node is safe.
}
} }
virtual_base = newBase; virtual_base = newBase;