From: Christoph Hellwig Date: Sun, 6 Jun 2021 08:07:33 +0000 (+0200) Subject: block: split blk_integrity_register X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=6d4af7273f98c582af7e2f007a543b61821f0c0a;p=users%2Fhch%2Fblock.git block: split blk_integrity_register Replace blk_integrity_register with more targeted interfaces: - t10_pi_register registers support for T10 protection information, and just need the PI type and a flags argument - blk_nointegrity_register registers support for non-integrity metadata - blk_set_integrity_interval allows to set the ingegrity interval in combination with either of the above - blk_integrity_copy copies over integrity/metadata information from one gendisk to another, and can be used by stacking drivers Signed-off-by: Christoph Hellwig --- diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 5612a6dbc8de..607600299334 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -16,6 +16,12 @@ #include "blk.h" +const char *blk_integrity_type_str(struct blk_integrity *bi) +{ + return bi->profile->name; +} +EXPORT_SYMBOL_GPL(blk_integrity_type_str); + /** * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements * @q: request queue @@ -383,44 +389,30 @@ static const struct blk_integrity_profile nop_profile = { }; /** - * blk_integrity_register - Register a gendisk as being integrity-capable + * blk_nointegrity_register - Register a gendisk as having non-itegrity metadata * @disk: struct gendisk pointer to make integrity-aware - * @template: block integrity profile to register - * - * Description: When a device needs to advertise itself as being able to - * send/receive integrity metadata it must use this function to register - * the capability with the block layer. The template is a blk_integrity - * struct with values appropriate for the underlying hardware. See - * Documentation/block/data-integrity.rst. + * @meta_size: size of the metadata */ -void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template) +void blk_nointegrity_register(struct gendisk *disk, unsigned char meta_size) { struct blk_integrity *bi = &disk->queue->integrity; - bi->flags = template->flags; - if (bi->profile->verify_fn) - bi->flags |= BLK_INTEGRITY_VERIFY; - if (bi->profile->generate_fn) - bi->flags |= BLK_INTEGRITY_GENERATE; - bi->interval_exp = template->interval_exp ? : - ilog2(queue_logical_block_size(disk->queue)); - bi->profile = template->profile ? template->profile : &nop_profile; - bi->tuple_size = template->tuple_size; - bi->tag_size = template->tag_size; - - if (!bi->profile->verify_fn && !bi->profile->generate_fn) - return; - - blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, disk->queue); + bi->flags = 0; + bi->profile = &nop_profile; + bi->tuple_size = meta_size; + bi->tag_size = meta_size; + bi->interval_exp = ilog2(queue_logical_block_size(disk->queue)); +} +EXPORT_SYMBOL(blk_nointegrity_register); -#ifdef CONFIG_BLK_INLINE_ENCRYPTION - if (disk->queue->ksm) { - pr_warn("blk-integrity: Integrity and hardware inline encryption are not supported together. Disabling hardware inline encryption.\n"); - blk_ksm_unregister(disk->queue); - } -#endif +void blk_integrity_copy(struct gendisk *to, struct gendisk *from) +{ + to->queue->integrity = from->queue->integrity; + if (to->queue->integrity.flags & + (BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE)) + blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, to->queue); } -EXPORT_SYMBOL(blk_integrity_register); +EXPORT_SYMBOL(blk_integrity_copy); /** * blk_integrity_unregister - Unregister block integrity profile diff --git a/block/t10-pi.c b/block/t10-pi.c index 00c203b2a921..8c31bc859f24 100644 --- a/block/t10-pi.c +++ b/block/t10-pi.c @@ -251,14 +251,13 @@ const struct blk_integrity_profile t10_pi_type1_crc = { }; EXPORT_SYMBOL(t10_pi_type1_crc); -const struct blk_integrity_profile t10_pi_type1_ip = { +static const struct blk_integrity_profile t10_pi_type1_ip = { .name = "T10-DIF-TYPE1-IP", .generate_fn = t10_pi_type1_generate_ip, .verify_fn = t10_pi_type1_verify_ip, .prepare_fn = t10_pi_type1_prepare, .complete_fn = t10_pi_type1_complete, }; -EXPORT_SYMBOL(t10_pi_type1_ip); const struct blk_integrity_profile t10_pi_type3_crc = { .name = "T10-DIF-TYPE3-CRC", @@ -269,13 +268,68 @@ const struct blk_integrity_profile t10_pi_type3_crc = { }; EXPORT_SYMBOL(t10_pi_type3_crc); -const struct blk_integrity_profile t10_pi_type3_ip = { +static const struct blk_integrity_profile t10_pi_type3_ip = { .name = "T10-DIF-TYPE3-IP", .generate_fn = t10_pi_type3_generate_ip, .verify_fn = t10_pi_type3_verify_ip, .prepare_fn = t10_pi_type3_prepare, .complete_fn = t10_pi_type3_complete, }; -EXPORT_SYMBOL(t10_pi_type3_ip); + +/** + * t10_pi_register - Register a gendisk as being T10-PI capable + * @disk: struct gendisk pointer to make integrity-aware + * @type: Protetion type + * @flags: BLK_INTEGRITY_* flags applicatble to this disk + */ +void t10_pi_register(struct gendisk *disk, enum t10_dif_type type, + unsigned int flags) +{ + struct blk_integrity *bi = &disk->queue->integrity; + + switch (type) { + case T10_PI_TYPE0_PROTECTION: + flags &= ~(BLK_INTEGRITY_DEVICE_CAPABLE | BLK_INTEGRITY_APP_TAG); + break; + case T10_PI_TYPE2_PROTECTION: + case T10_PI_TYPE1_PROTECTION: + if (flags & BLK_INTEGRITY_IP_CHECKSUM) + bi->profile = &t10_pi_type1_ip; + else + bi->profile = &t10_pi_type1_crc; + break; + case T10_PI_TYPE3_PROTECTION: + if (flags & BLK_INTEGRITY_IP_CHECKSUM) + bi->profile = &t10_pi_type3_ip; + else + bi->profile = &t10_pi_type3_crc; + break; + default: + WARN_ON_ONCE(1); + return; + } + + bi->tuple_size = sizeof(struct t10_pi_tuple); + bi->interval_exp = ilog2(queue_logical_block_size(disk->queue)); + bi->flags = flags | BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE; + + if (!(flags & BLK_INTEGRITY_APP_TAG)) + bi->tag_size = 0; + else if (type == T10_PI_TYPE3_PROTECTION) + bi->tag_size = sizeof(u16) + sizeof(u32); + else + bi->tag_size = sizeof(u16); + + blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, disk->queue); + +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + if (disk->queue->ksm) { + pr_warn("blk-integrity: Integrity and hardware inline encryption are not supported together. "); + pr_warn("Disabling hardware inline encryption.\n"); + blk_ksm_unregister(disk->queue); + } +#endif +} +EXPORT_SYMBOL(t10_pi_register); MODULE_LICENSE("GPL"); diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 7f96ac7768c7..34e305f02f9c 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -3464,14 +3464,10 @@ try_smaller_buffer: static void dm_integrity_set(struct dm_target *ti, struct dm_integrity_c *ic) { struct gendisk *disk = dm_disk(dm_table_get_md(ti->table)); - struct blk_integrity bi; - memset(&bi, 0, sizeof(bi)); - bi.tuple_size = ic->tag_size; - bi.tag_size = bi.tuple_size; - bi.interval_exp = ic->sb->log2_sectors_per_block + SECTOR_SHIFT; - - blk_integrity_register(disk, &bi); + blk_nointegrity_register(disk, ic->tag_size); + blk_set_integrity_interval(disk, + ic->sb->log2_sectors_per_block + SECTOR_SHIFT); blk_queue_max_integrity_segments(disk->queue, UINT_MAX); } diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index ee47a332b462..f794038e1ad1 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1167,8 +1167,7 @@ static int dm_table_register_integrity(struct dm_table *t) * Register integrity profile during table load; we can do * this because the final profile must match during resume. */ - blk_integrity_register(dm_disk(md), - blk_get_integrity(template_disk)); + blk_integrity_copy(dm_disk(md), template_disk); return 0; } diff --git a/drivers/md/md.c b/drivers/md/md.c index d806be8cc210..d02d51ed670e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2375,8 +2375,7 @@ int md_integrity_register(struct mddev *mddev) * All component devices are integrity capable and have matching * profiles, register the common profile for the md device. */ - blk_integrity_register(mddev->gendisk, - bdev_get_integrity(reference->bdev)); + blk_integrity_copy(mddev->gendisk, reference->bdev->bd_disk); pr_debug("md: data integrity enabled on %s\n", mdname(mddev)); if (bioset_integrity_create(&mddev->bio_set, BIO_POOL_SIZE)) { diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index 7de592d7eff4..a407d82106f9 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c @@ -551,19 +551,10 @@ EXPORT_SYMBOL_GPL(nvdimm_bus_add_badrange); #ifdef CONFIG_BLK_DEV_INTEGRITY int nd_integrity_init(struct gendisk *disk, unsigned long meta_size) { - struct blk_integrity bi; - - if (meta_size == 0) - return 0; - - memset(&bi, 0, sizeof(bi)); - - bi.tuple_size = meta_size; - bi.tag_size = meta_size; - - blk_integrity_register(disk, &bi); - blk_queue_max_integrity_segments(disk->queue, 1); - + if (meta_size) { + blk_nointegrity_register(disk, meta_size); + blk_queue_max_integrity_segments(disk->queue, 1); + } return 0; } EXPORT_SYMBOL(nd_integrity_init); diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 0dae30f5d21d..bd905cd2ac94 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1597,40 +1597,6 @@ int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo) return 0; } -#ifdef CONFIG_BLK_DEV_INTEGRITY -static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type, - u32 max_integrity_segments) -{ - struct blk_integrity integrity; - - memset(&integrity, 0, sizeof(integrity)); - switch (pi_type) { - case NVME_NS_DPS_PI_TYPE3: - integrity.profile = &t10_pi_type3_crc; - integrity.tag_size = sizeof(u16) + sizeof(u32); - integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE; - break; - case NVME_NS_DPS_PI_TYPE1: - case NVME_NS_DPS_PI_TYPE2: - integrity.profile = &t10_pi_type1_crc; - integrity.tag_size = sizeof(u16); - integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE; - break; - default: - integrity.profile = NULL; - break; - } - integrity.tuple_size = ms; - blk_integrity_register(disk, &integrity); - blk_queue_max_integrity_segments(disk->queue, max_integrity_segments); -} -#else -static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type, - u32 max_integrity_segments) -{ -} -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns) { struct nvme_ctrl *ctrl = ns->ctrl; @@ -1821,11 +1787,25 @@ static void nvme_update_disk_info(struct gendisk *disk, */ if (ns->ms) { if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) && - (ns->features & NVME_NS_METADATA_SUPPORTED)) - nvme_init_integrity(disk, ns->ms, ns->pi_type, - ns->ctrl->max_integrity_segments); - else if (!nvme_ns_has_pi(ns)) + (ns->features & NVME_NS_METADATA_SUPPORTED)) { + switch (ns->pi_type) { + case NVME_NS_DPS_PI_TYPE3: + case NVME_NS_DPS_PI_TYPE1: + case NVME_NS_DPS_PI_TYPE2: + t10_pi_register(disk, ns->pi_type, + BLK_INTEGRITY_DEVICE_CAPABLE | + BLK_INTEGRITY_APP_TAG); + break; + default: + blk_nointegrity_register(disk, ns->ms); + break; + } + + blk_queue_max_integrity_segments(disk->queue, + ns->ctrl->max_integrity_segments); + } else if (!nvme_ns_has_pi(ns)) { capacity = 0; + } } set_capacity_and_notify(disk, capacity); diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index bc3882f5cc69..1ac9dd564cc7 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -170,7 +170,6 @@ scsi_mod-$(CONFIG_SCSI_DH) += scsi_dh.o hv_storvsc-y := storvsc_drv.o sd_mod-objs := sd.o -sd_mod-$(CONFIG_BLK_DEV_INTEGRITY) += sd_dif.o sd_mod-$(CONFIG_BLK_DEV_ZONED) += sd_zbc.o sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 289951736933..0bfa08085334 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * sd.c Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale + * Copyright (C) 1992 Drew Eckhardt + * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale + * Copyright (C) 2007, 2008 Oracle Corporation * * Linux scsi disk driver * Initial versions: Drew Eckhardt @@ -3338,6 +3339,31 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) return 0; } +static void sd_dif_config_host(struct scsi_disk *sdkp) +{ + struct scsi_device *sdp = sdkp->device; + unsigned int flags = 0; + + if (scsi_host_dix_capable(sdp->host, sdkp->protection_type)) { + if (scsi_host_dif_capable(sdp->host, sdkp->protection_type)) { + flags |= BLK_INTEGRITY_DEVICE_CAPABLE; + if (sdkp->ATO) + flags |= BLK_INTEGRITY_APP_TAG; + } + } else { + if (!scsi_host_dix_capable(sdp->host, 0)) + return; + } + + if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) + flags |= BLK_INTEGRITY_IP_CHECKSUM; + + t10_pi_register(sdkp->disk, sdkp->protection_type, flags); + + sd_printk(KERN_NOTICE, sdkp, "Enabling DIX %s protection\n", + blk_integrity_type_str(blk_get_integrity(sdkp->disk))); +} + /** * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once @@ -3464,7 +3490,8 @@ static int sd_probe(struct device *dev) sdp->host->hostt->rpm_autosuspend_delay); } device_add_disk(dev, gd, NULL); - if (sdkp->capacity) + + if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) && sdkp->capacity) sd_dif_config_host(sdkp); sd_revalidate_disk(gd); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index b59136c4125b..bc9d8d03e2f2 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -197,18 +197,6 @@ static inline sector_t sectors_to_logical(struct scsi_device *sdev, sector_t sec return sector >> (ilog2(sdev->sector_size) - 9); } -#ifdef CONFIG_BLK_DEV_INTEGRITY - -extern void sd_dif_config_host(struct scsi_disk *); - -#else /* CONFIG_BLK_DEV_INTEGRITY */ - -static inline void sd_dif_config_host(struct scsi_disk *disk) -{ -} - -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - static inline int sd_is_zoned(struct scsi_disk *sdkp) { return sdkp->zoned == 1 || sdkp->device->type == TYPE_ZBC; diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c deleted file mode 100644 index 4cadb26070a8..000000000000 --- a/drivers/scsi/sd_dif.c +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * sd_dif.c - SCSI Data Integrity Field - * - * Copyright (C) 2007, 2008 Oracle Corporation - * Written by: Martin K. Petersen - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sd.h" - -/* - * Configure exchange of protection information between OS and HBA. - */ -void sd_dif_config_host(struct scsi_disk *sdkp) -{ - struct scsi_device *sdp = sdkp->device; - struct gendisk *disk = sdkp->disk; - u8 type = sdkp->protection_type; - struct blk_integrity bi; - int dif, dix; - - dif = scsi_host_dif_capable(sdp->host, type); - dix = scsi_host_dix_capable(sdp->host, type); - - if (!dix && scsi_host_dix_capable(sdp->host, 0)) { - dif = 0; dix = 1; - } - - if (!dix) - return; - - memset(&bi, 0, sizeof(bi)); - - /* Enable DMA of protection information */ - if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { - if (type == T10_PI_TYPE3_PROTECTION) - bi.profile = &t10_pi_type3_ip; - else - bi.profile = &t10_pi_type1_ip; - - bi.flags |= BLK_INTEGRITY_IP_CHECKSUM; - } else - if (type == T10_PI_TYPE3_PROTECTION) - bi.profile = &t10_pi_type3_crc; - else - bi.profile = &t10_pi_type1_crc; - - bi.tuple_size = sizeof(struct t10_pi_tuple); - sd_printk(KERN_NOTICE, sdkp, - "Enabling DIX %s protection\n", bi.profile->name); - - if (dif && type) { - bi.flags |= BLK_INTEGRITY_DEVICE_CAPABLE; - - if (!sdkp->ATO) - goto out; - - if (type == T10_PI_TYPE3_PROTECTION) - bi.tag_size = sizeof(u16) + sizeof(u32); - else - bi.tag_size = sizeof(u16); - - sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n", - bi.tag_size); - } - -out: - blk_integrity_register(disk, &bi); -} - diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 91c40bc75520..24a1a230dfd5 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1652,6 +1652,7 @@ enum blk_integrity_flags { BLK_INTEGRITY_GENERATE = 1 << 1, BLK_INTEGRITY_DEVICE_CAPABLE = 1 << 2, BLK_INTEGRITY_IP_CHECKSUM = 1 << 3, + BLK_INTEGRITY_APP_TAG = 1 << 4, }; #ifdef CONFIG_BLK_DEV_INTEGRITY @@ -1676,7 +1677,8 @@ struct blk_integrity_profile { const char *name; }; -extern void blk_integrity_register(struct gendisk *, struct blk_integrity *); +void blk_integrity_copy(struct gendisk *to, struct gendisk *from); +void blk_nointegrity_register(struct gendisk *disk, unsigned char meta_size); extern void blk_integrity_unregister(struct gendisk *); extern int blk_integrity_compare(struct gendisk *, struct gendisk *); extern int blk_rq_map_integrity_sg(struct request_queue *, struct bio *, @@ -1710,6 +1712,12 @@ static inline bool blk_integrity_rq(struct request *rq) return rq->cmd_flags & REQ_INTEGRITY; } +static inline void blk_set_integrity_interval(struct gendisk *disk, + u8 interval_exp) +{ + disk->queue->integrity.interval_exp = interval_exp; +} + static inline void blk_queue_max_integrity_segments(struct request_queue *q, unsigned int segs) { @@ -1793,13 +1801,20 @@ static inline int blk_integrity_compare(struct gendisk *a, struct gendisk *b) { return 0; } -static inline void blk_integrity_register(struct gendisk *d, - struct blk_integrity *b) +static inline void blk_integrity_copy(struct gendisk *to, struct gendisk *from) +{ +} +static inline void blk_nointegrity_register(struct gendisk *disk, + unsigned char meta_size) { } static inline void blk_integrity_unregister(struct gendisk *d) { } +static inline void blk_set_integrity_interval(struct gendisk *disk, + u8 interval_exp) +{ +} static inline void blk_queue_max_integrity_segments(struct request_queue *q, unsigned int segs) { @@ -1828,6 +1843,8 @@ static inline struct bio_vec *rq_integrity_vec(struct request *rq) #endif /* CONFIG_BLK_DEV_INTEGRITY */ +const char *blk_integrity_type_str(struct blk_integrity *bi); + #ifdef CONFIG_BLK_INLINE_ENCRYPTION bool blk_ksm_register(struct blk_keyslot_manager *ksm, struct request_queue *q); diff --git a/include/linux/t10-pi.h b/include/linux/t10-pi.h index 96305a64a5a7..6758dd7844a7 100644 --- a/include/linux/t10-pi.h +++ b/include/linux/t10-pi.h @@ -48,9 +48,10 @@ static inline u32 t10_pi_ref_tag(struct request *rq) return blk_rq_pos(rq) >> (shift - SECTOR_SHIFT) & 0xffffffff; } +void t10_pi_register(struct gendisk *disk, enum t10_dif_type type, + unsigned int flags); + extern const struct blk_integrity_profile t10_pi_type1_crc; -extern const struct blk_integrity_profile t10_pi_type1_ip; extern const struct blk_integrity_profile t10_pi_type3_crc; -extern const struct blk_integrity_profile t10_pi_type3_ip; #endif