[PATCH 08/16] mm/shmem: stop retrying folios that cannot be split
From: David Hildenbrand (Arm)
Date: Mon Oct 26 2026 - 05:47:57 EST
From: Chris Mason <mason@xxxxxxxxxx>
A fault or collapse can insert a large folio crossing EOF after
shmem_undo_range() has handled the boundary folios. If splitting that
folio fails, truncate_inode_partial_folio() retains it when it is dirty.
The final scan then repeatedly finds it because it restarts from an
unchanged start.
Truncation keeps the inode lock and ignores fatal signals while looping.
A concurrent unlink() can then block other directory operations while
holding the directory lock and waiting for the file's lock.
Advance start past the retained folio, whose truncated part has already
been zeroed. Do not move start backwards if the failed split has shrunk
the folio.
Fix generated by an LLM and sent by Chris Mason in private.
Fixes: 55ac8bbe358b ("mm/shmem: fix race in shmem_undo_range w/THP")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Chris Mason <mason@xxxxxxxxxx>
[ david: split fixes, simplify descriptions, adjust comments ]
Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
---
mm/shmem.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/mm/shmem.c b/mm/shmem.c
index 2410ec46ee1d1..e2c3b04051833 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1490,6 +1490,14 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, uoff_t lend,
index = start;
break;
}
+ } else {
+ /*
+ * Splitting failed, but the part in the
+ * range is already zeroed, so skip this
+ * folio when restarting the scan to
+ * avoid retrying it forever.
+ */
+ start = max(start, folio_next_index(folio));
}
}
folio_unlock(folio);
--
2.43.0