From 906623697e99d7012bbcbc6a206bc0c93a7a0c1b Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Sat, 8 Mar 2025 10:16:02 -0500 Subject: [PATCH] ram_disk: Do not use cache_get_pages in Trim(). cache_get_pages locks and unlocks the cache to wait for busy pages, as well as after it's done, which creates a race where some other thread may start waiting on a page that we have marked busy. But as we are about to free those pages, that wait will deadlock. Just loop through the cache's pages directly, skipping any busy ones and freeing the others directly. Fixes a deadlock observed with BFS on a ramdisk. --- .../disk/virtual/ram_disk/ram_disk.cpp | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp b/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp index 521d16f4b5..6c821076e3 100644 --- a/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp @@ -575,36 +575,23 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl { TRACE("ramdisk: trim %" B_PRIu64 " bytes from %" B_PRIu64 "\n", length, offset); - ASSERT(offset % B_PAGE_SIZE == 0); - ASSERT(length % B_PAGE_SIZE == 0); - - BStackOrHeapArray pages(length / B_PAGE_SIZE); - if (!pages.IsValid()) { - result = B_NO_MEMORY; - break; - } - - cache_get_pages(fCache, (off_t)offset, (off_t)length, false, pages); - AutoLocker locker(fCache); for (uint64 j = 0; j < length / B_PAGE_SIZE; j++) { - // If we run out of pages (some may already be trimmed), stop. - if (pages[j] == NULL) - break; + vm_page* page = fCache->LookupPage(offset + j * B_PAGE_SIZE); + if (page == NULL || page->busy) + continue; TRACE("free range %" B_PRIu32 ", page %" B_PRIu64 ", offset %" B_PRIu64 "\n", i, j, offset); - DEBUG_PAGE_ACCESS_START(pages[j]); + DEBUG_PAGE_ACCESS_START(page); - if (pages[j]->Cache() != NULL) - fCache->RemovePage(pages[j]); - vm_page_free(NULL, pages[j]); + fCache->RemovePage(page); + vm_page_free(NULL, page); trimmedSize += B_PAGE_SIZE; } } trimData->trimmed_size = trimmedSize; - return result; }