[PATCH v3 09/15] mm/shmem: discard whole new large folios on fallocate rollback

From: David Hildenbrand (Arm)

Date: Wed Oct 28 2026 - 05:58:17 EST


When undoing a failed fallocate(), shmem_undo_range() must discard each
newly allocated folio. Its second scan instead passes large
folios to truncate_inode_partial_folio(), which does not necessarily
discard the entire large folio, but instead tries splitting it to
discard only the requested range.

For example, with huge=always, a failed allocation starting at offset
4 KiB can leave page 0 allocated in an otherwise empty file.

Discard the whole folio when unfalloc is set. Note that we enter this
path only for folios that are not uptodate, and can consequently be
dropped without losing any data.

Fixes: 55ac8bbe358b ("mm/shmem: fix race in shmem_undo_range w/THP")
Cc: stable@xxxxxxxxxxxxxxx
Reviewed-by: Zi Yan <ziy@xxxxxxxxxx>
Acked-by: Kiryl Shutsemau (Meta) <kas@xxxxxxxxxx>
Reviewed-by: Baolin Wang <baolin.wang@xxxxxxxxxxxxxxxxx>
Tested-by: Gregory Price (Meta) <gourry@xxxxxxxxxx>
Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
---
mm/shmem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/shmem.c b/mm/shmem.c
index f52bab8176d7..a686b3d77647 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1473,7 +1473,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, uoff_t lend,
if (!unfalloc && folio_test_large(folio))
folio_mark_dirty(folio);

- if (!folio_test_large(folio)) {
+ if (unfalloc || !folio_test_large(folio)) {
truncate_inode_folio(mapping, folio);
} else if (truncate_inode_partial_folio(folio,
lstart, lend, NULL, NULL)) {

--
2.43.0