Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

block: centralize PI remapping logic to the block layer

Currently t10_pi_prepare/t10_pi_complete functions are called during the
NVMe and SCSi layers command preparetion/completion, but their actual
place should be the block layer since T10-PI is a general data integrity
feature that is used by block storage protocols. Introduce .prepare_fn
and .complete_fn callbacks within the integrity profile that each type
can implement according to its needs.

Suggested-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Suggested-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Max Gurtovoy <maxg@mellanox.com>

Fixed to not call queue integrity functions if BLK_DEV_INTEGRITY
isn't defined in the config.

Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Max Gurtovoy and committed by
Jens Axboe
54d4e6ab 5eaed68d

+114 -99
+7
block/blk-core.c
··· 34 34 #include <linux/ratelimit.h> 35 35 #include <linux/pm_runtime.h> 36 36 #include <linux/blk-cgroup.h> 37 + #include <linux/t10-pi.h> 37 38 #include <linux/debugfs.h> 38 39 #include <linux/bpf.h> 39 40 #include <linux/psi.h> ··· 1436 1435 1437 1436 if (!req->bio) 1438 1437 return false; 1438 + 1439 + #ifdef CONFIG_BLK_DEV_INTEGRITY 1440 + if (blk_integrity_rq(req) && req_op(req) == REQ_OP_READ && 1441 + error == BLK_STS_OK) 1442 + req->q->integrity.profile->complete_fn(req, nr_bytes); 1443 + #endif 1439 1444 1440 1445 if (unlikely(error && !blk_rq_is_passthrough(req) && 1441 1446 !(req->rq_flags & RQF_QUIET)))
+11
block/blk-integrity.c
··· 368 368 return BLK_STS_OK; 369 369 } 370 370 371 + static void blk_integrity_nop_prepare(struct request *rq) 372 + { 373 + } 374 + 375 + static void blk_integrity_nop_complete(struct request *rq, 376 + unsigned int nr_bytes) 377 + { 378 + } 379 + 371 380 static const struct blk_integrity_profile nop_profile = { 372 381 .name = "nop", 373 382 .generate_fn = blk_integrity_nop_fn, 374 383 .verify_fn = blk_integrity_nop_fn, 384 + .prepare_fn = blk_integrity_nop_prepare, 385 + .complete_fn = blk_integrity_nop_complete, 375 386 }; 376 387 377 388 /**
+6
block/blk-mq.c
··· 30 30 #include <trace/events/block.h> 31 31 32 32 #include <linux/blk-mq.h> 33 + #include <linux/t10-pi.h> 33 34 #include "blk.h" 34 35 #include "blk-mq.h" 35 36 #include "blk-mq-debugfs.h" ··· 701 700 */ 702 701 rq->nr_phys_segments++; 703 702 } 703 + 704 + #ifdef CONFIG_BLK_DEV_INTEGRITY 705 + if (blk_integrity_rq(rq) && req_op(rq) == REQ_OP_WRITE) 706 + q->integrity.profile->prepare_fn(rq); 707 + #endif 704 708 } 705 709 EXPORT_SYMBOL(blk_mq_start_request); 706 710
+76 -68
block/t10-pi.c
··· 120 120 return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE1_PROTECTION); 121 121 } 122 122 123 - static blk_status_t t10_pi_type3_generate_crc(struct blk_integrity_iter *iter) 124 - { 125 - return t10_pi_generate(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION); 126 - } 127 - 128 - static blk_status_t t10_pi_type3_generate_ip(struct blk_integrity_iter *iter) 129 - { 130 - return t10_pi_generate(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION); 131 - } 132 - 133 - static blk_status_t t10_pi_type3_verify_crc(struct blk_integrity_iter *iter) 134 - { 135 - return t10_pi_verify(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION); 136 - } 137 - 138 - static blk_status_t t10_pi_type3_verify_ip(struct blk_integrity_iter *iter) 139 - { 140 - return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION); 141 - } 142 - 143 - const struct blk_integrity_profile t10_pi_type1_crc = { 144 - .name = "T10-DIF-TYPE1-CRC", 145 - .generate_fn = t10_pi_type1_generate_crc, 146 - .verify_fn = t10_pi_type1_verify_crc, 147 - }; 148 - EXPORT_SYMBOL(t10_pi_type1_crc); 149 - 150 - const struct blk_integrity_profile t10_pi_type1_ip = { 151 - .name = "T10-DIF-TYPE1-IP", 152 - .generate_fn = t10_pi_type1_generate_ip, 153 - .verify_fn = t10_pi_type1_verify_ip, 154 - }; 155 - EXPORT_SYMBOL(t10_pi_type1_ip); 156 - 157 - const struct blk_integrity_profile t10_pi_type3_crc = { 158 - .name = "T10-DIF-TYPE3-CRC", 159 - .generate_fn = t10_pi_type3_generate_crc, 160 - .verify_fn = t10_pi_type3_verify_crc, 161 - }; 162 - EXPORT_SYMBOL(t10_pi_type3_crc); 163 - 164 - const struct blk_integrity_profile t10_pi_type3_ip = { 165 - .name = "T10-DIF-TYPE3-IP", 166 - .generate_fn = t10_pi_type3_generate_ip, 167 - .verify_fn = t10_pi_type3_verify_ip, 168 - }; 169 - EXPORT_SYMBOL(t10_pi_type3_ip); 170 - 171 123 /** 172 - * t10_pi_prepare - prepare PI prior submitting request to device 124 + * t10_pi_type1_prepare - prepare PI prior submitting request to device 173 125 * @rq: request with PI that should be prepared 174 - * @protection_type: PI type (Type 1/Type 2/Type 3) 175 126 * 176 127 * For Type 1/Type 2, the virtual start sector is the one that was 177 128 * originally submitted by the block layer for the ref_tag usage. Due to 178 129 * partitioning, MD/DM cloning, etc. the actual physical start sector is 179 130 * likely to be different. Remap protection information to match the 180 131 * physical LBA. 181 - * 182 - * Type 3 does not have a reference tag so no remapping is required. 183 132 */ 184 - void t10_pi_prepare(struct request *rq, u8 protection_type) 133 + static void t10_pi_type1_prepare(struct request *rq) 185 134 { 186 135 const int tuple_sz = rq->q->integrity.tuple_size; 187 136 u32 ref_tag = t10_pi_ref_tag(rq); 188 137 struct bio *bio; 189 - 190 - if (protection_type == T10_PI_TYPE3_PROTECTION) 191 - return; 192 138 193 139 __rq_for_each_bio(bio, rq) { 194 140 struct bio_integrity_payload *bip = bio_integrity(bio); ··· 168 222 bip->bip_flags |= BIP_MAPPED_INTEGRITY; 169 223 } 170 224 } 171 - EXPORT_SYMBOL(t10_pi_prepare); 172 225 173 226 /** 174 - * t10_pi_complete - prepare PI prior returning request to the block layer 227 + * t10_pi_type1_complete - prepare PI prior returning request to the blk layer 175 228 * @rq: request with PI that should be prepared 176 - * @protection_type: PI type (Type 1/Type 2/Type 3) 177 - * @intervals: total elements to prepare 229 + * @nr_bytes: total bytes to prepare 178 230 * 179 231 * For Type 1/Type 2, the virtual start sector is the one that was 180 232 * originally submitted by the block layer for the ref_tag usage. Due to ··· 180 236 * likely to be different. Since the physical start sector was submitted 181 237 * to the device, we should remap it back to virtual values expected by the 182 238 * block layer. 183 - * 184 - * Type 3 does not have a reference tag so no remapping is required. 185 239 */ 186 - void t10_pi_complete(struct request *rq, u8 protection_type, 187 - unsigned int intervals) 240 + static void t10_pi_type1_complete(struct request *rq, unsigned int nr_bytes) 188 241 { 242 + unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp; 189 243 const int tuple_sz = rq->q->integrity.tuple_size; 190 244 u32 ref_tag = t10_pi_ref_tag(rq); 191 245 struct bio *bio; 192 - 193 - if (protection_type == T10_PI_TYPE3_PROTECTION) 194 - return; 195 246 196 247 __rq_for_each_bio(bio, rq) { 197 248 struct bio_integrity_payload *bip = bio_integrity(bio); ··· 215 276 } 216 277 } 217 278 } 218 - EXPORT_SYMBOL(t10_pi_complete); 279 + 280 + static blk_status_t t10_pi_type3_generate_crc(struct blk_integrity_iter *iter) 281 + { 282 + return t10_pi_generate(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION); 283 + } 284 + 285 + static blk_status_t t10_pi_type3_generate_ip(struct blk_integrity_iter *iter) 286 + { 287 + return t10_pi_generate(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION); 288 + } 289 + 290 + static blk_status_t t10_pi_type3_verify_crc(struct blk_integrity_iter *iter) 291 + { 292 + return t10_pi_verify(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION); 293 + } 294 + 295 + static blk_status_t t10_pi_type3_verify_ip(struct blk_integrity_iter *iter) 296 + { 297 + return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION); 298 + } 299 + 300 + /** 301 + * Type 3 does not have a reference tag so no remapping is required. 302 + */ 303 + static void t10_pi_type3_prepare(struct request *rq) 304 + { 305 + } 306 + 307 + /** 308 + * Type 3 does not have a reference tag so no remapping is required. 309 + */ 310 + static void t10_pi_type3_complete(struct request *rq, unsigned int nr_bytes) 311 + { 312 + } 313 + 314 + const struct blk_integrity_profile t10_pi_type1_crc = { 315 + .name = "T10-DIF-TYPE1-CRC", 316 + .generate_fn = t10_pi_type1_generate_crc, 317 + .verify_fn = t10_pi_type1_verify_crc, 318 + .prepare_fn = t10_pi_type1_prepare, 319 + .complete_fn = t10_pi_type1_complete, 320 + }; 321 + EXPORT_SYMBOL(t10_pi_type1_crc); 322 + 323 + const struct blk_integrity_profile t10_pi_type1_ip = { 324 + .name = "T10-DIF-TYPE1-IP", 325 + .generate_fn = t10_pi_type1_generate_ip, 326 + .verify_fn = t10_pi_type1_verify_ip, 327 + .prepare_fn = t10_pi_type1_prepare, 328 + .complete_fn = t10_pi_type1_complete, 329 + }; 330 + EXPORT_SYMBOL(t10_pi_type1_ip); 331 + 332 + const struct blk_integrity_profile t10_pi_type3_crc = { 333 + .name = "T10-DIF-TYPE3-CRC", 334 + .generate_fn = t10_pi_type3_generate_crc, 335 + .verify_fn = t10_pi_type3_verify_crc, 336 + .prepare_fn = t10_pi_type3_prepare, 337 + .complete_fn = t10_pi_type3_complete, 338 + }; 339 + EXPORT_SYMBOL(t10_pi_type3_crc); 340 + 341 + const struct blk_integrity_profile t10_pi_type3_ip = { 342 + .name = "T10-DIF-TYPE3-IP", 343 + .generate_fn = t10_pi_type3_generate_ip, 344 + .verify_fn = t10_pi_type3_verify_ip, 345 + .prepare_fn = t10_pi_type3_prepare, 346 + .complete_fn = t10_pi_type3_complete, 347 + }; 348 + EXPORT_SYMBOL(t10_pi_type3_ip);
+10
drivers/md/dm-integrity.c
··· 345 345 #define DEBUG_bytes(bytes, len, msg, ...) do { } while (0) 346 346 #endif 347 347 348 + static void dm_integrity_prepare(struct request *rq) 349 + { 350 + } 351 + 352 + static void dm_integrity_complete(struct request *rq, unsigned int nr_bytes) 353 + { 354 + } 355 + 348 356 /* 349 357 * DM Integrity profile, protection is performed layer above (dm-crypt) 350 358 */ ··· 360 352 .name = "DM-DIF-EXT-TAG", 361 353 .generate_fn = NULL, 362 354 .verify_fn = NULL, 355 + .prepare_fn = dm_integrity_prepare, 356 + .complete_fn = dm_integrity_complete, 363 357 }; 364 358 365 359 static void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map);
-9
drivers/nvme/host/core.c
··· 666 666 if (WARN_ON_ONCE(!nvme_ns_has_pi(ns))) 667 667 return BLK_STS_NOTSUPP; 668 668 control |= NVME_RW_PRINFO_PRACT; 669 - } else if (req_op(req) == REQ_OP_WRITE) { 670 - t10_pi_prepare(req, ns->pi_type); 671 669 } 672 670 673 671 switch (ns->pi_type) { ··· 688 690 689 691 void nvme_cleanup_cmd(struct request *req) 690 692 { 691 - if (blk_integrity_rq(req) && req_op(req) == REQ_OP_READ && 692 - nvme_req(req)->status == 0) { 693 - struct nvme_ns *ns = req->rq_disk->private_data; 694 - 695 - t10_pi_complete(req, ns->pi_type, 696 - blk_rq_bytes(req) >> ns->lba_shift); 697 - } 698 693 if (req->rq_flags & RQF_SPECIAL_PAYLOAD) { 699 694 struct nvme_ns *ns = req->rq_disk->private_data; 700 695 struct page *page = req->special_vec.bv_page;
-8
drivers/scsi/sd.c
··· 1211 1211 dix = scsi_prot_sg_count(cmd); 1212 1212 dif = scsi_host_dif_capable(cmd->device->host, sdkp->protection_type); 1213 1213 1214 - if (write && dix) 1215 - t10_pi_prepare(cmd->request, sdkp->protection_type); 1216 - 1217 1214 if (dif || dix) 1218 1215 protect = sd_setup_protect_cmnd(cmd, dix, dif); 1219 1216 else ··· 2050 2053 SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt, 2051 2054 "sd_done: completed %d of %d bytes\n", 2052 2055 good_bytes, scsi_bufflen(SCpnt))); 2053 - 2054 - if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt) && 2055 - good_bytes) 2056 - t10_pi_complete(SCpnt->request, sdkp->protection_type, 2057 - good_bytes / scsi_prot_interval(SCpnt)); 2058 2056 2059 2057 return good_bytes; 2060 2058 }
+4
include/linux/blkdev.h
··· 1522 1522 }; 1523 1523 1524 1524 typedef blk_status_t (integrity_processing_fn) (struct blk_integrity_iter *); 1525 + typedef void (integrity_prepare_fn) (struct request *); 1526 + typedef void (integrity_complete_fn) (struct request *, unsigned int); 1525 1527 1526 1528 struct blk_integrity_profile { 1527 1529 integrity_processing_fn *generate_fn; 1528 1530 integrity_processing_fn *verify_fn; 1531 + integrity_prepare_fn *prepare_fn; 1532 + integrity_complete_fn *complete_fn; 1529 1533 const char *name; 1530 1534 }; 1531 1535
-14
include/linux/t10-pi.h
··· 53 53 extern const struct blk_integrity_profile t10_pi_type3_crc; 54 54 extern const struct blk_integrity_profile t10_pi_type3_ip; 55 55 56 - #ifdef CONFIG_BLK_DEV_INTEGRITY 57 - extern void t10_pi_prepare(struct request *rq, u8 protection_type); 58 - extern void t10_pi_complete(struct request *rq, u8 protection_type, 59 - unsigned int intervals); 60 - #else 61 - static inline void t10_pi_complete(struct request *rq, u8 protection_type, 62 - unsigned int intervals) 63 - { 64 - } 65 - static inline void t10_pi_prepare(struct request *rq, u8 protection_type) 66 - { 67 - } 68 - #endif 69 - 70 56 #endif