From 05772630b8151d2919150b10a4fdc232f72cf2e1 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Mon, 30 Mar 2026 17:50:20 -0400 Subject: [PATCH] kernel/file_cache: Recheck size in the do_cache_io loop. Since we unlock the cache at various points in this loop, we need to periodically recheck the size here, as otherwise we might try to insert pages past the end. This amends 4f8eaff87f9e161f2340395c796ce62bd3e148a3. Re-tested using the case described in that commit. Change-Id: Id65e309f986a9b7f3e701d2b99c4f318a4eefbd3 Reviewed-on: https://review.haiku-os.org/c/haiku/+/10626 Reviewed-by: waddlesplash --- src/system/kernel/cache/file_cache.cpp | 28 ++++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/system/kernel/cache/file_cache.cpp b/src/system/kernel/cache/file_cache.cpp index 4ae4979c3a..2999c7895f 100644 --- a/src/system/kernel/cache/file_cache.cpp +++ b/src/system/kernel/cache/file_cache.cpp @@ -767,13 +767,15 @@ do_cache_io(void* _cacheRef, void* cookie, off_t offset, addr_t buffer, file_cache_ref* ref = (file_cache_ref*)_cacheRef; VMCache* cache = ref->cache; - bool useBuffer = buffer != 0; + + const bool useBuffer = buffer != 0; + const off_t startOffset = offset; + const size_t size = *_size; TRACE(("cache_io(ref = %p, offset = %lld, buffer = %p, size = %lu, %s)\n", - ref, offset, (void*)buffer, *_size, doWrite ? "write" : "read")); + ref, offset, (void*)buffer, size, doWrite ? "write" : "read")); int32 pageOffset = offset & (B_PAGE_SIZE - 1); - size_t size = *_size; offset -= pageOffset; // "offset" and "lastOffset" are always aligned to B_PAGE_SIZE, @@ -791,15 +793,6 @@ do_cache_io(void* _cacheRef, void* cookie, off_t offset, addr_t buffer, AutoLocker locker(cache); - // Now that we have the lock, make sure the situation didn't change. - if ((pageOffset + offset) >= cache->virtual_end) { - locker.Unlock(); - *_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; @@ -915,6 +908,15 @@ do_cache_io(void* _cacheRef, void* cookie, off_t offset, addr_t buffer, lastPageOffset = 0; } + if ((lastOffset + (off_t)lastLeft) > cache->virtual_end) { + // Someone else must've shrunk the cache. + if (lastOffset > startOffset) + *_size = lastOffset - startOffset; + else + *_size = 0; + return B_OK; + } + if (bytesLeft <= bytesInPage) break; @@ -1310,7 +1312,7 @@ file_cache_disable(void* _cacheRef) AutoLocker _(ref->cache); - // If already disabled, there's nothing to do for us. + // If already disabled, there's nothing for us to do. if (ref->disabled_count > 0) { ref->disabled_count++; return B_OK;