* [PATCH v4 1/5] block: use integrity interval instead of sector as seed
2026-06-27 5:42 [PATCH v4 0/5] block: use integrity interval instead of sector as seed Caleb Sander Mateos
@ 2026-06-27 5:42 ` Caleb Sander Mateos
2026-06-27 5:42 ` [PATCH v4 2/5] blk-integrity: take u64 in bio_integrity_intervals() Caleb Sander Mateos
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos
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. However, Type 1 and Type 2
ref tags are actually the least significant bits of the integrity
interval number. On devices with integrity interval size > 512 bytes,
the ref tag seed thus isn't the correct initial ref tag. The ref tag
seed is correctly incremented/decremented in units of integrity
intervals in bio_integrity_map_iter(), bio_integrity_advance(), and
blk_integrity_interval().
For REQ_OP_{WRITE,READ}, blk_integrity_{prepare,complete}() covers up
this ref tag seed discrepancy by adding/subtracting the difference
between the initial integrity interval and ref tag values to/from each
ref tag in the protection information. However, REQ_OP_ZONE_APPEND can
also carry PI but doesn't go through blk_integrity_prepare() because the
final data location on the zoned block device isn't known until the
operation completes. As a result, the REQ_OP_ZONE_APPEND PI ref tags
start from the ref tag seed, which isn't in integrity interval units.
Subsequent reads of the appended blocks will fail to remap the ref tags
from the expected integrity interval numbers to sector numbers.
Additionally, NVMe and many SCSI transports support offloading ref tag
remapping to the device by specifying the expected initial ref tag in
the command. The kernel doesn't currently take advantage of this, always
remapping ref tags in software for reads and writes and setting the
expected initial ref tag to the integrity interval. Setting the ref tag
seed in units of integrity intervals would be a prerequisite to allowing
the kernel to skip the software remapping and pass the ref tag seed as
the expected initial ref tag in the command.
So compute the ref tag seed in units of integrity intervals instead of
sectors to avoid relying on ref tag remapping for the conversion.
Fixes: 0512a75b98f8 ("block: Introduce REQ_OP_ZONE_APPEND")
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
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 b23e2434d80c..d20f9002c7c9 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -102,12 +102,13 @@ void bio_integrity_free_buf(struct bio_integrity_payload *bip)
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;
if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
bip->bip_flags |= BIP_IP_CHECKSUM;
diff --git a/block/t10-pi.c b/block/t10-pi.c
index a19b4e102a83..e58d5eb6cefb 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -308,18 +308,19 @@ static blk_status_t blk_integrity_iterate(struct bio *bio,
struct bvec_iter *data_iter,
bool verify)
{
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,
.bi = bi,
.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;
while (iter.data_iter.bi_size && ret == BLK_STS_OK) {
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v4 2/5] blk-integrity: take u64 in bio_integrity_intervals()
2026-06-27 5:42 [PATCH v4 0/5] block: use integrity interval instead of sector as seed Caleb Sander Mateos
2026-06-27 5:42 ` [PATCH v4 1/5] " Caleb Sander Mateos
@ 2026-06-27 5:42 ` Caleb Sander Mateos
2026-06-27 5:42 ` [PATCH v4 3/5] bio-integrity-fs: use integrity interval instead of sector as seed Caleb Sander Mateos
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos
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 <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
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 b1b530613c34..825d777c078b 100644
--- a/include/linux/blk-integrity.h
+++ b/include/linux/blk-integrity.h
@@ -64,23 +64,23 @@ queue_max_integrity_segments(const struct request_queue *q)
{
return q->limits.max_integrity_segments;
}
/**
- * 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,
unsigned int sectors)
{
@@ -151,12 +151,12 @@ static inline unsigned short
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;
}
static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v4 3/5] bio-integrity-fs: use integrity interval instead of sector as seed
2026-06-27 5:42 [PATCH v4 0/5] block: use integrity interval instead of sector as seed Caleb Sander Mateos
2026-06-27 5:42 ` [PATCH v4 1/5] " Caleb Sander Mateos
2026-06-27 5:42 ` [PATCH v4 2/5] blk-integrity: take u64 in bio_integrity_intervals() Caleb Sander Mateos
@ 2026-06-27 5:42 ` Caleb Sander Mateos
2026-06-27 5:42 ` [PATCH v4 4/5] t10-pi: use bio_integrity_intervals() helper Caleb Sander Mateos
2026-06-27 5:42 ` [PATCH v4 5/5] blk-integrity: avoid sector_t in bip_{get,set}_seed() Caleb Sander Mateos
4 siblings, 0 replies; 6+ messages in thread
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos
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 <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
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 9c5fe5fa8f0d..770eacb2220f 100644
--- a/block/bio-integrity-fs.c
+++ b/block/bio-integrity-fs.c
@@ -65,11 +65,11 @@ int fs_bio_integrity_verify(struct bio *bio, sector_t sector, unsigned int size)
*
* This is for use in the submitter after the driver is done with the
* 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));
}
static int __init fs_bio_integrity_init(void)
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v4 4/5] t10-pi: use bio_integrity_intervals() helper
2026-06-27 5:42 [PATCH v4 0/5] block: use integrity interval instead of sector as seed Caleb Sander Mateos
` (2 preceding siblings ...)
2026-06-27 5:42 ` [PATCH v4 3/5] bio-integrity-fs: use integrity interval instead of sector as seed Caleb Sander Mateos
@ 2026-06-27 5:42 ` Caleb Sander Mateos
2026-06-27 5:42 ` [PATCH v4 5/5] blk-integrity: avoid sector_t in bip_{get,set}_seed() Caleb Sander Mateos
4 siblings, 0 replies; 6+ messages in thread
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos
Use bio_integrity_intervals() to convert blk_rq_pos(rq) to integrity
intervals to reduce code duplication.
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
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 e58d5eb6cefb..787950dec50a 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -541,11 +541,11 @@ static void __blk_reftag_remap(struct bio *bio, struct blk_integrity *bi,
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;
if (!(bi->flags & BLK_INTEGRITY_REF_TAG))
return;
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v4 5/5] blk-integrity: avoid sector_t in bip_{get,set}_seed()
2026-06-27 5:42 [PATCH v4 0/5] block: use integrity interval instead of sector as seed Caleb Sander Mateos
` (3 preceding siblings ...)
2026-06-27 5:42 ` [PATCH v4 4/5] t10-pi: use bio_integrity_intervals() helper Caleb Sander Mateos
@ 2026-06-27 5:42 ` Caleb Sander Mateos
4 siblings, 0 replies; 6+ messages in thread
From: Caleb Sander Mateos @ 2026-06-27 5:42 UTC (permalink / raw)
To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Martin K. Petersen
Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
linux-kernel, Caleb Sander Mateos, Christoph Hellwig
bip_set_seed() and bip_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 <hch@infradead.org>
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
---
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 d20f9002c7c9..7e5fb9b44848 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -102,13 +102,12 @@ void bio_integrity_free_buf(struct bio_integrity_payload *bip)
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;
if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
bip->bip_flags |= BIP_IP_CHECKSUM;
@@ -488,11 +487,11 @@ int bio_integrity_map_iter(struct bio *bio, struct uio_meta *meta)
it.count = integrity_bytes;
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));
}
return ret;
}
diff --git a/block/t10-pi.c b/block/t10-pi.c
index 787950dec50a..71367fd082bd 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -510,11 +510,11 @@ static void blk_reftag_remap_prepare(struct blk_integrity *bi,
static void __blk_reftag_remap(struct bio *bio, struct blk_integrity *bi,
unsigned *intervals, u64 *ref, bool prep)
{
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;
if (prep && bip->bip_flags & BIP_MAPPED_INTEGRITY) {
*ref += bio->bi_iter.bi_size >> bi->interval_exp;
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index f2d9e8901df4..65fce51b024a 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -218,12 +218,11 @@ static int nvmet_bdev_alloc_bip(struct nvmet_req *req, struct bio *bio,
pr_err("Unable to allocate bio_integrity_payload\n");
return PTR_ERR(bip);
}
/* 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)) {
len = min_t(size_t, miter->length, resid);
rc = bio_integrity_add_page(bio, miter->page, len,
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 1087d1d17c36..1aeb5be529a8 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -706,12 +706,11 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio,
pr_err("Unable to allocate bio_integrity_payload\n");
return PTR_ERR(bip);
}
/* 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);
resid = bio_integrity_bytes(bi, bio_sectors(bio));
diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h
index c3dda32fd803..992cb1622c2c 100644
--- a/include/linux/bio-integrity.h
+++ b/include/linux/bio-integrity.h
@@ -56,21 +56,10 @@ static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag)
return bip->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,
unsigned int nr);
int bio_integrity_add_page(struct bio *bio, struct page *page, unsigned int len,
diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h
index 825d777c078b..c82b2f6fe194 100644
--- a/include/linux/blk-integrity.h
+++ b/include/linux/blk-integrity.h
@@ -85,10 +85,23 @@ static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
unsigned int sectors)
{
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 92837e2743f1..22bded380bbf 100644
--- a/include/linux/bvec.h
+++ b/include/linux/bvec.h
@@ -91,10 +91,11 @@ static inline struct folio *bvec_folio(const struct bio_vec *bv)
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;
/*
* Remaining size in bytes.
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread