Re: [PATCH 11/16] mm/shmem: rescan after nonuniform folio splitting

From: David Hildenbrand (Arm)

Date: Tue Oct 27 2026 - 06:49:02 EST


On 10/27/26 03:32, Zi Yan wrote:
> On Mon Oct 26, 2026 at 5:40 AM EDT, David Hildenbrand (Arm) wrote:
>> 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.
>>
>
>
>> Restart when the original folio is still in the mapping after partial
>> truncation, identified by checking folio->mapping. If the helper
>> removed the whole folio, no rescan is needed.
>
> This paragraph is no longer needed after Zhang Yi's truncate fix, since
> truncate_inode_partial_folio() returns true only if the folio is split.
> The function returns false when the whole folio is truncated[1].
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git/tree/mm/truncate.c?h=mm-stable#n282
>
>>
>> Fixes: 7460b470a131f ("mm/truncate: use folio_split() in truncate operation")
>> Cc: stable@xxxxxxxxxxxxxxx
>> Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
>> ---
>> mm/shmem.c | 11 ++++-------
>> 1 file changed, 4 insertions(+), 7 deletions(-)
>>
>
> folio->mapping check is dropped and the comment is adjusted after the
> patch is rebased on top of mm-stable because of the aforementioned
> reason:
>
>
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 7cf5a4d9d1ace..ddea31f44fb32 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -1477,18 +1477,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 {
> /*
> * Splitting failed, but the part in the
>

Yeah, that's straight forward. For this one I will keep Kiryl's ACK.

Thanks all.

--
Cheers,

David