diff options
| author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-12-23 15:31:24 -0500 |
|---|---|---|
| committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-01-18 05:14:22 -0500 |
| commit | ecebbf6ccbca58b4470f092cfb0644df59ea05dd (patch) | |
| tree | 62bf3d2934841d0076315eddf23f17bc0985c0ac | |
| parent | def2b339b422070ecb99298a80e4b15033adc0ce (diff) | |
target/iblock: Add blk_integrity + BIP passthrough support
This patch adds blk_integrity passthrough support for block_device
backends using IBLOCK.
This includes iblock_alloc_bip() + setup of bio_integrity_payload
information that attaches to the leading struct bio once bio_list
is populated during fast-path iblock_execute_rw() I/O dispatch.
It also updates setup in iblock_configure_device() to detect modes
of protection + se dev->dev_attrib.pi_prot_type accordingly, along
with creating required bio_set integrity mempools.
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Sagi Grimberg <sagig@mellanox.com>
Cc: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
| -rw-r--r-- | drivers/target/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/target/target_core_iblock.c | 91 |
2 files changed, 90 insertions, 2 deletions
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig index 50aad2eeed6e..dc2d84ac5a0e 100644 --- a/drivers/target/Kconfig +++ b/drivers/target/Kconfig | |||
| @@ -14,6 +14,7 @@ if TARGET_CORE | |||
| 14 | 14 | ||
| 15 | config TCM_IBLOCK | 15 | config TCM_IBLOCK |
| 16 | tristate "TCM/IBLOCK Subsystem Plugin for Linux/BLOCK" | 16 | tristate "TCM/IBLOCK Subsystem Plugin for Linux/BLOCK" |
| 17 | select BLK_DEV_INTEGRITY | ||
| 17 | help | 18 | help |
| 18 | Say Y here to enable the TCM/IBLOCK subsystem plugin for non-buffered | 19 | Say Y here to enable the TCM/IBLOCK subsystem plugin for non-buffered |
| 19 | access to Linux/Block devices using BIO | 20 | access to Linux/Block devices using BIO |
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 15d9121a517e..293d9b081e8a 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c | |||
| @@ -91,6 +91,7 @@ static int iblock_configure_device(struct se_device *dev) | |||
| 91 | struct iblock_dev *ib_dev = IBLOCK_DEV(dev); | 91 | struct iblock_dev *ib_dev = IBLOCK_DEV(dev); |
| 92 | struct request_queue *q; | 92 | struct request_queue *q; |
| 93 | struct block_device *bd = NULL; | 93 | struct block_device *bd = NULL; |
| 94 | struct blk_integrity *bi; | ||
| 94 | fmode_t mode; | 95 | fmode_t mode; |
| 95 | int ret = -ENOMEM; | 96 | int ret = -ENOMEM; |
| 96 | 97 | ||
| @@ -155,8 +156,40 @@ static int iblock_configure_device(struct se_device *dev) | |||
| 155 | if (blk_queue_nonrot(q)) | 156 | if (blk_queue_nonrot(q)) |
| 156 | dev->dev_attrib.is_nonrot = 1; | 157 | dev->dev_attrib.is_nonrot = 1; |
| 157 | 158 | ||
| 159 | bi = bdev_get_integrity(bd); | ||
| 160 | if (bi) { | ||
| 161 | struct bio_set *bs = ib_dev->ibd_bio_set; | ||
| 162 | |||
| 163 | if (!strcmp(bi->name, "T10-DIF-TYPE3-IP") || | ||
| 164 | !strcmp(bi->name, "T10-DIF-TYPE1-IP")) { | ||
| 165 | pr_err("IBLOCK export of blk_integrity: %s not" | ||
| 166 | " supported\n", bi->name); | ||
| 167 | ret = -ENOSYS; | ||
| 168 | goto out_blkdev_put; | ||
| 169 | } | ||
| 170 | |||
| 171 | if (!strcmp(bi->name, "T10-DIF-TYPE3-CRC")) { | ||
| 172 | dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE3_PROT; | ||
| 173 | } else if (!strcmp(bi->name, "T10-DIF-TYPE1-CRC")) { | ||
| 174 | dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE1_PROT; | ||
| 175 | } | ||
| 176 | |||
| 177 | if (dev->dev_attrib.pi_prot_type) { | ||
| 178 | if (bioset_integrity_create(bs, IBLOCK_BIO_POOL_SIZE) < 0) { | ||
| 179 | pr_err("Unable to allocate bioset for PI\n"); | ||
| 180 | ret = -ENOMEM; | ||
| 181 | goto out_blkdev_put; | ||
| 182 | } | ||
| 183 | pr_debug("IBLOCK setup BIP bs->bio_integrity_pool: %p\n", | ||
| 184 | bs->bio_integrity_pool); | ||
| 185 | } | ||
| 186 | dev->dev_attrib.hw_pi_prot_type = dev->dev_attrib.pi_prot_type; | ||
| 187 | } | ||
| 188 | |||
| 158 | return 0; | 189 | return 0; |
| 159 | 190 | ||
| 191 | out_blkdev_put: | ||
| 192 | blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); | ||
| 160 | out_free_bioset: | 193 | out_free_bioset: |
| 161 | bioset_free(ib_dev->ibd_bio_set); | 194 | bioset_free(ib_dev->ibd_bio_set); |
| 162 | ib_dev->ibd_bio_set = NULL; | 195 | ib_dev->ibd_bio_set = NULL; |
| @@ -170,8 +203,10 @@ static void iblock_free_device(struct se_device *dev) | |||
| 170 | 203 | ||
| 171 | if (ib_dev->ibd_bd != NULL) | 204 | if (ib_dev->ibd_bd != NULL) |
| 172 | blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); | 205 | blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); |
| 173 | if (ib_dev->ibd_bio_set != NULL) | 206 | if (ib_dev->ibd_bio_set != NULL) { |
| 207 | bioset_integrity_free(ib_dev->ibd_bio_set); | ||
| 174 | bioset_free(ib_dev->ibd_bio_set); | 208 | bioset_free(ib_dev->ibd_bio_set); |
| 209 | } | ||
| 175 | kfree(ib_dev); | 210 | kfree(ib_dev); |
| 176 | } | 211 | } |
| 177 | 212 | ||
| @@ -586,13 +621,58 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b) | |||
| 586 | return bl; | 621 | return bl; |
| 587 | } | 622 | } |
| 588 | 623 | ||
| 624 | static int | ||
| 625 | iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio) | ||
| 626 | { | ||
| 627 | struct se_device *dev = cmd->se_dev; | ||
| 628 | struct blk_integrity *bi; | ||
| 629 | struct bio_integrity_payload *bip; | ||
| 630 | struct iblock_dev *ib_dev = IBLOCK_DEV(dev); | ||
| 631 | struct scatterlist *sg; | ||
| 632 | int i, rc; | ||
| 633 | |||
| 634 | bi = bdev_get_integrity(ib_dev->ibd_bd); | ||
| 635 | if (!bi) { | ||
| 636 | pr_err("Unable to locate bio_integrity\n"); | ||
| 637 | return -ENODEV; | ||
| 638 | } | ||
| 639 | |||
| 640 | bip = bio_integrity_alloc(bio, GFP_NOIO, cmd->t_prot_nents); | ||
| 641 | if (!bip) { | ||
| 642 | pr_err("Unable to allocate bio_integrity_payload\n"); | ||
| 643 | return -ENOMEM; | ||
| 644 | } | ||
| 645 | |||
| 646 | bip->bip_size = (cmd->data_length / dev->dev_attrib.block_size) * | ||
| 647 | dev->prot_length; | ||
| 648 | bip->bip_sector = bio->bi_sector; | ||
| 649 | |||
| 650 | pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_size, | ||
| 651 | (unsigned long long)bip->bip_sector); | ||
| 652 | |||
| 653 | for_each_sg(cmd->t_prot_sg, sg, cmd->t_prot_nents, i) { | ||
| 654 | |||
| 655 | rc = bio_integrity_add_page(bio, sg_page(sg), sg->length, | ||
| 656 | sg->offset); | ||
| 657 | if (rc != sg->length) { | ||
| 658 | pr_err("bio_integrity_add_page() failed; %d\n", rc); | ||
| 659 | return -ENOMEM; | ||
| 660 | } | ||
| 661 | |||
| 662 | pr_debug("Added bio integrity page: %p length: %d offset; %d\n", | ||
| 663 | sg_page(sg), sg->length, sg->offset); | ||
| 664 | } | ||
| 665 | |||
| 666 | return 0; | ||
| 667 | } | ||
| 668 | |||
| 589 | static sense_reason_t | 669 | static sense_reason_t |
| 590 | iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | 670 | iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, |
| 591 | enum dma_data_direction data_direction) | 671 | enum dma_data_direction data_direction) |
| 592 | { | 672 | { |
| 593 | struct se_device *dev = cmd->se_dev; | 673 | struct se_device *dev = cmd->se_dev; |
| 594 | struct iblock_req *ibr; | 674 | struct iblock_req *ibr; |
| 595 | struct bio *bio; | 675 | struct bio *bio, *bio_start; |
| 596 | struct bio_list list; | 676 | struct bio_list list; |
| 597 | struct scatterlist *sg; | 677 | struct scatterlist *sg; |
| 598 | u32 sg_num = sgl_nents; | 678 | u32 sg_num = sgl_nents; |
| @@ -655,6 +735,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
| 655 | if (!bio) | 735 | if (!bio) |
| 656 | goto fail_free_ibr; | 736 | goto fail_free_ibr; |
| 657 | 737 | ||
| 738 | bio_start = bio; | ||
| 658 | bio_list_init(&list); | 739 | bio_list_init(&list); |
| 659 | bio_list_add(&list, bio); | 740 | bio_list_add(&list, bio); |
| 660 | 741 | ||
| @@ -688,6 +769,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
| 688 | sg_num--; | 769 | sg_num--; |
| 689 | } | 770 | } |
| 690 | 771 | ||
| 772 | if (cmd->prot_type) { | ||
| 773 | int rc = iblock_alloc_bip(cmd, bio_start); | ||
| 774 | if (rc) | ||
| 775 | goto fail_put_bios; | ||
| 776 | } | ||
| 777 | |||
| 691 | iblock_submit_bios(&list, rw); | 778 | iblock_submit_bios(&list, rw); |
| 692 | iblock_complete_cmd(cmd); | 779 | iblock_complete_cmd(cmd); |
| 693 | return 0; | 780 | return 0; |
