[PATCH] mm: filemap: skip dropbehind folios during fault-around

From: Wenjie Qi

Date: Sun Aug 30 2026 - 07:49:26 EST


From: Wenjie Qi <qiwenjie@xxxxxxxxxx>

filemap_map_pages() maps uptodate folios speculatively without going
through the normal filemap lookup that clears dropbehind. As a result,
a neighboring dropbehind folio can acquire a PTE and the mapped-folio
completion guard will retain it even if that PTE is never accessed.

Skip still-dropbehind folios in next_uptodate_folio(). If the skipped
folio covers the fault address, do_read_fault() falls back to
filemap_fault(), where the normal lookup clears dropbehind and updates
WB_DONTCACHE_DIRTY accounting before mapping it. Speculative neighbors
remain unmapped and can be discarded when I/O completes. Normal folios
continue to use fault-around.

Dropbehind is folio-wide, so a fault into any subpage retains the whole
large folio through the normal fault path.

Signed-off-by: Wenjie Qi <qiwenjie@xxxxxxxxxx>
---
Tested on XFS over a 5-second dm-delay target in QEMU:
- neighbor-dontcache: the target remained unmapped and was evicted.
- target-dontcache: the directly faulted target was mapped and retained.
- neighbor-normal: the target was fault-around mapped and retained.
- unmapped-dontcache: the target remained unmapped and was evicted.
All cases completed writeback, validated data, and kept dmesg clean.

mm/filemap.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/mm/filemap.c b/mm/filemap.c
index 00fd89cf6f550..c123de583b3e1 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -3769,6 +3769,8 @@ static struct folio *next_uptodate_folio(struct xa_state *xas,
goto unlock;
if (!folio_test_uptodate(folio))
goto unlock;
+ if (folio_test_dropbehind(folio))
+ goto unlock;
max_idx = DIV_ROUND_UP(i_size_read(mapping->host), PAGE_SIZE);
if (xas->xa_index >= max_idx)
goto unlock;
--
2.43.0