From 695fe977f63b8b13250ef09df39212032be7604e Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Thu, 16 Apr 2026 19:57:27 -0600 Subject: [PATCH 1/6] block: use integrity interval instead of sector as seed bio_integrity_setup_default() and blk_integrity_iterate() set the integrity seed (initial reference tag) to the absolute address in the block device in units of 512-byte sectors. The seed is correctly incremented/decremented in units of integrity intervals in bio_integrity_map_iter(), bio_integrity_advance(), and blk_integrity_interval(). As a result, the ref tag written or read to a particular integrity interval on a block device with integrity interval size > 512 bytes varies with the starting offset of the read/write. Convert the initial seed to units of integrity intervals so a consistent ref tag is used for each integrity interval. Fixes: 3be91c4a3d09 ("block: Deprecate the use of the term sector in the context of block integrity") Fixes: 63573e359d05 ("bio-integrity: Restore original iterator on verify stage") Signed-off-by: Caleb Sander Mateos Reviewed-by: Anuj Gupta Reviewed-by: Christoph Hellwig --- block/bio-integrity.c | 3 ++- block/t10-pi.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/block/bio-integrity.c b/block/bio-integrity.c index e79eaf0477943..3ad6a6799f170 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -105,8 +105,9 @@ void bio_integrity_setup_default(struct bio *bio) { struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk); struct bio_integrity_payload *bip = bio_integrity(bio); + u64 seed = bio->bi_iter.bi_sector >> (bi->interval_exp - SECTOR_SHIFT); - bip_set_seed(bip, bio->bi_iter.bi_sector); + bip_set_seed(bip, seed); if (bi->csum_type) { bip->bip_flags |= BIP_CHECK_GUARD; diff --git a/block/t10-pi.c b/block/t10-pi.c index a19b4e102a837..e58d5eb6cefb8 100644 --- a/block/t10-pi.c +++ b/block/t10-pi.c @@ -310,6 +310,7 @@ static blk_status_t blk_integrity_iterate(struct bio *bio, { struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk); struct bio_integrity_payload *bip = bio_integrity(bio); + u64 seed = data_iter->bi_sector >> (bi->interval_exp - SECTOR_SHIFT); struct blk_integrity_iter iter = { .bio = bio, .bip = bip, @@ -317,7 +318,7 @@ static blk_status_t blk_integrity_iterate(struct bio *bio, .data_iter = *data_iter, .prot_iter = bip->bip_iter, .interval_remaining = 1 << bi->interval_exp, - .seed = data_iter->bi_sector, + .seed = seed, .csum = 0, }; blk_status_t ret = BLK_STS_OK; From 7c0a74fbfbecc950086f27f3396e2fc0b7c1fb5d Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Thu, 16 Apr 2026 19:57:28 -0600 Subject: [PATCH 2/6] bio-integrity-fs: pass data iter to bio_integrity_verify() bio_integrity_verify() expects the passed struct bvec_iter to be an iterator over bio data, not integrity. So construct a separate data bvec_iter without the bio_integrity_bytes() conversion and pass it to bio_integrity_verify() instead of bip_iter. Fixes: 0bde8a12b554 ("block: add fs_bio_integrity helpers") Signed-off-by: Caleb Sander Mateos Reviewed-by: Anuj Gupta Reviewed-by: Christoph Hellwig --- block/bio-integrity-fs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/block/bio-integrity-fs.c b/block/bio-integrity-fs.c index acb1e5f270d2b..0daa42d9ead77 100644 --- a/block/bio-integrity-fs.c +++ b/block/bio-integrity-fs.c @@ -55,6 +55,10 @@ int fs_bio_integrity_verify(struct bio *bio, sector_t sector, unsigned int size) { 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, + }; /* * Reinitialize bip->bip_iter. @@ -65,7 +69,7 @@ int fs_bio_integrity_verify(struct bio *bio, sector_t sector, unsigned int 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, &bip->bip_iter)); + return blk_status_to_errno(bio_integrity_verify(bio, &data_iter)); } static int __init fs_bio_integrity_init(void) From 51abee0e499feeb849a92f56370f35aa6744dc9d Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Thu, 16 Apr 2026 19:57:29 -0600 Subject: [PATCH 3/6] blk-integrity: take u64 in bio_integrity_intervals() To allow bio_integrity_intervals() to convert an absolute sector to an absolute integrity interval, use u64 for its argument and return types. Also use SECTOR_SHIFT instead of the magic constant 9. Signed-off-by: Caleb Sander Mateos Reviewed-by: Anuj Gupta Reviewed-by: Christoph Hellwig --- include/linux/blk-integrity.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h index b1b530613c342..825d777c078bd 100644 --- a/include/linux/blk-integrity.h +++ b/include/linux/blk-integrity.h @@ -66,19 +66,19 @@ queue_max_integrity_segments(const struct request_queue *q) } /** - * bio_integrity_intervals - Return number of integrity intervals for a bio + * bio_integrity_intervals - Convert sectors to integrity intervals * @bi: blk_integrity profile for device - * @sectors: Size of the bio in 512-byte sectors + * @sectors: Number of 512-byte sectors * * Description: The block layer calculates everything in 512 byte * sectors but integrity metadata is done in terms of the data integrity * interval size of the storage device. Convert the block layer sectors * to the appropriate number of integrity intervals. */ -static inline unsigned int bio_integrity_intervals(struct blk_integrity *bi, - unsigned int sectors) +static inline u64 bio_integrity_intervals(const struct blk_integrity *bi, + u64 sectors) { - return sectors >> (bi->interval_exp - 9); + return sectors >> (bi->interval_exp - SECTOR_SHIFT); } static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi, @@ -153,8 +153,8 @@ queue_max_integrity_segments(const struct request_queue *q) return 0; } -static inline unsigned int bio_integrity_intervals(struct blk_integrity *bi, - unsigned int sectors) +static inline u64 bio_integrity_intervals(const struct blk_integrity *bi, + u64 sectors) { return 0; } From a13e32f24a7226912a0bc5e45931800463d2383c Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Thu, 16 Apr 2026 19:57:30 -0600 Subject: [PATCH 4/6] bio-integrity-fs: use integrity interval instead of sector as seed bip_iter.bi_sector is meant to be in units of integrity intervals rather than 512-byte sectors. bio_integrity_verify() doesn't actually use it currently (it uses the passed in struct bvec_iter's bi_sector instead). But let's set it to the expected value for consistency. Signed-off-by: Caleb Sander Mateos Reviewed-by: Anuj Gupta Reviewed-by: Christoph Hellwig --- block/bio-integrity-fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/bio-integrity-fs.c b/block/bio-integrity-fs.c index 0daa42d9ead77..0ad1c5ab64e9b 100644 --- a/block/bio-integrity-fs.c +++ b/block/bio-integrity-fs.c @@ -67,7 +67,7 @@ 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_sector = bio_integrity_intervals(bi, sector); bip->bip_iter.bi_size = bio_integrity_bytes(bi, size >> SECTOR_SHIFT); return blk_status_to_errno(bio_integrity_verify(bio, &data_iter)); } From 1bee71f75edaccfc692858c09ff9499b2c2cd242 Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Thu, 16 Apr 2026 19:57:31 -0600 Subject: [PATCH 5/6] t10-pi: use bio_integrity_intervals() helper Use bio_integrity_intervals() to convert blk_rq_pos(rq) to integrity intervals to reduce code duplication. Signed-off-by: Caleb Sander Mateos Reviewed-by: Anuj Gupta Reviewed-by: Christoph Hellwig --- block/t10-pi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/t10-pi.c b/block/t10-pi.c index e58d5eb6cefb8..787950dec50a8 100644 --- a/block/t10-pi.c +++ b/block/t10-pi.c @@ -543,7 +543,7 @@ static void blk_integrity_remap(struct request *rq, unsigned int nr_bytes, bool prep) { struct blk_integrity *bi = &rq->q->limits.integrity; - u64 ref = blk_rq_pos(rq) >> (bi->interval_exp - SECTOR_SHIFT); + u64 ref = bio_integrity_intervals(bi, blk_rq_pos(rq)); unsigned intervals = nr_bytes >> bi->interval_exp; struct bio *bio; From b7ea5f4cba793e75b8ebe8375b5a0856f83f4347 Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Thu, 16 Apr 2026 19:57:32 -0600 Subject: [PATCH 6/6] blk-integrity: avoid sector_t in bip_{get,set}_seed() bip_set_seed() and big_get_seed() take/return a sector_t value that's actually an integrity interval number. This is confusing, so pass struct bio instead to bip_set_seed() and convert the bio's device address to integrity intervals. Open-code the access to bip->bip_iter.bi_sector in the one caller of bip_set_seed() that doesn't use the bio device address for the seed. Open-code bip_get_seed() in its one caller. Add a comment to struct bvec_iter's bi_sector field explaining its alternate use for bip_iter. Suggested-by: Christoph Hellwig Signed-off-by: Caleb Sander Mateos --- block/bio-integrity.c | 5 ++--- block/t10-pi.c | 2 +- drivers/nvme/target/io-cmd-bdev.c | 3 +-- drivers/target/target_core_iblock.c | 3 +-- include/linux/bio-integrity.h | 11 ----------- include/linux/blk-integrity.h | 13 +++++++++++++ include/linux/bvec.h | 1 + 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/block/bio-integrity.c b/block/bio-integrity.c index 3ad6a6799f170..8549d9148b0b0 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -105,9 +105,8 @@ void bio_integrity_setup_default(struct bio *bio) { struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk); struct bio_integrity_payload *bip = bio_integrity(bio); - u64 seed = bio->bi_iter.bi_sector >> (bi->interval_exp - SECTOR_SHIFT); - bip_set_seed(bip, seed); + bip_set_seed(bio); if (bi->csum_type) { bip->bip_flags |= BIP_CHECK_GUARD; @@ -474,7 +473,7 @@ int bio_integrity_map_iter(struct bio *bio, struct uio_meta *meta) ret = bio_integrity_map_user(bio, &it); if (!ret) { bio_uio_meta_to_bip(bio, meta); - bip_set_seed(bio_integrity(bio), meta->seed); + bio_integrity(bio)->bip_iter.bi_sector = meta->seed; iov_iter_advance(&meta->iter, integrity_bytes); meta->seed += bio_integrity_intervals(bi, bio_sectors(bio)); } diff --git a/block/t10-pi.c b/block/t10-pi.c index 787950dec50a8..71367fd082bd4 100644 --- a/block/t10-pi.c +++ b/block/t10-pi.c @@ -512,7 +512,7 @@ static void __blk_reftag_remap(struct bio *bio, struct blk_integrity *bi, { struct bio_integrity_payload *bip = bio_integrity(bio); struct bvec_iter iter = bip->bip_iter; - u64 virt = bip_get_seed(bip); + u64 virt = bip->bip_iter.bi_sector; union pi_tuple *ptuple; union pi_tuple tuple; diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c index f2d9e8901df4e..65fce51b024a9 100644 --- a/drivers/nvme/target/io-cmd-bdev.c +++ b/drivers/nvme/target/io-cmd-bdev.c @@ -220,8 +220,7 @@ static int nvmet_bdev_alloc_bip(struct nvmet_req *req, struct bio *bio, } /* virtual start sector must be in integrity interval units */ - bip_set_seed(bip, bio->bi_iter.bi_sector >> - (bi->interval_exp - SECTOR_SHIFT)); + bip_set_seed(bio); resid = bio_integrity_bytes(bi, bio_sectors(bio)); while (resid > 0 && sg_miter_next(miter)) { diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 1087d1d17c36d..1aeb5be529a88 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -708,8 +708,7 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio, } /* virtual start sector must be in integrity interval units */ - bip_set_seed(bip, bio->bi_iter.bi_sector >> - (bi->interval_exp - SECTOR_SHIFT)); + bip_set_seed(bio); pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_iter.bi_size, (unsigned long long)bip->bip_iter.bi_sector); diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h index af5178434ec61..edcd0855abba8 100644 --- a/include/linux/bio-integrity.h +++ b/include/linux/bio-integrity.h @@ -58,17 +58,6 @@ static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag) return false; } -static inline sector_t bip_get_seed(struct bio_integrity_payload *bip) -{ - return bip->bip_iter.bi_sector; -} - -static inline void bip_set_seed(struct bio_integrity_payload *bip, - sector_t seed) -{ - bip->bip_iter.bi_sector = seed; -} - void bio_integrity_init(struct bio *bio, struct bio_integrity_payload *bip, struct bio_vec *bvecs, unsigned int nr_vecs); struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, gfp_t gfp, diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h index 825d777c078bd..c82b2f6fe194a 100644 --- a/include/linux/blk-integrity.h +++ b/include/linux/blk-integrity.h @@ -87,6 +87,19 @@ static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi, return bio_integrity_intervals(bi, sectors) * bi->metadata_size; } +/** + * bip_set_seed - Set bip reference tag seed from bio device address + * @bio: struct bio whose integrity payload's ref tag seed to initialize + */ +static inline void bip_set_seed(struct bio *bio) +{ + struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk); + struct bio_integrity_payload *bip = bio_integrity(bio); + + bip->bip_iter.bi_sector = + bio_integrity_intervals(bi, bio->bi_iter.bi_sector); +} + static inline bool blk_integrity_rq(const struct request *rq) { return rq->cmd_flags & REQ_INTEGRITY; diff --git a/include/linux/bvec.h b/include/linux/bvec.h index d36dd476feda3..3dc88f5cd3672 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -78,6 +78,7 @@ struct bvec_iter { /* * Current device address in 512 byte sectors. Only updated by the bio * iter wrappers and not the bvec iterator helpers themselves. + * For bip_iter, this is overloaded to represent the integrity interval. */ sector_t bi_sector;