[PATCH RFC 1/1] mm/filemap: handle large folio split race in page cache lookups
From: Chris J Arges
Date: Thu Mar 05 2026 - 13:35:35 EST
We have been hitting VM_BUG_ON_FOLIO(!folio_contains(folio, index)) in
production environments. These machines are using XFS with large folio
support enabled and are under high memory pressure.
>From reading the code it seems plausible that folio splits due to memory
reclaim are racing with filemap_fault() serving mmap page faults.
The existing code checks for truncation (folio->mapping != mapping) and
retries, but there does not appear to be equivalent handling for the
split case. The result is:
kernel BUG at mm/filemap.c:3519!
VM_BUG_ON_FOLIO(!folio_contains(folio, index), folio)
This RFC patch extends the existing truncation retry checks to also
cover the case where the folio no longer contains the target index.
Fixes: e292e6d644ce ("filemap: Convert filemap_fault to folio")
Signed-off-by: Chris J Arges <carges@xxxxxxxxxxxxxx>
---
mm/filemap.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/mm/filemap.c b/mm/filemap.c
index 6cd7974d4ada..334d3f700beb 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1954,13 +1954,13 @@ struct folio *__filemap_get_folio_mpol(struct address_space *mapping,
folio_lock(folio);
}
- /* Has the page been truncated? */
- if (unlikely(folio->mapping != mapping)) {
+ /* Has the page been truncated or split? */
+ if (unlikely(folio->mapping != mapping) ||
+ unlikely(!folio_contains(folio, index))) {
folio_unlock(folio);
folio_put(folio);
goto repeat;
}
- VM_BUG_ON_FOLIO(!folio_contains(folio, index), folio);
}
if (fgp_flags & FGP_ACCESSED)
@@ -2179,10 +2179,9 @@ unsigned find_lock_entries(struct address_space *mapping, pgoff_t *start,
if (!folio_trylock(folio))
goto put;
if (folio->mapping != mapping ||
- folio_test_writeback(folio))
+ folio_test_writeback(folio) ||
+ !folio_contains(folio, xas.xa_index))
goto unlock;
- VM_BUG_ON_FOLIO(!folio_contains(folio, xas.xa_index),
- folio);
} else {
nr = 1 << xas_get_order(&xas);
base = xas.xa_index & ~(nr - 1);
@@ -3570,13 +3569,13 @@ vm_fault_t filemap_fault(struct vm_fault *vmf)
if (!lock_folio_maybe_drop_mmap(vmf, folio, &fpin))
goto out_retry;
- /* Did it get truncated? */
- if (unlikely(folio->mapping != mapping)) {
+ /* Did it get truncated or split? */
+ if (unlikely(folio->mapping != mapping) ||
+ unlikely(!folio_contains(folio, index))) {
folio_unlock(folio);
folio_put(folio);
goto retry_find;
}
- VM_BUG_ON_FOLIO(!folio_contains(folio, index), folio);
/*
* We have a locked folio in the page cache, now we need to check
--
2.43.0