linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] ext4: fix racy may inline data check in dio write
@ 2023-10-02 18:50 Brian Foster
  2023-10-06 18:06 ` Theodore Ts'o
  0 siblings, 1 reply; 2+ messages in thread
From: Brian Foster @ 2023-10-02 18:50 UTC (permalink / raw)
  To: linux-ext4

syzbot reports that the following warning from ext4_iomap_begin()
triggers as of the commit referenced below:

        if (WARN_ON_ONCE(ext4_has_inline_data(inode)))
                return -ERANGE;

This occurs during a dio write, which is never expected to encounter
an inode with inline data. To enforce this behavior,
ext4_dio_write_iter() checks the current inline state of the inode
and clears the MAY_INLINE_DATA state flag to either fall back to
buffered writes, or enforce that any other writers in progress on
the inode are not allowed to create inline data.

The problem is that the check for existing inline data and the state
flag can span a lock cycle. For example, if the ilock is originally
locked shared and subsequently upgraded to exclusive, another writer
may have reacquired the lock and created inline data before the dio
write task acquires the lock and proceeds.

The commit referenced below loosens the lock requirements to allow
some forms of unaligned dio writes to occur under shared lock, but
AFAICT the inline data check was technically already racy for any
dio write that would have involved a lock cycle. Regardless, lift
clearing of the state bit to the same lock critical section that
checks for preexisting inline data on the inode to close the race.

Reported-by: syzbot+307da6ca5cb0d01d581a@syzkaller.appspotmail.com
Fixes: 310ee0902b8d ("ext4: allow concurrent unaligned dio overwrites")
Signed-off-by: Brian Foster <bfoster@redhat.com>
---

Hi all,

Obviously there's a few different ways to address this, but this seemed
most straightforward to me. Another option could be to push more of this
checking down into _write_checks() to retry the should_use_dio() bits
after a lock cycle, for example. Let me know if anybody has other
thoughts.

Otherwise, this addresses the syzbot report [1] (see the couple of debug
patch test runs) and survives an fstests regression run. Thanks.

Brian

[1] https://lore.kernel.org/linux-ext4/0000000000005697bd05fe4aea49@google.com/

 fs/ext4/file.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 6830ea3a6c59..747c0378122d 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -569,18 +569,20 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
 		return ext4_buffered_write_iter(iocb, from);
 	}
 
+	/*
+	 * Prevent inline data from being created since we are going to allocate
+	 * blocks for DIO. We know the inode does not currently have inline data
+	 * because ext4_should_use_dio() checked for it, but we have to clear
+	 * the state flag before the write checks because a lock cycle could
+	 * introduce races with other writers.
+	 */
+	ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
+
 	ret = ext4_dio_write_checks(iocb, from, &ilock_shared, &extend,
 				    &unwritten, &dio_flags);
 	if (ret <= 0)
 		return ret;
 
-	/*
-	 * Make sure inline data cannot be created anymore since we are going
-	 * to allocate blocks for DIO. We know the inode does not have any
-	 * inline data now because ext4_dio_supported() checked for that.
-	 */
-	ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
-
 	offset = iocb->ki_pos;
 	count = ret;
 
-- 
2.41.0


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

* Re: [PATCH] ext4: fix racy may inline data check in dio write
  2023-10-02 18:50 [PATCH] ext4: fix racy may inline data check in dio write Brian Foster
@ 2023-10-06 18:06 ` Theodore Ts'o
  0 siblings, 0 replies; 2+ messages in thread
From: Theodore Ts'o @ 2023-10-06 18:06 UTC (permalink / raw)
  To: linux-ext4, Brian Foster; +Cc: Theodore Ts'o


On Mon, 02 Oct 2023 14:50:20 -0400, Brian Foster wrote:
> syzbot reports that the following warning from ext4_iomap_begin()
> triggers as of the commit referenced below:
> 
>         if (WARN_ON_ONCE(ext4_has_inline_data(inode)))
>                 return -ERANGE;
> 
> This occurs during a dio write, which is never expected to encounter
> an inode with inline data. To enforce this behavior,
> ext4_dio_write_iter() checks the current inline state of the inode
> and clears the MAY_INLINE_DATA state flag to either fall back to
> buffered writes, or enforce that any other writers in progress on
> the inode are not allowed to create inline data.
> 
> [...]

Applied, thanks!

[1/1] ext4: fix racy may inline data check in dio write
      commit: a37d4c46392e207518deb6533768986634b193c0

Best regards,
-- 
Theodore Ts'o <tytso@mit.edu>

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

end of thread, other threads:[~2023-10-06 18:06 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-02 18:50 [PATCH] ext4: fix racy may inline data check in dio write Brian Foster
2023-10-06 18:06 ` Theodore Ts'o

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).