@@ -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);
@@ -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
@@ -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)
@@ -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;