Re: [PATCH 06/22] block,iomap: fix protection information verification with initial bvec offset
Andrey Albershteyn <[email protected]> Wed, 29 Jul 2026 11:52:46 +0200
| Newsgroups | org.kernel.vger.linux-xfs,org.kernel.vger.linux-block,org.kernel.vger.linux-fsdevel |
|---|---|
| Message-ID | <[email protected]> |
On 2026-07-23 16:49:31, Christoph Hellwig wrote:
> When reconstructing a bvec_iter from an ioend for protection information
> verification, iomap currently ignores the offset into the initial
> bio_vec.
>
> This can't happen for buffered I/O an direct I/O to user addresses, but
> is exercised by split on O_DIRECT file descriptors or when using the loop
> driver.
>
> Fortunately the only file system PI user (XFS) currently always bounce
> buffers, so this can't actually be triggered yet. But we'll want to make
> the bounce buffering conditional soon, for which this needs to be fixed.
>
> Store the initial offset in struct iomap_ioend, and pass a
> pre-constructed bvec_iter to fs_bio_integrity_verify. For the
> synchronous read case the fix is even simpler as this path can
> simply stash away the original bvec_iter.
>
> Fixes: 0bde8a12b554 ("block: add fs_bio_integrity helpers")
> Signed-off-by: Christoph Hellwig <[email protected]>
> ---
> block/bio-integrity-fs.c | 13 +++++--------
> fs/iomap/bio.c | 4 +++-
> fs/iomap/ioend.c | 14 ++++++++++----
> include/linux/bio-integrity.h | 3 +--
> include/linux/iomap.h | 8 ++++++++
> 5 files changed, 27 insertions(+), 15 deletions(-)
>
> diff --git a/block/bio-integrity-fs.c b/block/bio-integrity-fs.c
> index 692403dfa047..dd6c85530913 100644
> --- a/block/bio-integrity-fs.c
> +++ b/block/bio-integrity-fs.c
> @@ -52,14 +52,10 @@ void fs_bio_integrity_generate(struct bio *bio)
> }
> EXPORT_SYMBOL_GPL(fs_bio_integrity_generate);
>
> -int fs_bio_integrity_verify(struct bio *bio, sector_t sector, unsigned int size)
> +int fs_bio_integrity_verify(struct bio *bio, struct bvec_iter *data_iter)
> {
> struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
> struct bio_integrity_payload *bip = bio_integrity(bio);
> - struct bvec_iter data_iter = {
> - .bi_sector = sector,
> - .bi_size = size,
> - };
>
> if (!bip || !(bip->bip_flags & BIP_CHECK_FLAGS))
> return 0;
> @@ -71,9 +67,10 @@ int fs_bio_integrity_verify(struct bio *bio, sector_t sector, unsigned int size)
> * bio. Requires the submitter to remember the sector and the size.
> */
> memset(&bip->bip_iter, 0, sizeof(bip->bip_iter));
> - bip->bip_iter.bi_sector = sector;
> - bip->bip_iter.bi_size = bio_integrity_bytes(bi, size >> SECTOR_SHIFT);
> - return blk_status_to_errno(bio_integrity_verify(bio, &data_iter));
> + bip->bip_iter.bi_sector = data_iter->bi_sector;
> + bip->bip_iter.bi_size =
> + bio_integrity_bytes(bi, data_iter->bi_size >> SECTOR_SHIFT);
> + return blk_status_to_errno(bio_integrity_verify(bio, data_iter));
> }
>
> static int __init fs_bio_integrity_init(void)
> diff --git a/fs/iomap/bio.c b/fs/iomap/bio.c
> index 30ef78a66b4f..813002b2299d 100644
> --- a/fs/iomap/bio.c
> +++ b/fs/iomap/bio.c
> @@ -169,6 +169,7 @@ int iomap_bio_read_folio_range_sync(const struct iomap_iter *iter,
> {
> const struct iomap *srcmap = iomap_iter_srcmap(iter);
> sector_t sector = iomap_sector(srcmap, pos);
> + struct bvec_iter saved_iter;
> struct bio_vec bvec;
> struct bio bio;
> int error;
> @@ -178,10 +179,11 @@ int iomap_bio_read_folio_range_sync(const struct iomap_iter *iter,
> bio_add_folio_nofail(&bio, folio, len, offset_in_folio(folio, pos));
> if (srcmap->flags & IOMAP_F_INTEGRITY)
> fs_bio_integrity_alloc(&bio);
> + saved_iter = bio.bi_iter;
> error = submit_bio_wait(&bio);
> if (bio_integrity(&bio)) {
> if (!error)
> - error = fs_bio_integrity_verify(&bio, sector, len);
> + error = fs_bio_integrity_verify(&bio, &saved_iter);
> fs_bio_integrity_free(&bio);
> }
> return error;
> diff --git a/fs/iomap/ioend.c b/fs/iomap/ioend.c
> index 2ec755a89228..d43e6229900c 100644
> --- a/fs/iomap/ioend.c
> +++ b/fs/iomap/ioend.c
> @@ -25,6 +25,7 @@ struct iomap_ioend *iomap_init_ioend(struct inode *inode,
> ioend->io_parent = NULL;
> INIT_LIST_HEAD(&ioend->io_list);
> ioend->io_flags = ioend_flags;
> + ioend->io_bvec_offset = bio->bi_iter.bi_bvec_done;
> ioend->io_inode = inode;
> ioend->io_offset = file_offset;
> ioend->io_size = bio->bi_iter.bi_size;
> @@ -311,6 +312,13 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
> }
> EXPORT_SYMBOL_GPL(iomap_add_to_ioend);
>
> +static int iomap_ioend_integrity_verify(struct iomap_ioend *ioend)
> +{
> + struct bvec_iter data_iter = BVEC_ITER_IOEND(ioend);
> +
> + return fs_bio_integrity_verify(&ioend->io_bio, &data_iter);
> +}
> +
> static u32 iomap_finish_ioend(struct iomap_ioend *ioend, int error)
> {
> if (ioend->io_parent) {
> @@ -328,10 +336,8 @@ static u32 iomap_finish_ioend(struct iomap_ioend *ioend, int error)
>
> if (!ioend->io_error &&
> bio_integrity(&ioend->io_bio) &&
> - bio_op(&ioend->io_bio) == REQ_OP_READ) {
> - ioend->io_error = fs_bio_integrity_verify(&ioend->io_bio,
> - ioend->io_sector, ioend->io_size);
> - }
> + bio_op(&ioend->io_bio) == REQ_OP_READ)
> + ioend->io_error = iomap_ioend_integrity_verify(ioend);
>
> if (ioend->io_flags & IOMAP_IOEND_DIRECT)
> return iomap_finish_ioend_direct(ioend);
> diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h
> index 0ea2a8bf7efb..a954c97be0b3 100644
> --- a/include/linux/bio-integrity.h
> +++ b/include/linux/bio-integrity.h
> @@ -151,7 +151,6 @@ void bio_integrity_setup_default(struct bio *bio);
> unsigned int fs_bio_integrity_alloc(struct bio *bio);
> void fs_bio_integrity_free(struct bio *bio);
> void fs_bio_integrity_generate(struct bio *bio);
> -int fs_bio_integrity_verify(struct bio *bio, sector_t sector,
> - unsigned int size);
> +int fs_bio_integrity_verify(struct bio *bio, struct bvec_iter *data_iter);
shouldn't this have a static inline stub if BLK_DEV_INTEGRITY=no?
linker fails to resolve this in ioend.c
not sure why _generate and rest are apparently fine
--
- Andrey