From: Chris Mason <mason@kernel.org>
To: mason@kernel.org, tytso@mit.edu, cem@kernel.org,
david@fromorbit.com, jack@suse.cz, djwong@kernel.org,
josef@toxicpanda.com, hch@lst.de, linux-xfs@vger.kernel.org,
linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org,
tz2294@columbia.edu, brauner@kernel.org
Subject: [PATCH v8 11/15] xfs: restart faults racing with realtime flag changes
Date: Wed, 11 Nov 2026 20:02:40 -0500 [thread overview]
Message-ID: <20261112010229.51029-12-mason@kernel.org> (raw)
In-Reply-To: <20261112010229.51029-1-mason@kernel.org>
On a zoned XFS, a store through a shared mapping can dereference a NULL
pointer, or corrupt the free block counter, if the realtime flag of the
file changes during the write fault.
xfs_write_fault() reserves zoned space only for a zoned inode, and tests
for that with no lock held. xfs_buffered_write_iomap_begin() tests again
before it takes the ILOCK. FS_IOC_FSSETXATTR can change the flag of a
file with no blocks between the two tests, since a fault never takes the
IOLOCK:
write fault FS_IOC_FSSETXATTR
=========== =================
xfs_write_fault()
sees that the inode is not zoned
sets the realtime flag
xfs_buffered_write_iomap_begin()
sees that the inode is zoned
/* ac is NULL */
If the flag is cleared instead, xfs_zoned_buffered_write_iomap_begin()
can be waiting for the ILOCK at that time. It then reserves blocks the
zoned way on a regular inode, and the free block counter ends up too
high.
The fix used here is to test again under the ILOCK, before blocks are
reserved or allocated, and to make the fault start over if the flag has
changed. Any other caller that gets there fails, as a write does.
Fixes: 058dd70c65ab ("xfs: implement buffered writes to zoned RT devices")
Signed-off-by: Chris Mason <mason@kernel.org>
---
Notes:
v7->v8:
- Only a page fault gets -EAGAIN. Any other caller that gets to one of
the tests fails with -EINVAL, as a write and an fallocate do. pNFS can
get there: xfs_fs_map_blocks() tests the flag before it takes its
locks (Christoph Hellwig).
- The warning now says "during block mapping".
- The helper reads the inode number with I_INO(), and its comment no
longer says that the flag is stable once the inode has blocks.
- Was 11/11.
v6->v7:
- xfs_direct_write_iomap_begin() tests the flag too, as soon as it holds
the ILOCK. It could allocate blocks for a COW fork extent before it
got to the test in xfs_iomap_write_direct().
- The assert on the extent size hint in
xfs_zoned_buffered_write_iomap_begin() moved below the test of the
flag.
- Dropped the Reviewed-by of Christoph Hellwig, since the patch changed.
- Was 10/10.
fs/xfs/xfs_iomap.c | 42 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index c3465204b8d5..d36650450cbb 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -264,6 +264,25 @@ xfs_iomap_eof_align_last_fsb(
return end_fsb;
}
+/*
+ * A write fault picks the zoned or the regular path before it takes a lock, and
+ * it never takes the IOLOCK. The realtime flag cannot change under the ILOCK,
+ * so look at it again there, before reserving or allocating blocks. Only a
+ * fault can start over, so refuse any other caller, as the write path does.
+ */
+static int
+xfs_iomap_rtflag_changed(
+ struct xfs_inode *ip,
+ unsigned int flags)
+{
+ xfs_warn_ratelimited(ip->i_mount,
+ "RT flag modifying during block mapping for inode 0x%llx.",
+ I_INO(ip));
+ if (flags & IOMAP_FAULT)
+ return -EAGAIN;
+ return -EINVAL;
+}
+
int
xfs_iomap_write_direct(
struct xfs_inode *ip,
@@ -334,6 +353,11 @@ xfs_iomap_write_direct(
if (error)
return error;
+ if (xfs_is_zoned_inode(ip)) {
+ error = xfs_iomap_rtflag_changed(ip, flags);
+ goto out_trans_cancel;
+ }
+
error = xfs_iext_count_extend(tp, ip, XFS_DATA_FORK, nr_exts);
if (error)
goto out_trans_cancel;
@@ -919,6 +943,11 @@ xfs_direct_write_iomap_begin(
if (error)
return error;
+ if (xfs_is_zoned_inode(ip)) {
+ error = xfs_iomap_rtflag_changed(ip, flags);
+ goto out_unlock;
+ }
+
/*
* The reflink iflag could have changed since the earlier unlocked
* check, check if it again and relock if needed.
@@ -1666,9 +1695,7 @@ xfs_zoned_buffered_write_iomap_begin(
struct xfs_iext_cursor icur;
int error = 0;
- ASSERT(!xfs_get_extsz_hint(ip));
ASSERT(!(flags & IOMAP_UNSHARE));
- ASSERT(ac);
if (xfs_is_shutdown(mp))
return -EIO;
@@ -1682,6 +1709,12 @@ xfs_zoned_buffered_write_iomap_begin(
if (error)
return error;
+ if (!xfs_is_zoned_inode(ip) || !ac) {
+ error = xfs_iomap_rtflag_changed(ip, flags);
+ goto out_unlock;
+ }
+ ASSERT(!xfs_get_extsz_hint(ip));
+
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(&ip->i_df)) ||
XFS_TEST_ERROR(mp, XFS_ERRTAG_BMAPIFORMAT)) {
xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
@@ -1865,6 +1898,11 @@ xfs_buffered_write_iomap_begin(
if (error)
return error;
+ if (xfs_is_zoned_inode(ip)) {
+ error = xfs_iomap_rtflag_changed(ip, flags);
+ goto out_unlock;
+ }
+
if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(&ip->i_df)) ||
XFS_TEST_ERROR(mp, XFS_ERRTAG_BMAPIFORMAT)) {
xfs_bmap_mark_sick(ip, XFS_DATA_FORK);
--
2.55.0
next prev parent reply other threads:[~2026-11-12 1:02 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-12 1:02 [PATCH v8 00/15] reflink and atomic write bugs Chris Mason
2026-11-12 1:02 ` [PATCH v8 01/15] xfs: don't skip the flush before shifting extents Chris Mason
2026-11-12 1:02 ` [PATCH v8 02/15] xfs: flush the shifted range before changing the file Chris Mason
2026-11-12 1:02 ` [PATCH v8 03/15] xfs: don't change the block map under a dirty folio Chris Mason
2026-11-12 1:02 ` [PATCH v8 04/15] iomap: don't punch delalloc under a dirty EOF block Chris Mason
2026-11-12 1:02 ` [PATCH v8 05/15] fs: validate atomic writes after O_APPEND and limits Chris Mason
2026-11-12 1:02 ` [PATCH v8 06/15] xfs: recheck direct write alignment after write checks Chris Mason
2026-11-12 1:02 ` [PATCH v8 07/15] xfs: test for reflink after the dio " Chris Mason
2026-11-12 1:02 ` [PATCH v8 08/15] xfs: refuse writes to files racing with realtime inode flag changes Chris Mason
2026-11-12 1:02 ` [PATCH v8 09/15] xfs: test for always COW after the dio write checks Chris Mason
2026-11-12 1:02 ` [PATCH v8 10/15] xfs: refuse fallocate racing with realtime flag changes Chris Mason
2026-11-12 1:02 ` Chris Mason [this message]
2026-11-12 13:34 ` [PATCH v8 11/15] xfs: restart faults " Christoph Hellwig
2026-11-12 1:02 ` [PATCH v8 12/15] xfs: test for an extsize hint again under the ILOCK Chris Mason
2026-11-12 13:35 ` Christoph Hellwig
2026-11-12 1:02 ` [PATCH v8 13/15] xfs: resample the extsize hint after taking " Chris Mason
2026-11-12 13:35 ` Christoph Hellwig
2026-11-12 13:49 ` Chris Mason
2026-11-12 1:02 ` [PATCH v8 14/15] xfs: resample the COW extsize hint after cycling ILOCK Chris Mason
2026-11-12 13:36 ` Christoph Hellwig
2026-11-12 1:02 ` [PATCH v8 15/15] xfs: don't enable DAX on zoned inodes Chris Mason
2026-11-12 13:39 ` Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261112010229.51029-12-mason@kernel.org \
--to=mason@kernel.org \
--cc=brauner@kernel.org \
--cc=cem@kernel.org \
--cc=david@fromorbit.com \
--cc=djwong@kernel.org \
--cc=hch@lst.de \
--cc=jack@suse.cz \
--cc=josef@toxicpanda.com \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=tytso@mit.edu \
--cc=tz2294@columbia.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox