Re: [PATCH] target/iblock: split T10 PI SGL across command bios

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 08/08/2018 02:31 PM, Greg Edwards wrote:
> 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.
> 

Did you hit this with a older distro kernel?

It looks like iblock_get_bio will alloc a bio that has enough vecs for
the entire cmd (bi_max_vecs will equal sgl_nents). So it is not clear to
me how does the bio_add_page call ever return a value other than
sg->length, and we end up doing another iblock_get_bio call?


> 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;
>  	}
> 




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux