Commit 203247c5 authored by Keith Busch's avatar Keith Busch Committed by Jens Axboe
Browse files

blk-integrity: support arbitrary buffer alignment



A bio segment may have partial interval block data with the rest
continuing into the next segments because direct-io data payloads only
need to align in memory to the device's DMA limits.

At the same time, the protection information may also be split in
multiple segments. The most likely way that may happen is if two
requests merge, or if we're directly using the io_uring user metadata.
The generate/verify, however, only ever accessed the first bip_vec.

Further, it may be possible to unalign the protection fields from the
user space buffer, or if there are odd additional opaque bytes in front
or in back of the protection information metadata region.

Change up the iteration to allow spanning multiple segments. This patch
is mostly a re-write of the protection information handling to allow any
arbitrary alignments, so it's probably easier to review the end result
rather than the diff.

Many controllers are not able to handle interval data composed of
multiple segments when PI is used, so this patch introduces a new
integrity limit that a low level driver can set to notify that it is
capable, default to false. The nvme driver is the first one to enable it
in this patch. Everyone else will force DMA alignment to the logical
block size as before to ensure interval data is always aligned within a
single segment.

Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarKeith Busch <kbusch@kernel.org>
Link: https://patch.msgid.link/20260313144701.1221652-2-kbusch@meta.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 3dbaacf6
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -189,11 +189,11 @@ static int blk_validate_integrity_limits(struct queue_limits *lim)
	}

	/*
	 * The PI generation / validation helpers do not expect intervals to
	 * straddle multiple bio_vecs.  Enforce alignment so that those are
	 * Some IO controllers can not handle data intervals straddling
	 * multiple bio_vecs.  For those, enforce alignment so that those are
	 * never generated, and that each buffer is aligned as expected.
	 */
	if (bi->csum_type) {
	if (!(bi->flags & BLK_SPLIT_INTERVAL_CAPABLE) && bi->csum_type) {
		lim->dma_alignment = max(lim->dma_alignment,
					(1U << bi->interval_exp) - 1);
	}
@@ -992,10 +992,14 @@ bool queue_limits_stack_integrity(struct queue_limits *t,
		if ((ti->flags & BLK_INTEGRITY_REF_TAG) !=
		    (bi->flags & BLK_INTEGRITY_REF_TAG))
			goto incompatible;
		if ((ti->flags & BLK_SPLIT_INTERVAL_CAPABLE) &&
		    !(bi->flags & BLK_SPLIT_INTERVAL_CAPABLE))
			ti->flags &= ~BLK_SPLIT_INTERVAL_CAPABLE;
	} else {
		ti->flags = BLK_INTEGRITY_STACKED;
		ti->flags |= (bi->flags & BLK_INTEGRITY_DEVICE_CAPABLE) |
			     (bi->flags & BLK_INTEGRITY_REF_TAG);
			     (bi->flags & BLK_INTEGRITY_REF_TAG) |
			     (bi->flags & BLK_SPLIT_INTERVAL_CAPABLE);
		ti->csum_type = bi->csum_type;
		ti->pi_tuple_size = bi->pi_tuple_size;
		ti->metadata_size = bi->metadata_size;
+455 −361

File changed.

Preview size limit exceeded, changes collapsed.

+1 −0
Original line number Diff line number Diff line
@@ -1875,6 +1875,7 @@ static bool nvme_init_integrity(struct nvme_ns_head *head,
		break;
	}

	bi->flags |= BLK_SPLIT_INTERVAL_CAPABLE;
	bi->metadata_size = head->ms;
	if (bi->csum_type) {
		bi->pi_tuple_size = head->pi_size;
+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ enum blk_integrity_flags {
	BLK_INTEGRITY_DEVICE_CAPABLE	= 1 << 2,
	BLK_INTEGRITY_REF_TAG		= 1 << 3,
	BLK_INTEGRITY_STACKED		= 1 << 4,
	BLK_SPLIT_INTERVAL_CAPABLE	= 1 << 5,
};

const char *blk_integrity_profile_name(struct blk_integrity *bi);