Re: [PATCH v5 0/4] mm/truncate: fix data loss when truncating straddling large folios

From: Zhang Yi

Date: Tue Sep 29 2026 - 04:37:32 EST


On 9/29/2026 5:49 AM, Andrew Morton wrote:
> On Mon, 28 Sep 2026 20:08:29 +0800 Zhang Yi <yi.zhang@xxxxxxxxxxxxxxx> wrote:
>
>> From: Zhang Yi <yi.zhang@xxxxxxxxxx>
>>
>> Hello,
>>
>> This is the fifth version fixing data loss when truncating straddling
>> large folios caught on the upcomming ext4 + iomap buffered I/O
>> conversion.
>
> Thanks.
>
>> When truncate_inode_pages_range() punches a hole or truncates a file,
>> truncate_inode_partial_folio() splits a large folio so that the caller
>> can drop the in-range sub-folios while keeping the out-of-range tail
>> intact. This series fixes three distinct problems in that path that
>> can each lose the valid out-of-range tail of a straddling folio, plus a
>> follow-up that clarifies the return value semantics.
>>
>> Patch 01 aligns the truncation boundaries inwards to the mapping minimum
>> folio order in truncate_inode_pages_range(). With a non-zero min_order,
>> folio_split() stops at min_order instead of order 0, so a boundary
>> computed at page granularity can land inside a min-order-aligned
>> sub-folio and the truncate loop drops that whole chunk, valid tail
>> included, causing data loss.
>>
>> Patch 02 looks the end-edge straddler up by its page index through
>> __filemap_get_folio() in truncate_inode_partial_folio(). After the
>> first split the straddler is unlocked and only transiently ref'd in the
>> page cache, so the page pointer derived from the original folio can be
>> freed and reallocated as a different folio in the same mapping, and the
>> mapping check cannot catch it, which may cause incorrect splitting and
>> potential data loss.
>>
>> Patch 03 reworks the contract between truncate_inode_partial_folio() and
>> its callers. If the second split of the straddler fails, the function
>> reported success unconditionally, and the leftover incorrect end
>> position could cause the truncate loop to drop that valid tail. After
>> rework, it tells the caller the exact page range safe to discard via new
>> pstart/pend out-parameters, so the truncate loop never touches a
>> straddling folio that still holds valid out-of-range data.
>>
>> Patch 04 clarifies the return value semantics to "at least one split
>> succeeded", which is all the shmem caller needs to decide whether to
>> reset its scan loop.
>>
>> The second patch fixes a pre-existing race issue that is reachable
>> today, so it is Cc'd to stable. Patches 01 and 03 require a dirty large
>> folio that carries no filesystem private data, so they are not reachable
>> on current filesystems. They were found while developing the upcoming
>> ext4 iomap buffered I/O path. [1]
>
> Can you confirm that [2/4] will work correctly when backported into
> -stable kernels? That is has no dependency on the other three?
>

I confirmed the 6.18 and 7.2 versions that need to be backport. The 7.2
version applies cleanly, and the 6.18 version also applies smoothly with
only minor adaptation.

>From a code analysis perspective, I did not find any obvious issues.
After merging both versions, I ran local xfstests on ext4, LTP, and mm
self tests, and did not find any regressions, so I believe it works
correctly.

Cheers,
Yi.