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.)
This commit is contained in:
Augustin Cavalier
2025-02-07 13:46:50 -05:00
parent 7a0fdd19a0
commit 4f8eaff87f
+21 -9
View File
@@ -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<VMCache> 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