kernel/vm: put pages in order on the clear page queue

possibly help with #15789:
I was testing virtual_block devices with dd, and noticed it didn't work with higher block sizes.
Indeed the driver was passing a list of single pages, very inefficient. To be remarked is that
the physical pages were reversed in memory, causing get_memory_map to provide a map of single pages.
What happens: dd fills up the buffer from 0 until the block size, causing soft faults for still unmapped
pages. Each fault maps a cleared physical page out of the clear page queue. This means that some page runs
are actually put reversed in the clear page queue, which this commit fixes.

Change-Id: I36395849c7f13086b44a1b284cc0c858d8c29f75
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7081
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
Reviewed-by: Axel Dörfler <[email protected]>
This commit is contained in:
Jérôme Duval
2023-10-30 19:04:51 +00:00
parent 1a497824d8
commit 208006054c
+7 -4
View File
@@ -1815,7 +1815,7 @@ page_scrubber(void *unused)
if (reserved == 0)
continue;
// get some pages from the free queue
// get some pages from the free queue, mostly sorted
ReadLocker locker(sFreePageQueuesLock);
vm_page *page[SCRUB_SIZE];
@@ -1848,7 +1848,8 @@ page_scrubber(void *unused)
locker.Lock();
// and put them into the clear queue
for (int32 i = 0; i < scrubCount; i++) {
// process the array reversed when prepending to preserve sequential order
for (int32 i = scrubCount - 1; i >= 0; i--) {
page[i]->SetState(PAGE_STATE_CLEAR);
page[i]->busy = false;
DEBUG_PAGE_ACCESS_END(page[i]);
@@ -3654,14 +3655,16 @@ static void
allocate_page_run_cleanup(VMPageQueue::PageList& freePages,
VMPageQueue::PageList& clearPages)
{
while (vm_page* page = freePages.RemoveHead()) {
// Page lists are sorted, so remove tails before prepending to the respective queue.
while (vm_page* page = freePages.RemoveTail()) {
page->busy = false;
page->SetState(PAGE_STATE_FREE);
DEBUG_PAGE_ACCESS_END(page);
sFreePageQueue.PrependUnlocked(page);
}
while (vm_page* page = clearPages.RemoveHead()) {
while (vm_page* page = clearPages.RemoveTail()) {
page->busy = false;
page->SetState(PAGE_STATE_CLEAR);
DEBUG_PAGE_ACCESS_END(page);