All of lore.kernel.org
 help / color / mirror / Atom feed
From: John Garry <john.g.garry@oracle.com>
To: Tal Zussman <tz2294@columbia.edu>, Jens Axboe <axboe@kernel.dk>,
	Christoph Hellwig <hch@lst.de>,
	Johannes Thumshirn <johannes.thumshirn@wdc.com>,
	Luis Chamberlain <mcgrof@kernel.org>,
	Hannes Reinecke <hare@suse.de>,
	"Matthew Wilcox (Oracle)" <willy@infradead.org>,
	Christian Brauner <brauner@kernel.org>,
	"Darrick J. Wong" <djwong@kernel.org>,
	Keith Busch <kbusch@kernel.org>,
	"Martin K. Petersen" <martin.petersen@oracle.com>,
	john.garry@linux.dev
Cc: linux-block@vger.kernel.org, linux-kernel@vger.kernel.org,
	Sashiko <sashiko-bot@kernel.org>
Subject: Re: [PATCH v2 5/7] block: fail atomic writes instead of falling back to buffered I/O
Date: Mon, 7 Sep 2026 08:49:54 +0100	[thread overview]
Message-ID: <a7752d1e-8ec1-44d1-a266-c287c315e8ab@oracle.com> (raw)
In-Reply-To: <20260828-blkdev-fixes-v2-5-32f3f40cebed@columbia.edu>

On 28/08/2026 14:49, Tal Zussman wrote:
> An IOCB_ATOMIC direct write to a block device can silently lose its
> torn-write guarantee in two ways:
> 
>     1. blkdev_direct_write() turns an -EBUSY from page cache invalidation
>        into a 0 return, so the whole write is retried through
>        blkdev_buffered_write(), with no atomicity guarantee.
> 
>     2. On a partial page pin, __blkdev_direct_IO_simple() and
>        __blkdev_direct_IO_async() submit what was pinned with REQ_ATOMIC
>        set and leave the rest to the buffered fallback.
> 
> The second case can be triggered deterministically. A 16K
> pwritev2(RWF_ATOMIC) whose last page is PROT_NONE, on a scsi_debug

If there is some scenario which does not allow the iovec to be written 
atomically for RWF_ATOMIC, then we should document it in the man pages 
description of RWF_ATOMIC.

> device with atomic_wr=1, completes short with only three of the four
> pages written, violating RWF_ATOMIC semantics.
> 
> Fail the I/O instead. Return -EAGAIN when page cache invalidation fails
> for IOCB_ATOMIC rather than retrying through the page cache, matching
> __iomap_dio_rw(), which treats the failure as transient and lets the
> caller retry. Release a short atomic pin and return -EFAULT before
> submission, which is what a direct write already returns when none of
> the buffer can be pinned. A sync atomic write can then never return
> short with a remainder, so the buffered fallback is never reached.
> 
> ext4 has the same fallback and only warns in it. 

It should reject it, as IOCB_ATOMIC would be ignored in that path.

