The final scan in shmem_undo_range() restarts after a successful split only if the original folio is no longer large. A nonuniform split can leave that folio large, so the scan skips the newly created folios. Hole punching then leaves pages within the hole allocated even though they could be discarded. For example, a fault below the hole can allocate a 2 MiB folio after boundary handling. Punching a 1 MiB hole at offset 64 KiB splits the folio successfully but leaves the original folio at order 4. The scan continues past all 512 pages, leaving 2 MiB allocated instead of 1 MiB. The hole reads as zero, but the pages and their block charges remain. Fixes: 7460b470a131 ("mm/truncate: use folio_split() in truncate operation") Cc: stable@vger.kernel.org Reviewed-by: Baolin Wang Acked-by: Kiryl Shutsemau (Meta) Tested-by: Gregory Price (Meta) Reviewed-by: Zi Yan Signed-off-by: David Hildenbrand (Arm) --- mm/shmem.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index 151704b2091d..e96dc3beac95 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1478,18 +1478,12 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, uoff_t lend, } else if (truncate_inode_partial_folio(folio, lstart, lend, NULL, NULL)) { /* - * If we split a page, reset the loop so - * that we pick up the new sub pages. - * Otherwise the THP was entirely - * dropped or the target range was - * zeroed, so just continue the loop as - * is. + * The folio was split. Retry the scan + * to find the split folios. */ - if (!folio_test_large(folio)) { - folio_unlock(folio); - index = start; - break; - } + folio_unlock(folio); + index = start; + break; } else if (folio->mapping) { /* * Splitting failed, but the part in the -- 2.43.0