Skip to content

Commit 500c6ff

Browse files
committed
Add support for two bdevs in blkdev_copy_offload
Signed-off-by: Ameer Hamza <[email protected]>
1 parent a658c9e commit 500c6ff

File tree

4 files changed

+69
-34
lines changed

4 files changed

+69
-34
lines changed

block/blk-core.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -854,18 +854,18 @@ void submit_bio_noacct(struct bio *bio)
854854
if (!bdev_is_zoned(bio->bi_bdev))
855855
goto not_supported;
856856
break;
857+
case REQ_OP_COPY_SRC:
858+
case REQ_OP_COPY_DST:
859+
if (!q->limits.max_copy_sectors)
860+
goto not_supported;
861+
break;
857862
case REQ_OP_DRV_IN:
858863
case REQ_OP_DRV_OUT:
859864
/*
860865
* Driver private operations are only used with passthrough
861866
* requests.
862867
*/
863868
fallthrough;
864-
case REQ_OP_COPY_SRC:
865-
case REQ_OP_COPY_DST:
866-
if (!q->limits.max_copy_sectors)
867-
goto not_supported;
868-
break;
869869
default:
870870
goto not_supported;
871871
}

block/blk-lib.c

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,6 @@
1010

1111
#include "blk.h"
1212

13-
/* Keeps track of all outstanding copy IO */
14-
struct blkdev_copy_io {
15-
atomic_t refcount;
16-
ssize_t copied;
17-
int status;
18-
struct task_struct *waiter;
19-
void (*endio)(void *private, int status, ssize_t copied);
20-
void *private;
21-
};
22-
23-
/* Keeps track of single outstanding copy offload IO */
24-
struct blkdev_copy_offload_io {
25-
struct blkdev_copy_io *cio;
26-
loff_t offset;
27-
};
28-
2913
static sector_t bio_discard_limit(struct block_device *bdev, sector_t sector)
3014
{
3115
unsigned int discard_granularity = bdev_discard_granularity(bdev);
@@ -180,14 +164,17 @@ static void blkdev_copy_offload_src_endio(struct bio *bio)
180164
cio->status = blk_status_to_errno(bio->bi_status);
181165
}
182166
bio_put(bio);
167+
if (offload_io->dst_bio)
168+
bio_put(offload_io->dst_bio);
169+
183170
kfree(offload_io);
184171

185172
if (atomic_dec_and_test(&cio->refcount))
186173
blkdev_copy_endio(cio);
187174
}
188175

189176
/*
190-
* @bdev: block device
177+
* @bdev: source block device
191178
* @pos_in: source offset
192179
* @pos_out: destination offset
193180
* @len: length in bytes to be copied
@@ -196,6 +183,7 @@ static void blkdev_copy_offload_src_endio(struct bio *bio)
196183
* @private: endio function will be called with this private data,
197184
* for synchronous operation this should be NULL
198185
* @gfp_mask: memory allocation flags (for bio_alloc)
186+
* @bdev_out: destination block device
199187
*
200188
* For synchronous operation returns the length of bytes copied or error
201189
* For asynchronous operation returns -EIOCBQUEUED or error
@@ -216,20 +204,38 @@ static void blkdev_copy_offload_src_endio(struct bio *bio)
216204
ssize_t blkdev_copy_offload(struct block_device *bdev, loff_t pos_in,
217205
loff_t pos_out, size_t len,
218206
void (*endio)(void *, int, ssize_t),
219-
void *private, gfp_t gfp)
207+
void *private, gfp_t gfp, struct block_device *bdev_out)
220208
{
221209
struct blkdev_copy_io *cio;
222210
struct blkdev_copy_offload_io *offload_io;
223211
struct bio *src_bio, *dst_bio;
224212
size_t rem, chunk;
225-
size_t max_copy_bytes = bdev_max_copy_sectors(bdev) << SECTOR_SHIFT;
226213
ssize_t ret;
227214
struct blk_plug plug;
215+
int is_mq = 0;
216+
size_t max_copy_bytes = min(bdev_max_copy_sectors(bdev) << SECTOR_SHIFT,
217+
bdev_max_copy_sectors(bdev_out) << SECTOR_SHIFT);
228218

229219
if (!max_copy_bytes)
230220
return -EOPNOTSUPP;
231221

232-
ret = blkdev_copy_sanity_check(bdev, pos_in, bdev, pos_out, len);
222+
if (queue_is_mq(bdev->bd_queue)) {
223+
if (bdev->bd_queue->mq_ops != bdev_out->bd_queue->mq_ops)
224+
return -EOPNOTSUPP;
225+
is_mq = 1;
226+
} else if (!bdev->bd_disk->fops->submit_bio ||
227+
bdev->bd_disk->fops->submit_bio != bdev_out->bd_disk->fops->submit_bio) {
228+
return -EOPNOTSUPP;
229+
}
230+
231+
/*
232+
* Cross device copy only supported for zvols
233+
*/
234+
if (strncmp(bdev_out->bd_disk->disk_name, "zd", 2))
235+
return -EOPNOTSUPP;
236+
237+
ret = blkdev_copy_sanity_check(bdev, pos_in, bdev_out, pos_out, len);
238+
233239
if (ret)
234240
return ret;
235241

