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@xxxxxxxxxxx> Co-developed-by: Anuj Gupta <anuj20.g@xxxxxxxxxxx> Signed-off-by: Anuj Gupta <anuj20.g@xxxxxxxxxxx> --- 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