[PATCH v4 1/5] block: use integrity interval instead of sector as seed

Caleb Sander Mateos csander at purestorage.com
Wed Jul 1 12:56:24 PDT 2026


On Fri, Jun 26, 2026 at 10:42 PM Caleb Sander Mateos
<csander at purestorage.com> wrote:
>
> 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.

Martin, are you okay with this updated commit message? Would be nice
to get this fix in so auto-integrity works correctly for zone appends
on 4KB-integrity-interval devices.

Thanks,
Caleb


>
> Fixes: 0512a75b98f8 ("block: Introduce REQ_OP_ZONE_APPEND")
> Signed-off-by: Caleb Sander Mateos <csander at purestorage.com>
> Reviewed-by: Anuj Gupta <anuj20.g at samsung.com>
> Reviewed-by: Christoph Hellwig <hch at 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
>



More information about the Linux-nvme mailing list