@@ -258,25 +264,33 @@ ssize_t blkdev_copy_offload(struct block_device *bdev, loff_t pos_in,
258264
* successful copy length
259265
*/
260266
offload_io->offset = len - rem;
267+
if (bdev_out)
268+
offload_io->driver_private = bdev_out->bd_queue->queuedata;
261269

262270
dst_bio = bio_alloc(bdev, 0, REQ_OP_COPY_DST, gfp);
263271
if (!dst_bio)
264272
goto err_free_offload_io;
265273
dst_bio->bi_iter.bi_size = chunk;
266274
dst_bio->bi_iter.bi_sector = pos_out >> SECTOR_SHIFT;
267275

268-
blk_start_plug(&plug);
269-
src_bio = blk_next_bio(dst_bio, bdev, 0, REQ_OP_COPY_SRC, gfp);
276+
if (is_mq) {
277+
blk_start_plug(&plug);
278+
src_bio = blk_next_bio(dst_bio, bdev, 0, REQ_OP_COPY_SRC, gfp);
279+
} else {
280+
src_bio = bio_alloc(bdev, 0, REQ_OP_COPY_SRC, gfp);
281+
}
270282
if (!src_bio)
271283
goto err_free_dst_bio;
272284
src_bio->bi_iter.bi_size = chunk;
273285
src_bio->bi_iter.bi_sector = pos_in >> SECTOR_SHIFT;
274286
src_bio->bi_end_io = blkdev_copy_offload_src_endio;
275287
src_bio->bi_private = offload_io;
288+
offload_io->dst_bio = (is_mq) ? NULL : dst_bio;
276289

277290
atomic_inc(&cio->refcount);
278291
submit_bio(src_bio);
279-
blk_finish_plug(&plug);
292+
if (is_mq)
293+
blk_finish_plug(&plug);
280294
pos_in += chunk;
281295
pos_out += chunk;
282296
}
@@ -289,6 +303,8 @@ ssize_t blkdev_copy_offload(struct block_device *bdev, loff_t pos_in,
289303
return blkdev_copy_wait_for_completion_io(cio);
290304

291305
err_free_dst_bio:
306+
if (is_mq)
307+
blk_finish_plug(&plug);
292308
bio_put(dst_bio);
293309
err_free_offload_io:
294310
kfree(offload_io);

block/fops.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -784,12 +784,12 @@ static ssize_t blkdev_copy_file_range(struct file *file_in, loff_t pos_in,
784784
struct block_device *out_bdev = I_BDEV(bdev_file_inode(file_out));
785785
ssize_t copied = 0;
786786

787-
if ((in_bdev == out_bdev) && bdev_max_copy_sectors(in_bdev) &&
787+
if (bdev_max_copy_sectors(in_bdev) &&
788788
(file_in->f_iocb_flags & IOCB_DIRECT) &&
789789
(file_out->f_iocb_flags & IOCB_DIRECT)) {
790790
copied = blkdev_copy_offload(in_bdev, pos_in, pos_out, len,
791-
NULL, NULL, GFP_KERNEL);
792-
if (copied < 0)
791+
NULL, NULL, GFP_KERNEL, out_bdev);
792+
if (copied != -EOPNOTSUPP && copied < 0)
793793
copied = 0;
794794
} else {
795795
copied = splice_copy_file_range(file_in, pos_in + copied,

include/linux/blkdev.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,24 @@ struct queue_limits {
409409
struct blk_integrity integrity;
410410
};
411411

412+
/* Keeps track of all outstanding copy IO */
413+
struct blkdev_copy_io {
414+
atomic_t refcount;
415+
ssize_t copied;
416+
int status;
417+
struct task_struct *waiter;
418+
void (*endio)(void *private, int status, ssize_t copied);
419+
void *private;
420+
};
421+
422+
/* Keeps track of single outstanding copy offload IO */
423+
struct blkdev_copy_offload_io {
424+
struct bio *dst_bio;
425+
void *driver_private;
426+
struct blkdev_copy_io *cio;
427+
loff_t offset;
428+
};
429+
412430
typedef int (*report_zones_cb)(struct blk_zone *zone, unsigned int idx,
413431
void *data);
414432

@@ -1111,7 +1129,8 @@ int blkdev_issue_secure_erase(struct block_device *bdev, sector_t sector,
11111129
ssize_t blkdev_copy_offload(struct block_device *bdev, loff_t pos_in,
11121130
loff_t pos_out, size_t len,
11131131
void (*endio)(void *, int, ssize_t),
1114-
void *private, gfp_t gfp_mask);
1132+
void *private, gfp_t gfp_mask,
1133+
struct block_device *bdev_out);
11151134

11161135
#define BLKDEV_ZERO_NOUNMAP (1 << 0) /* do not free blocks */
11171136
#define BLKDEV_ZERO_NOFALLBACK (1 << 1) /* don't write explicit zeroes */
@@ -1307,8 +1326,8 @@ static inline unsigned int bdev_discard_granularity(struct block_device *bdev)
13071326
return bdev_get_queue(bdev)->limits.discard_granularity;
13081327
}
13091328

1310-
/* maximum copy offload length, this is set to 128MB based on current testing */
1311-
#define BLK_COPY_MAX_BYTES (1 << 27)
1329+
/* Tested till 2GB with zvol testing */
1330+
#define BLK_COPY_MAX_BYTES (1U << 31)
13121331

13131332
static inline unsigned int bdev_max_copy_sectors(struct block_device *bdev)
13141333
{

0 commit comments

Comments
 (0)