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:
@@ -1815,7 +1815,7 @@ page_scrubber(void *unused)
|
|||||||
if (reserved == 0)
|
if (reserved == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// get some pages from the free queue
|
// get some pages from the free queue, mostly sorted
|
||||||
ReadLocker locker(sFreePageQueuesLock);
|
ReadLocker locker(sFreePageQueuesLock);
|
||||||
|
|
||||||
vm_page *page[SCRUB_SIZE];
|
vm_page *page[SCRUB_SIZE];
|
||||||
@@ -1848,7 +1848,8 @@ page_scrubber(void *unused)
|
|||||||
locker.Lock();
|
locker.Lock();
|
||||||
|
|
||||||
// and put them into the clear queue
|
// 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]->SetState(PAGE_STATE_CLEAR);
|
||||||
page[i]->busy = false;
|
page[i]->busy = false;
|
||||||
DEBUG_PAGE_ACCESS_END(page[i]);
|
DEBUG_PAGE_ACCESS_END(page[i]);
|
||||||
@@ -3654,14 +3655,16 @@ static void
|
|||||||
allocate_page_run_cleanup(VMPageQueue::PageList& freePages,
|
allocate_page_run_cleanup(VMPageQueue::PageList& freePages,
|
||||||
VMPageQueue::PageList& clearPages)
|
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->busy = false;
|
||||||
page->SetState(PAGE_STATE_FREE);
|
page->SetState(PAGE_STATE_FREE);
|
||||||
DEBUG_PAGE_ACCESS_END(page);
|
DEBUG_PAGE_ACCESS_END(page);
|
||||||
sFreePageQueue.PrependUnlocked(page);
|
sFreePageQueue.PrependUnlocked(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (vm_page* page = clearPages.RemoveHead()) {
|
while (vm_page* page = clearPages.RemoveTail()) {
|
||||||
page->busy = false;
|
page->busy = false;
|
||||||
page->SetState(PAGE_STATE_CLEAR);
|
page->SetState(PAGE_STATE_CLEAR);
|
||||||
DEBUG_PAGE_ACCESS_END(page);
|
DEBUG_PAGE_ACCESS_END(page);
|
||||||
|
|||||||
Reference in New Issue
Block a user