> For block devices both
> ways in can be detected before any I/O is submitted, so fail early instead.
> 
> Fixes: caf336f81b3a ("block: Add fops atomic write support")
> Reported-by: Sashiko<sashiko-bot@kernel.org>
> Link:https://urldefense.com/v3/__https://sashiko.dev/*/patchset/20260802-blkdev-
> fixes-v1-0-a82fc549fd74*40columbia.edu?part=2__;IyU!!ACWV5N9M2RV99hQ!
> Ot6CcSo02WbMqinlLCziLAkOQYQGgeUA0ZNlGPWcDEbGge8zNfHyjKzp4_TU7rV9CEVu9_fWOEwt6d_RQBbgVw$<https://urldefense.com/v3/__https://sashiko.dev/*/patchset/20260802- 
> blkdev-fixes-v1-0-a82fc549fd74*40columbia.edu?part=2__;IyU!! 
> ACWV5N9M2RV99hQ! 
> Ot6CcSo02WbMqinlLCziLAkOQYQGgeUA0ZNlGPWcDEbGge8zNfHyjKzp4_TU7rV9CEVu9_fWOEwt6d_RQBbgVw$>
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: Tal Zussman<tz2294@columbia.edu>
> ---
>    block/fops.c | 21 ++++++++++++++++++++-
>    1 file changed, 20 insertions(+), 1 deletion(-)
> 
> diff --git a/block/fops.c b/block/fops.c
> index a3a709697b40..8769bb13df1c 100644
> --- a/block/fops.c
> +++ b/block/fops.c
> @@ -87,6 +87,12 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
>    	ret = blkdev_iov_iter_get_pages(&bio, iter, bdev);
>    	if (unlikely(ret))
>    		goto out;
> +	if ((iocb->ki_flags & IOCB_ATOMIC) && iov_iter_count(iter)) {

Could we even move this check into bio_iov_iter_get_pages()? 
bio_iov_iter_get_pages() is used in fs/iomap/direct-io.c in the same 
fashion, i.e. it's expected to be iter'ed only once for IOCB_ATOMIC.

If bio_iov_iter_get_pages() does not give all the pages for REQ_ATOMIC, 
then something is wrong and we should error. For this to work, we must 
ensure that bio_iov_iter_get_pages() is only called once for a 
REQ_ATOMIC bio - that would be the semantic.

> +		/* a short atomic write would be torn by definition */
> +		bio_release_pages(&bio, false);
> +		ret = -EFAULT;

Eh, generally we return -EINVAL for something which can't be written 
atomically - like in iomap_dio_bio_iter_one(). -EFAULT is not documented 
for RWF_ATOMIC (afair).

> +		goto out;
> +	}
>    	ret = bio.bi_iter.bi_size;
>    
>    	if (iov_iter_rw(iter) == WRITE)
> @@ -352,6 +358,12 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
>    		ret = blkdev_iov_iter_get_pages(bio, iter, bdev);
>    		if (unlikely(ret))
>    			goto out_bio_put;
> +		if ((iocb->ki_flags & IOCB_ATOMIC) && iov_iter_count(iter)) {

At least this check could be factored out of 
__blkdev_direct_IO_simple(), right?

> +			/* a short atomic write would be torn by definition */
> +			bio_release_pages(bio, false);
> +			ret = -EFAULT;
> +			goto out_bio_put;
> +		}
>    	}
>    	dio->size = bio->bi_iter.bi_size;
>    
> @@ -691,8 +703,15 @@ blkdev_direct_write(struct kiocb *iocb, struct iov_iter *from)
>    
>    	written = kiocb_invalidate_pages(iocb, count);
>    	if (written) {
> -		if (written == -EBUSY)
> +		/*
> +		 * The buffered write fallback cannot provide torn-write
> +		 * protection, so atomic writes must fail instead.
> +		 */

Would it be better to have this check in direct_write_fallback(), i.e. 
always -EAGAIN in direct_write_fallback() for IOCB_ATOMIC?

> +		if (written == -EBUSY) {
> +			if (iocb->ki_flags & IOCB_ATOMIC)
> +				return -EAGAIN;
>    			return 0;
> +		}
>    		return written;
>    	}
>    
> 
> -- 
> 2.39.5


  parent reply	other threads:[~2026-09-07  7:50 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-28 13:49 [PATCH v2 0/7] block device fixes for large block sizes, IOCB_NOWAIT, and direct I/O Tal Zussman
2026-08-28 13:49 ` [PATCH v2 1/7] block: use iomap_dirty_folio for block devices Tal Zussman
2026-09-02 12:43   ` Hannes Reinecke
2026-08-28 13:49 ` [PATCH v2 2/7] block: take i_rwsem for the direct I/O write fallback Tal Zussman
2026-09-02 12:47   ` Hannes Reinecke
2026-09-04 16:22     ` Tal Zussman
2026-09-07  7:08   ` Christoph Hellwig
2026-09-07 23:15     ` Tal Zussman
2026-08-28 13:49 ` [PATCH v2 3/7] block: take i_rwsem for the splice read path Tal Zussman
2026-09-02 12:52   ` Hannes Reinecke
2026-09-07  7:10   ` Christoph Hellwig
2026-08-28 13:49 ` [PATCH v2 4/7] block: honor IOCB_NOWAIT in the block device buffered " Tal Zussman
2026-09-02 13:04   ` Hannes Reinecke
2026-09-07  7:11   ` Christoph Hellwig
2026-09-08  0:09     ` Tal Zussman
2026-08-28 13:49 ` [PATCH v2 5/7] block: fail atomic writes instead of falling back to buffered I/O Tal Zussman
2026-09-02 14:09   ` Hannes Reinecke
2026-09-07  7:12   ` Christoph Hellwig
2026-09-07  7:49   ` John Garry [this message]
2026-09-09  6:03     ` Tal Zussman
2026-08-28 13:49 ` [PATCH v2 6/7] block: unpin all pages of a bvec in bio_iov_iter_align_down() Tal Zussman
2026-08-28 14:36   ` Tal Zussman
2026-09-07  7:13     ` Christoph Hellwig
2026-09-08  0:11       ` Tal Zussman
2026-09-02 14:13   ` Hannes Reinecke
2026-08-28 13:49 ` [PATCH v2 7/7] block: remove dead metadata handling from the async direct I/O path Tal Zussman
2026-09-07  7:13   ` Christoph Hellwig
2026-08-28 15:32 ` [PATCH v2 0/7] block device fixes for large block sizes, IOCB_NOWAIT, and direct I/O Tal Zussman
2026-09-04 16:19 ` Tal Zussman

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=a7752d1e-8ec1-44d1-a266-c287c315e8ab@oracle.com \
    --to=john.g.garry@oracle.com \
    --cc=axboe@kernel.dk \
    --cc=brauner@kernel.org \
    --cc=djwong@kernel.org \
    --cc=hare@suse.de \
    --cc=hch@lst.de \
    --cc=johannes.thumshirn@wdc.com \
    --cc=john.garry@linux.dev \
    --cc=kbusch@kernel.org \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=martin.petersen@oracle.com \
    --cc=mcgrof@kernel.org \
    --cc=sashiko-bot@kernel.org \
    --cc=tz2294@columbia.edu \
    --cc=willy@infradead.org \
    /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.