On Wed, 2014-05-28 at 23:52 -0400, Martin K. Petersen wrote:
> blkdev_issue_copy() is a library function that filesystems can use to
> clone block ranges between devices that support copy offloading. Both
> source and target device must have max_copy_sectors > 0 in the queue
> limits.
> 
> blkdev_issue_copy() will iterate over the blocks in the source range and
> issue copy offload requests using the granularity preferred by source
> and target.
> 
> There is no guarantee that a copy offload operation will be successful
> even if both devices are offload-capable. Filesystems must be prepared
> to manually copy or punt to userland if the operation fails.
> 
> Signed-off-by: Martin K. Petersen <martin.peter...@oracle.com>
> ---
>  block/blk-lib.c        | 85 
> ++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/blkdev.h |  2 ++
>  2 files changed, 87 insertions(+)
> 
> diff --git a/block/blk-lib.c b/block/blk-lib.c
> index 97a733cf3d5f..5a0afc6e933e 100644
> --- a/block/blk-lib.c
> +++ b/block/blk-lib.c
> @@ -305,3 +305,88 @@ int blkdev_issue_zeroout(struct block_device *bdev, 
> sector_t sector,
>       return __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask);
>  }
>  EXPORT_SYMBOL(blkdev_issue_zeroout);
> +
> +/**
> + * blkdev_issue_copy - queue a copy same operation
> + * @src_bdev:        source blockdev
> + * @src_sector:      source sector
> + * @dst_bdev:        destination blockdev
> + * @dst_sector: destination sector
> + * @nr_sects:        number of sectors to copy
> + * @gfp_mask:        memory allocation flags (for bio_alloc)
> + *
> + * Description:
> + *    Copy a block range from source device to target device.
> + */
> +int blkdev_issue_copy(struct block_device *src_bdev, sector_t src_sector,
> +                   struct block_device *dst_bdev, sector_t dst_sector,
> +                   unsigned int nr_sects, gfp_t gfp_mask)
> +{
> +     DECLARE_COMPLETION_ONSTACK(wait);
> +     struct request_queue *sq = bdev_get_queue(src_bdev);
> +     struct request_queue *dq = bdev_get_queue(dst_bdev);
> +     unsigned int max_copy_sectors;
> +     struct bio_batch bb;
> +     int ret = 0;
> +
> +     if (!sq || !dq)
> +             return -ENXIO;
> +
> +     max_copy_sectors = min(sq->limits.max_copy_sectors,
> +                            dq->limits.max_copy_sectors);
> +
> +     if (max_copy_sectors == 0)
> +             return -EOPNOTSUPP;
> +
> +     atomic_set(&bb.done, 1);
> +     bb.flags = 1 << BIO_UPTODATE;
> +     bb.wait = &wait;
> +
> +     while (nr_sects) {
> +             struct bio *bio;
> +             struct bio_copy *bc;
> +             unsigned int chunk;
> +
> +             bc = kmalloc(sizeof(struct bio_copy), gfp_mask);
> +             if (!bc) {
> +                     ret = -ENOMEM;
> +                     break;
> +             }
> +
> +             bio = bio_alloc(gfp_mask, 1);
> +             if (!bio) {
> +                     kfree(bc);
> +                     ret = -ENOMEM;
> +                     break;
> +             }
> +
> +             chunk = min(nr_sects, max_copy_sectors);
> +
> +             bio->bi_iter.bi_sector = dst_sector;
> +             bio->bi_iter.bi_size = chunk << 9;
> +             bio->bi_end_io = bio_batch_end_io;
> +             bio->bi_bdev = dst_bdev;
> +             bio->bi_private = &bb;
> +             bio->bi_special.copy = bc;
> +
> +             bc->bic_bdev = src_bdev;
> +             bc->bic_sector = src_sector;
> +
> +             atomic_inc(&bb.done);
> +             submit_bio(REQ_WRITE | REQ_COPY, bio);
> +
> +             src_sector += chunk;
> +             dst_sector += chunk;
> +             nr_sects -= chunk;
> +     }
> +
> +     /* Wait for bios in-flight */
> +     if (!atomic_dec_and_test(&bb.done))
> +             wait_for_completion_io(&wait);
> +
> +     if (!test_bit(BIO_UPTODATE, &bb.flags))
> +             ret = -ENOTSUPP;
> +
> +     return ret;
> +}
> +EXPORT_SYMBOL(blkdev_issue_copy);

Mmmm, where does *bc memory get released in the normal bio completion
path..?

--nab

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to