All of lore.kernel.org
 help / color / mirror / Atom feed
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 v9 11/14] xfs: take the MMAPLOCK in xfs_fileattr_set()
Date: Thu, 12 Nov 2026 16:46:15 -0500	[thread overview]
Message-ID: <20261112214604.67875-12-mason@kernel.org> (raw)
In-Reply-To: <20261112214604.67875-1-mason@kernel.org>

A store through a shared mapping can corrupt a realtime file system on
disk, or shut a file system down, if FS_IOC_FSSETXATTR changes the
realtime flag or an extent size hint of the file during the write fault.

A write fault reads the flag and the hints more than once: to choose
delayed allocation, to size the block reservation, and again in the
allocator. All of these have to see the same values. System calls that
write do the same, but they hold the IOLOCK, which keeps the ioctl out.
A fault only holds the MMAPLOCK, which the ioctl does not take:

    write fault                         FS_IOC_FSSETXATTR
    ===========                         =================
    takes the MMAPLOCK
    xfs_iomap_write_direct()
      reserves blocks for the old hint
                                        takes the ILOCK
                                        raises the hint
                                        drops the ILOCK
      takes the ILOCK
      xfs_bmapi_write()
        allocates for the new hint
        /* more than was reserved */

The fix used here is to make the ioctl take the MMAPLOCK of a regular
file as well.

Signed-off-by: Chris Mason <mason@kernel.org>
---

Notes:
    v8->v9:
    - New patch.

 fs/xfs/xfs_inode.c |  3 ++-
 fs/xfs/xfs_ioctl.c | 17 +++++++++++++++--
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index cb61305e4b80..0584ad11f92b 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -134,7 +134,8 @@ xfs_lock_flags_assert(
  * take both the i_rwsem and the invalidate_lock. These locks should *only* be
  * both taken in places where we need to invalidate the page cache in a race
  * free manner (e.g. truncate, hole punch and other extent manipulation
- * functions).
+ * functions), or where we change inode attributes that both kinds of IO rely
+ * on (xfs_fileattr_set).
  */
 void
 xfs_ilock(
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index f81b6e52ac40..af13ad6784b7 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -757,6 +757,7 @@ xfs_fileattr_set(
 	struct xfs_trans	*tp;
 	struct xfs_dquot	*pdqp = NULL;
 	struct xfs_dquot	*olddquot = NULL;
+	bool			isreg = S_ISREG(VFS_I(ip)->i_mode);
 	int			error;
 
 	trace_xfs_ioctl_setattr(ip);
@@ -804,10 +805,18 @@ xfs_fileattr_set(
 
 	xfs_ioctl_setattr_prepare_dax(ip, fa);
 
+	/*
+	 * A write fault only holds the MMAPLOCK, and it looks at the realtime
+	 * flag and at the extent size hints more than once.  Only regular files
+	 * have write faults.
+	 */
+	if (isreg)
+		xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
+
 	tp = xfs_ioctl_setattr_get_trans(ip, pdqp);
 	if (IS_ERR(tp)) {
 		error = PTR_ERR(tp);
-		goto error_free_dquots;
+		goto error_unlock;
 	}
 
 	error = xfs_ioctl_setattr_check_extsize(ip, fa);
@@ -864,6 +873,8 @@ xfs_fileattr_set(
 
 skip_xattr:
 	error = xfs_trans_commit(tp);
+	if (isreg)
+		xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
 
 	/*
 	 * Release any dquot(s) the inode had kept before chown.
@@ -875,7 +886,9 @@ xfs_fileattr_set(
 
 error_trans_cancel:
 	xfs_trans_cancel(tp);
-error_free_dquots:
+error_unlock:
+	if (isreg)
+		xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
 	xfs_qm_dqrele(pdqp);
 	return error;
 }
-- 
2.55.0


  parent reply	other threads:[~2026-11-12 21:46 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-12 21:46 [PATCH v9 00/14] reflink and atomic write bugs Chris Mason
2026-11-12 21:46 ` [PATCH v9 01/14] xfs: don't skip the flush before shifting extents Chris Mason
2026-11-12 21:55   ` sashiko-bot
2026-11-12 21:46 ` [PATCH v9 02/14] xfs: flush the shifted range before changing the file Chris Mason
2026-11-12 21:54   ` sashiko-bot
2026-11-12 21:46 ` [PATCH v9 03/14] xfs: don't change the block map under a dirty folio Chris Mason
2026-11-12 22:03   ` sashiko-bot
2026-11-12 21:46 ` [PATCH v9 04/14] iomap: don't punch delalloc under a dirty EOF block Chris Mason
2026-11-12 21:54   ` sashiko-bot
2026-11-12 21:46 ` [PATCH v9 05/14] fs: validate atomic writes after O_APPEND and limits Chris Mason
2026-11-12 22:16   ` sashiko-bot
2026-11-12 21:46 ` [PATCH v9 06/14] xfs: recheck direct write alignment after write checks Chris Mason
2026-11-12 22:22   ` sashiko-bot
2026-11-12 21:46 ` [PATCH v9 07/14] xfs: test for reflink after the dio " Chris Mason
2026-11-12 21:54   ` sashiko-bot
2026-11-12 21:46 ` [PATCH v9 08/14] xfs: refuse writes to files racing with realtime inode flag changes Chris Mason
2026-11-12 22:11   ` sashiko-bot
2026-11-12 21:46 ` [PATCH v9 09/14] xfs: test for always COW after the dio write checks Chris Mason
2026-11-12 21:53   ` sashiko-bot
2026-11-12 21:46 ` [PATCH v9 10/14] xfs: refuse fallocate racing with realtime flag changes Chris Mason
2026-11-12 22:11   ` sashiko-bot
2026-11-12 21:46 ` Chris Mason [this message]
2026-11-12 22:13   ` [PATCH v9 11/14] xfs: take the MMAPLOCK in xfs_fileattr_set() sashiko-bot
2026-11-12 23:49   ` Christoph Hellwig
2026-11-12 21:46 ` [PATCH v9 12/14] xfs: restart faults racing with realtime flag changes Chris Mason
2026-11-12 22:08   ` sashiko-bot
2026-11-12 23:50   ` Christoph Hellwig
2026-11-12 21:46 ` [PATCH v9 13/14] xfs: don't enable DAX on zoned inodes Chris Mason
2026-11-12 22:03   ` sashiko-bot
2026-11-12 23:50   ` Christoph Hellwig
2026-11-12 21:46 ` [PATCH v9 14/14] xfs: test for realtime and reflink under the pNFS locks Chris Mason
2026-11-12 22:02   ` sashiko-bot
2026-11-12 23:51   ` 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=20261112214604.67875-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.