block: don't fall back to buffered I/O for atomic writes

blkdev_direct_write() turns an -EBUSY from page cache invalidation into
a 0 return, so an IOCB_ATOMIC write is retried in full through
blkdev_buffered_write(), with no atomicity guarantee.

Skip the buffered fallback in blkdev_write_iter() for IOCB_ATOMIC, as
it already does for IOCB_NOWAIT, so the -EBUSY case returns -EAGAIN and
the caller retries, matching __iomap_dio_rw().

ext4 has the same fallback and only warns in it. For block devices the
fallback can be skipped before any I/O is submitted, so fail early
instead.

Fixes: caf336f81b ("block: Add fops atomic write support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/patchset/20260802-blkdev-fixes-v1-0-a82fc549fd74%40columbia.edu?part=2
Assisted-by: Claude:claude-fable-5
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: John Garry <john.garry@linux.dev>
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Link: https://patch.msgid.link/20261009-blkdev-fixes-v6-6-307939c387df@columbia.edu
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Tal Zussman 2026-10-09 12:50:14 -04:00 committed by Jens Axboe
parent 73a0ff6030
commit 9fd1afea19

View File

@ -782,10 +782,11 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (iocb->ki_flags & IOCB_DIRECT) {
ret = blkdev_direct_write(iocb, from);
if (ret >= 0 && iov_iter_count(from)) {
if (iocb->ki_flags & IOCB_NOWAIT) {
if (iocb->ki_flags & (IOCB_NOWAIT | IOCB_ATOMIC)) {
/*
* The buffered fallback blocks on i_rwsem and
* on writeback of the data it copied: return
* on writeback of the data it copied, and
* can't provide torn-write protection: return
* the short direct write instead and let the
* caller retry. The bytes already written
* still need a flush if REQ_FUA was not set.