From 4f8eaff87f9e161f2340395c796ce62bd3e148a3 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Fri, 7 Feb 2025 13:46:50 -0500 Subject: [PATCH] kernel/file_cache: Re-check the cache size after acquiring the lock. If it changed, then don't try to do I/O past the end. It would presumably just fail anyway, and since the addition of extra asserts to VMCache page insertion, will cause assertion failures due to inserting pages past the end of the cache. This case is particularly easy to trigger by holding the down arrow in the keymaps list (i.e. changing keymaps very rapidly.) --- src/system/kernel/cache/file_cache.cpp | 30 ++++++++++++++++++-------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/system/kernel/cache/file_cache.cpp b/src/system/kernel/cache/file_cache.cpp index 4531739fc0..c7267d1a98 100644 --- a/src/system/kernel/cache/file_cache.cpp +++ b/src/system/kernel/cache/file_cache.cpp @@ -750,21 +750,33 @@ cache_io(void* _cacheRef, void* cookie, off_t offset, addr_t buffer, // satisfied request part const uint32 kMaxChunkSize = MAX_IO_VECS * B_PAGE_SIZE; - size_t bytesLeft = size, lastLeft = size; - int32 lastPageOffset = pageOffset; - addr_t lastBuffer = buffer; - off_t lastOffset = offset; - size_t lastReservedPages = min_c(MAX_IO_VECS, (pageOffset + bytesLeft - + B_PAGE_SIZE - 1) >> PAGE_SHIFT); - size_t reservePages = 0; - size_t pagesProcessed = 0; - cache_func function = NULL; + size_t lastReservedPages = min_c(MAX_IO_VECS, (pageOffset + size + + B_PAGE_SIZE - 1) >> PAGE_SHIFT); vm_page_reservation reservation; reserve_pages(ref, &reservation, lastReservedPages, doWrite); AutoLocker locker(cache); + // Now that we have the lock, make sure the situation didn't change. + if ((pageOffset + offset) >= cache->virtual_end) { + locker.Unlock(); + vm_page_unreserve_pages(&reservation); + + *_size = 0; + return B_OK; + } + if ((off_t)(pageOffset + offset + size) > cache->virtual_end) + size = cache->virtual_end - (pageOffset + offset); + + size_t bytesLeft = size, lastLeft = size; + int32 lastPageOffset = pageOffset; + addr_t lastBuffer = buffer; + off_t lastOffset = offset; + size_t reservePages = 0; + size_t pagesProcessed = 0; + cache_func function = NULL; + while (bytesLeft > 0) { // Periodically reevaluate the low memory situation and select the // read/write hook accordingly