mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v5 0/4] mm/truncate: fix data loss when truncating straddling large folios
@ 2026-09-28 12:08 Zhang Yi
  2026-09-28 12:08 ` [PATCH v5 1/4] mm/truncate: align truncation boundaries to mapping minimum folio order Zhang Yi
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Zhang Yi @ 2026-09-28 12:08 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-fsdevel, linux-kernel, linux-ext4, akpm, david, ljs, liam,
	vbabka, rppt, surenb, mhocko, hughd, baolin.wang, willy, jack,
	ziy, bfoster, joannelkoong, djwong, yi.zhang, yi.zhang,
	yizhang089, yangerkun, chengzhihao1, wangkefeng.wang, yukuai

From: Zhang Yi <yi.zhang@huawei.com>

Hello,

This is the fifth version fixing data loss when truncating straddling
large folios caught on the upcomming ext4 + iomap buffered I/O
conversion.

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]

In addition, another two pre-existing issues were found during the
development of this series:

 - On 32-bit systems with a non-zero min_order filesystem, truncating or
   any operation operation involving folio_next_index() on the folio
   containing MAX_LFS_FILESIZE can cause the index calculation to
   overflow, posing an unpredictable risk. [2]
 - In shmem, at the last call site of truncate_inode_partial_folio() in
   shmem_undo_range(), the restart-loop check is wrong, which leaves
   split sub-folios behind. [3]

These two issues need to be fixed separately.

Thanks,
Yi.

[1] https://lore.kernel.org/linux-fsdevel/a638a8fb-c184-4069-ae33-379ec12cd514@huaweicloud.com/
[2] https://lore.kernel.org/linux-mm/5a454f2a-8ae2-491d-b903-750c945cfb9d@huaweicloud.com/
[3] https://lore.kernel.org/linux-mm/5pthbyxtn7q6xi4fmkofvksmcjzfnujcw2g4fxmxjzfin5pbgf@zui3vcimb4cv/


v4-v5:
 - Collects RVB labels from Jan, Brian and Zi Yan.
 - In patch 1, move the initialization of the min_order variable to
   the top, which looks nicer. (Zi Yan)
 - In patch 3, replace the leftover folio_test_large() check with a
   check of whether the folio's order equals min_order, so as to
   determine whether the folio needs to be split. (Zi Yan)

v3->v4:
 - Move the patch that fixes data loss when min_order is non-zero to the
   first patch position, aligning start and end in
   truncate_inode_pages_range(). (Zi Yan)
 - Add patch 2, fixing the invalid folio2 issue under concurrency when
   truncate_inode_partial_folio() splits at the end position. Use
   __filemap_get_folio() to obtain a reliable folio2. (Jan Kara)

v2->v3:
 - Rework the folio2 validity check logic to fix the invalid
   folio->index issue. (sashiko)
 - Clarify the pstart and pend setting logic and the corresponding
   comments to make it more readable. (Brian, Joanne)
 - Split the patch into 3 small patches. (Zi Yan)

v1->v2:
 - Export pstart as a new parameter so that the generic and shmem
   truncate paths don't need to recompute the start value from the
   return value. (Brian)
 - When min_order is non-zero, align [pstart, pend] to the inner
   boundaries of the folio to ensure they do not point into the middle
   of a large folio, which could otherwise cause valid data within the
   folio to be incorrectly cleared. (Joanne)

v4: https://lore.kernel.org/linux-mm/20260922110703.468389-1-yi.zhang@huaweicloud.com/
v3: https://lore.kernel.org/linux-mm/20260916092450.654408-1-yi.zhang@huaweicloud.com/
v2: https://lore.kernel.org/linux-mm/20260909062339.473816-1-yi.zhang@huaweicloud.com/
v1: https://lore.kernel.org/linux-mm/20260903115018.2034541-1-yi.zhang@huaweicloud.com/


Zhang Yi (4):
  mm/truncate: align truncation boundaries to mapping minimum folio
    order
  mm/truncate: look up the end-edge straddler by index
  mm/truncate: fix data loss when splitting straddling large folios
    fails
  mm/truncate: clarify return value of truncate_inode_partial_folio()

 mm/internal.h |   4 +-
 mm/shmem.c    |  13 ++---
 mm/truncate.c | 131 +++++++++++++++++++++++++++++++++-----------------
 3 files changed, 93 insertions(+), 55 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-09-29  8:35 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-28 12:08 [PATCH v5 0/4] mm/truncate: fix data loss when truncating straddling large folios Zhang Yi
2026-09-28 12:08 ` [PATCH v5 1/4] mm/truncate: align truncation boundaries to mapping minimum folio order Zhang Yi
     [not found]   ` <20260928123136.2D6891F000FF@smtp.kernel.org>
2026-09-28 12:46     ` Zhang Yi
2026-09-28 12:08 ` [PATCH v5 2/4] mm/truncate: look up the end-edge straddler by index Zhang Yi
2026-09-28 12:08 ` [PATCH v5 3/4] mm/truncate: fix data loss when splitting straddling large folios fails Zhang Yi
2026-09-28 12:08 ` [PATCH v5 4/4] mm/truncate: clarify return value of truncate_inode_partial_folio() Zhang Yi
2026-09-28 21:49 ` [PATCH v5 0/4] mm/truncate: fix data loss when truncating straddling large folios Andrew Morton
2026-09-29  8:35   ` Zhang Yi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®