When T10 PI is enabled on a backing device for the iblock backstore, the PI SGL for the entire command is attached to the first bio only. This works fine if the command is covered by a single bio, but results in integrity verification errors for the other bios in a multi-bio command. Split the PI SGL across the bios in the command, so each bip contains the protection information for the data in the bio. In a multi-bio command, store where we left off in the PI SGL so we know where to start with the next bio. Signed-off-by: Greg Edwards <gedwards@xxxxxxx> --- This patch depends on commit 359f642700f2 ("block: move bio_integrity_{intervals,bytes} into blkdev.h") in Jens' block for-next branch. drivers/target/target_core_iblock.c | 60 +++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index ce1321a5cb7b..d3ab83282f61 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -635,7 +635,8 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b) } static int -iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio) +iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio, + struct scatterlist **sgl, unsigned int *skip) { struct se_device *dev = cmd->se_dev; struct blk_integrity *bi; @@ -643,6 +644,7 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio) struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct scatterlist *sg; int i, rc; + unsigned int size, nr_pages, len, off; bi = bdev_get_integrity(ib_dev->ibd_bd); if (!bi) { @@ -650,32 +652,52 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio) return -ENODEV; } - bip = bio_integrity_alloc(bio, GFP_NOIO, cmd->t_prot_nents); + nr_pages = min_t(unsigned int, cmd->t_prot_nents, BIO_MAX_PAGES); + bip = bio_integrity_alloc(bio, GFP_NOIO, nr_pages); if (IS_ERR(bip)) { pr_err("Unable to allocate bio_integrity_payload\n"); return PTR_ERR(bip); } - bip->bip_iter.bi_size = (cmd->data_length / dev->dev_attrib.block_size) * - dev->prot_length; - bip->bip_iter.bi_sector = bio->bi_iter.bi_sector; + bip->bip_iter.bi_size = bio_integrity_bytes(bi, bio_sectors(bio)); + bip_set_seed(bip, bio->bi_iter.bi_sector); pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_iter.bi_size, (unsigned long long)bip->bip_iter.bi_sector); - for_each_sg(cmd->t_prot_sg, sg, cmd->t_prot_nents, i) { + size = bip->bip_iter.bi_size; + for_each_sg(*sgl, sg, nr_pages, i) { - rc = bio_integrity_add_page(bio, sg_page(sg), sg->length, - sg->offset); - if (rc != sg->length) { + len = sg->length - *skip; + off = sg->offset + *skip; + + if (*skip) + *skip = 0; + + if (len > size) { + len = size; + *skip = len; + } + + rc = bio_integrity_add_page(bio, sg_page(sg), len, off); + if (rc != len) { pr_err("bio_integrity_add_page() failed; %d\n", rc); return -ENOMEM; } pr_debug("Added bio integrity page: %p length: %d offset; %d\n", - sg_page(sg), sg->length, sg->offset); + sg_page(sg), len, off); + + size -= len; + if (!size) + break; } + if (*skip == 0) + *sgl = sg_next(sg); + else + *sgl = sg; + return 0; } @@ -686,12 +708,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, struct se_device *dev = cmd->se_dev; sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba); struct iblock_req *ibr; - struct bio *bio, *bio_start; + struct bio *bio; struct bio_list list; - struct scatterlist *sg; + struct scatterlist *sg, *sg_prot = cmd->t_prot_sg; u32 sg_num = sgl_nents; - unsigned bio_cnt; - int i, op, op_flags = 0; + unsigned int bio_cnt, skip = 0; + int i, rc, op, op_flags = 0; if (data_direction == DMA_TO_DEVICE) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); @@ -726,7 +748,6 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (!bio) goto fail_free_ibr; - bio_start = bio; bio_list_init(&list); bio_list_add(&list, bio); @@ -741,6 +762,13 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, */ while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) != sg->length) { + if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { + rc = iblock_alloc_bip(cmd, bio, &sg_prot, + &skip); + if (rc) + goto fail_put_bios; + } + if (bio_cnt >= IBLOCK_MAX_BIO_PER_TASK) { iblock_submit_bios(&list); bio_cnt = 0; @@ -762,7 +790,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, } if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { - int rc = iblock_alloc_bip(cmd, bio_start); + rc = iblock_alloc_bip(cmd, bio, &sg_prot, &skip); if (rc) goto fail_put_bios; } -- 2.17.1