* [PATCH v3] xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN
@ 2026-07-28 7:19 Lin Jiapeng
2026-08-03 13:22 ` Carlos Maiolino
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Lin Jiapeng @ 2026-07-28 7:19 UTC (permalink / raw)
To: cem, linux-xfs; +Cc: stable, djwong, hch, jiapenglin
When exchanging two full-file ranges, xmi_can_exchange_reflink_flags()
can move the reflink inode flag from the file that currently has it to
the other file, as long as exactly one side is marked. This assumes
that the file contents, and therefore all shared extents, are exchanged.
That assumption is not true when XFS_EXCHMAPS_INO1_WRITTEN is set.
xfs_exchmaps_can_skip_mapping() can skip hole and unwritten mappings
from file1, so an exchange can complete without moving every mapping
that the earlier flag-swap decision accounted for. In that case the
post-operation cleanup can clear the reflink flag from an inode that
still owns shared written extents. Later writes then take the
non-reflink write path and may update blocks that should still have
been protected by CoW, which shows up as data corruption between
reflink-related files.
Fix this by disabling the reflink flag exchange whenever
XFS_EXCHMAPS_INO1_WRITTEN is requested. The contents exchange can still
proceed; the conservative outcome is that both inodes keep the reflink
flag. The regular reflink flag cleanup path can drop the extra flag
later once the inode no longer has shared extents.
Reported-by: Lin Jiapeng(TencentOS Red Team) <jiapenglin@tencent.com>
Fixes: 966ceafc7a43 ("xfs: create deferred log items for file mapping exchanges")
Cc: <stable@vger.kernel.org> # v6.10
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Lin Jiapeng <jiapenglin@tencent.com>
---
fs/xfs/libxfs/xfs_exchmaps.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/fs/xfs/libxfs/xfs_exchmaps.c b/fs/xfs/libxfs/xfs_exchmaps.c
index dcd0bd0b13b4..3efed37cb98a 100644
--- a/fs/xfs/libxfs/xfs_exchmaps.c
+++ b/fs/xfs/libxfs/xfs_exchmaps.c
@@ -959,6 +959,16 @@ xmi_can_exchange_reflink_flags(
{
struct xfs_mount *mp = req->ip1->i_mount;
+ /*
+ * The INO1_WRITTEN optimization can skip exchanging hole and
+ * unwritten mappings, which means we cannot guarantee that all
+ * shared extents actually moved to the other file. Clearing the
+ * reflink flag of an inode that still holds shared extents breaks
+ * the CoW write path, so refuse to exchange the flags in that case.
+ */
+ if (req->flags & XFS_EXCHMAPS_INO1_WRITTEN)
+ return false;
+
if (hweight32(reflink_state) != 1)
return false;
if (req->startoff1 != 0 || req->startoff2 != 0)
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v3] xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN
2026-07-28 7:19 [PATCH v3] xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN Lin Jiapeng
@ 2026-08-03 13:22 ` Carlos Maiolino
2026-08-31 8:03 ` Carlos Maiolino
2026-09-03 6:05 ` Carlos Maiolino
2 siblings, 0 replies; 4+ messages in thread
From: Carlos Maiolino @ 2026-08-03 13:22 UTC (permalink / raw)
To: linux-xfs, Lin Jiapeng; +Cc: stable, djwong, hch, jiapenglin
On Tue, 28 Jul 2026 15:19:10 +0800, Lin Jiapeng wrote:
> When exchanging two full-file ranges, xmi_can_exchange_reflink_flags()
> can move the reflink inode flag from the file that currently has it to
> the other file, as long as exactly one side is marked. This assumes
> that the file contents, and therefore all shared extents, are exchanged.
>
> That assumption is not true when XFS_EXCHMAPS_INO1_WRITTEN is set.
> xfs_exchmaps_can_skip_mapping() can skip hole and unwritten mappings
> from file1, so an exchange can complete without moving every mapping
> that the earlier flag-swap decision accounted for. In that case the
> post-operation cleanup can clear the reflink flag from an inode that
> still owns shared written extents. Later writes then take the
> non-reflink write path and may update blocks that should still have
> been protected by CoW, which shows up as data corruption between
> reflink-related files.
>
> [...]
Applied to for-next, thanks!
[1/1] xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN
commit: b2d5a81dae385333f9734910277fbf94c78bd17f
Best regards,
--
Carlos Maiolino <cem@kernel.org>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v3] xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN
2026-07-28 7:19 [PATCH v3] xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN Lin Jiapeng
2026-08-03 13:22 ` Carlos Maiolino
@ 2026-08-31 8:03 ` Carlos Maiolino
2026-09-03 6:05 ` Carlos Maiolino
2 siblings, 0 replies; 4+ messages in thread
From: Carlos Maiolino @ 2026-08-31 8:03 UTC (permalink / raw)
To: Lin Jiapeng; +Cc: linux-xfs, stable, djwong, hch, jiapenglin
On Tue, Jul 28, 2026 at 03:19:10PM +0800, Lin Jiapeng wrote:
> When exchanging two full-file ranges, xmi_can_exchange_reflink_flags()
> can move the reflink inode flag from the file that currently has it to
> the other file, as long as exactly one side is marked. This assumes
> that the file contents, and therefore all shared extents, are exchanged.
>
> That assumption is not true when XFS_EXCHMAPS_INO1_WRITTEN is set.
> xfs_exchmaps_can_skip_mapping() can skip hole and unwritten mappings
> from file1, so an exchange can complete without moving every mapping
> that the earlier flag-swap decision accounted for. In that case the
> post-operation cleanup can clear the reflink flag from an inode that
> still owns shared written extents. Later writes then take the
> non-reflink write path and may update blocks that should still have
> been protected by CoW, which shows up as data corruption between
> reflink-related files.
>
> Fix this by disabling the reflink flag exchange whenever
> XFS_EXCHMAPS_INO1_WRITTEN is requested. The contents exchange can still
> proceed; the conservative outcome is that both inodes keep the reflink
> flag. The regular reflink flag cleanup path can drop the extra flag
> later once the inode no longer has shared extents.
>
> Reported-by: Lin Jiapeng(TencentOS Red Team) <jiapenglin@tencent.com>
> Fixes: 966ceafc7a43 ("xfs: create deferred log items for file mapping exchanges")
> Cc: <stable@vger.kernel.org> # v6.10
> Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Signed-off-by: Lin Jiapeng <jiapenglin@tencent.com>
You don't need to send new versions just to add RwBs to the patch, we
can retrieve them from the list.
Also for any new versions, please add a changelog so we can easily
understand why the new version.
> ---
> fs/xfs/libxfs/xfs_exchmaps.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/fs/xfs/libxfs/xfs_exchmaps.c b/fs/xfs/libxfs/xfs_exchmaps.c
> index dcd0bd0b13b4..3efed37cb98a 100644
> --- a/fs/xfs/libxfs/xfs_exchmaps.c
> +++ b/fs/xfs/libxfs/xfs_exchmaps.c
> @@ -959,6 +959,16 @@ xmi_can_exchange_reflink_flags(
> {
> struct xfs_mount *mp = req->ip1->i_mount;
>
> + /*
> + * The INO1_WRITTEN optimization can skip exchanging hole and
> + * unwritten mappings, which means we cannot guarantee that all
> + * shared extents actually moved to the other file. Clearing the
> + * reflink flag of an inode that still holds shared extents breaks
> + * the CoW write path, so refuse to exchange the flags in that case.
> + */
> + if (req->flags & XFS_EXCHMAPS_INO1_WRITTEN)
> + return false;
> +
> if (hweight32(reflink_state) != 1)
> return false;
> if (req->startoff1 != 0 || req->startoff2 != 0)
> --
> 2.50.1 (Apple Git-155)
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v3] xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN
2026-07-28 7:19 [PATCH v3] xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN Lin Jiapeng
2026-08-03 13:22 ` Carlos Maiolino
2026-08-31 8:03 ` Carlos Maiolino
@ 2026-09-03 6:05 ` Carlos Maiolino
2 siblings, 0 replies; 4+ messages in thread
From: Carlos Maiolino @ 2026-09-03 6:05 UTC (permalink / raw)
To: linux-xfs, Lin Jiapeng; +Cc: stable, djwong, hch, jiapenglin
On Tue, 28 Jul 2026 15:19:10 +0800, Lin Jiapeng wrote:
> When exchanging two full-file ranges, xmi_can_exchange_reflink_flags()
> can move the reflink inode flag from the file that currently has it to
> the other file, as long as exactly one side is marked. This assumes
> that the file contents, and therefore all shared extents, are exchanged.
>
> That assumption is not true when XFS_EXCHMAPS_INO1_WRITTEN is set.
> xfs_exchmaps_can_skip_mapping() can skip hole and unwritten mappings
> from file1, so an exchange can complete without moving every mapping
> that the earlier flag-swap decision accounted for. In that case the
> post-operation cleanup can clear the reflink flag from an inode that
> still owns shared written extents. Later writes then take the
> non-reflink write path and may update blocks that should still have
> been protected by CoW, which shows up as data corruption between
> reflink-related files.
>
> [...]
Applied to for-next, thanks!
[1/1] xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN
commit: f3772e189ee8e37860c2bb365f6ac3517db937e9
Best regards,
--
Carlos Maiolino <cem@kernel.org>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-03 6:06 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-28 7:19 [PATCH v3] xfs: fix exchange-range reflink flag clearing issue with INO1_WRITTEN Lin Jiapeng
2026-08-03 13:22 ` Carlos Maiolino
2026-08-31 8:03 ` Carlos Maiolino
2026-09-03 6:05 ` Carlos Maiolino
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox