[RFC 1/3] block: add integrity offload
Kanchan Joshi
joshi.k at samsung.com
Wed Jan 29 06:02:05 PST 2025
Add a 'offload_type' that is populated by the integrity providers
(e.g., drivers) based on the underlying capability/configuration.
- BLK_INTEGRITY_OFFLOAD_NONE: indicates offload capability is absent.
- BLK_INTEGRITY_OFFLOAD_NO_BUF: offload for which integrity buffer is
not needed.
- BLK_INTEGRITY_OFFLOAD_BUF: offload for which integrity buffer is
needed.
Make block layer skip certain processing (checksum generate/verify,
reftag remapping) that is not compatible with the offload.
Users (e.g., filesystems) can send the flag REQ_INTEGRITY_OFFLOAD to
ask for the offload.
Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
Co-developed-by: Anuj Gupta <anuj20.g at samsung.com>
Signed-off-by: Anuj Gupta <anuj20.g at samsung.com>
---
block/bio-integrity.c | 42 ++++++++++++++++++++++++++++++++++++++-
block/t10-pi.c | 7 +++++++
include/linux/blk_types.h | 3 +++
include/linux/blkdev.h | 7 +++++++
4 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index 5d81ad9a3d20..05872b5ad9aa 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -413,6 +413,41 @@ int bio_integrity_map_iter(struct bio *bio, struct uio_meta *meta)
return ret;
}
+static bool bio_integrity_offload(struct bio *bio)
+{
+ struct bio_integrity_payload *bip;
+ struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
+ unsigned int len;
+ void *buf;
+ gfp_t gfp = GFP_NOIO;
+
+ if (bi->offload_type == BLK_INTEGRITY_OFFLOAD_NO_BUF)
+ return true;
+
+ /* Allocate kernel buffer for protection data */
+ len = bio_integrity_bytes(bi, bio_sectors(bio));
+ buf = kmalloc(len, gfp | __GFP_ZERO);
+ if (unlikely(buf == NULL))
+ goto err_end_io;
+
+ bip = bio_integrity_alloc(bio, gfp, 1);
+ if (IS_ERR(bip)) {
+ kfree(buf);
+ goto err_end_io;
+ }
+
+ bip->bip_flags |= BIP_BLOCK_INTEGRITY;
+ if (bio_integrity_add_page(bio, virt_to_page(buf), len,
+ offset_in_page(buf)) < len)
+ goto err_end_io;
+
+ return true;
+
+err_end_io:
+ bio->bi_status = BLK_STS_RESOURCE;
+ bio_endio(bio);
+ return false;
+}
/**
* bio_integrity_prep - Prepare bio for integrity I/O
* @bio: bio to prepare
@@ -443,6 +478,10 @@ bool bio_integrity_prep(struct bio *bio)
if (bio_integrity(bio))
return true;
+ if (bio->bi_opf & REQ_INTEGRITY_OFFLOAD &&
+ bi->offload_type != BLK_INTEGRITY_OFFLOAD_NONE)
+ return bio_integrity_offload(bio);
+
switch (bio_op(bio)) {
case REQ_OP_READ:
if (bi->flags & BLK_INTEGRITY_NOVERIFY)
@@ -522,7 +561,8 @@ static void bio_integrity_verify_fn(struct work_struct *work)
container_of(work, struct bio_integrity_payload, bip_work);
struct bio *bio = bip->bip_bio;
- blk_integrity_verify(bio);
+ if (!(bio->bi_opf & REQ_INTEGRITY_OFFLOAD))
+ blk_integrity_verify(bio);
kfree(bvec_virt(bip->bip_vec));
bio_integrity_free(bio);
diff --git a/block/t10-pi.c b/block/t10-pi.c
index 2d05421f0fa5..9eca1ad5d5e6 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -452,6 +452,9 @@ void blk_integrity_prepare(struct request *rq)
if (!(bi->flags & BLK_INTEGRITY_REF_TAG))
return;
+ if ((rq->cmd_flags & REQ_INTEGRITY_OFFLOAD) &&
+ (bi->offload_type != BLK_INTEGRITY_OFFLOAD_NONE))
+ return;
if (bi->csum_type == BLK_INTEGRITY_CSUM_CRC64)
ext_pi_type1_prepare(rq);
@@ -466,6 +469,10 @@ void blk_integrity_complete(struct request *rq, unsigned int nr_bytes)
if (!(bi->flags & BLK_INTEGRITY_REF_TAG))
return;
+ if ((rq->cmd_flags & REQ_INTEGRITY_OFFLOAD) &&
+ (bi->offload_type != BLK_INTEGRITY_OFFLOAD_NONE))
+ return;
+
if (bi->csum_type == BLK_INTEGRITY_CSUM_CRC64)
ext_pi_type1_complete(rq, nr_bytes);
else
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index dce7615c35e7..65615dbc3e2d 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -378,6 +378,7 @@ enum req_flag_bits {
__REQ_DRV, /* for driver use */
__REQ_FS_PRIVATE, /* for file system (submitter) use */
__REQ_ATOMIC, /* for atomic write operations */
+ __REQ_INTEGRITY_OFFLOAD,/* I/O that wants HW integrity offload */
/*
* Command specific flags, keep last:
*/
@@ -399,6 +400,8 @@ enum req_flag_bits {
#define REQ_NOMERGE (__force blk_opf_t)(1ULL << __REQ_NOMERGE)
#define REQ_IDLE (__force blk_opf_t)(1ULL << __REQ_IDLE)
#define REQ_INTEGRITY (__force blk_opf_t)(1ULL << __REQ_INTEGRITY)
+#define REQ_INTEGRITY_OFFLOAD \
+ (__force blk_opf_t)(1ULL << __REQ_INTEGRITY_OFFLOAD)
#define REQ_FUA (__force blk_opf_t)(1ULL << __REQ_FUA)
#define REQ_PREFLUSH (__force blk_opf_t)(1ULL << __REQ_PREFLUSH)
#define REQ_RAHEAD (__force blk_opf_t)(1ULL << __REQ_RAHEAD)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 7ac153e4423a..ef061eb4cb73 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -113,6 +113,12 @@ enum blk_integrity_checksum {
BLK_INTEGRITY_CSUM_CRC64 = 3,
} __packed ;
+enum blk_integrity_offload {
+ BLK_INTEGRITY_OFFLOAD_NONE = 0,
+ BLK_INTEGRITY_OFFLOAD_NO_BUF = 1,
+ BLK_INTEGRITY_OFFLOAD_BUF = 2,
+} __packed;
+
struct blk_integrity {
unsigned char flags;
enum blk_integrity_checksum csum_type;
@@ -120,6 +126,7 @@ struct blk_integrity {
unsigned char pi_offset;
unsigned char interval_exp;
unsigned char tag_size;
+ unsigned char offload_type;
};
typedef unsigned int __bitwise blk_mode_t;
--
2.25.1
More information about the Linux-nvme
mailing list