Skip to content

Commit 6be6e4d

Browse files
nj-shettykawasaki
authored andcommitted
block: Add the REQ_OP_COPY_{SRC,DST} operations
Introduce the REQ_OP_COPY_SRC and REQ_OP_COPY_DST operations. The source and destination LBA range information is in separate bios because any other approach would require a rewrite of the device mapper. These bios are associated with each other via the new bi_copy_ctx pointer. A new pointer has been introduced because the copy offloading context information must be preserved when cloning a bio and the bi_private bio member must not be copied when cloning a bio. This patch supports the following approach for copy offloading: 1. Allocate a struct bio_copy_offload_ctx instance and set phase to BLKDEV_TRANSLATE_LBAS. 2. Allocate REQ_OP_COPY_SRC and REQ_OP_COPY_DST bios. Set the bi_copy_ctx member of these bios. 3. Set the bio_count member of struct bio_copy_offload_ctx. 4. Submit all REQ_OP_COPY_* bios. 5. In submit_bio(), do the following for REQ_OP_COPY_* bios: - If bio->bi_bdev is a stacking device, submit the bio. This will send the bio to the device mapper. The device mapper will clone the bio, translate the LBAs and will submit the cloned bio. That will result in a recursive submit_bio() call. - If bio->bi_bdev is not a stacking device, add the bio to the copy_ctx->bios list and decrement copy_ctx->bio_count. 6. Once copy_ctx->bio_count == 0, call copy_ctx->translation_complete(). 7. In the implementation of copy_ctx->translation_complete(), change copy_ctx->phase from BLKDEV_TRANSLATE_LBAS into BLKDEV_COPY. 8. Submit the first REQ_OP_COPY_* bio of the copy_ctx->bios list. 9. Once this bio reaches the block driver associated with the bio, retrieve the other bios involved in the copy operation from the copy context data structure and convert all these bios into a copy offload operation. 10. Once this bio completes, also complete all the other bios involved in the copy offload operation. This patch increases the size of struct bio from 104 to 112 bytes on 64-bit systems. To be discussed further: whether adding a new member in struct bio is acceptable or whether the new pointer perhaps should be stored in front of the bio. bioset_init() supports front padding. Signed-off-by: Nitesh Shetty <[email protected]> Signed-off-by: Anuj Gupta <[email protected]> [ bvanassche: changed the approach of this patch from combining the COPY_SRC and COPY_DST operations immediately to translating the LBA information first. ] Signed-off-by: Bart Van Assche <[email protected]>
1 parent 64dd6e0 commit 6be6e4d

6 files changed

Lines changed: 120 additions & 0 deletions

File tree

block/bio.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,7 @@ static int __bio_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp)
851851
bio->bi_write_hint = bio_src->bi_write_hint;
852852
bio->bi_write_stream = bio_src->bi_write_stream;
853853
bio->bi_iter = bio_src->bi_iter;
854+
bio->bi_copy_ctx = bio_src->bi_copy_ctx;
854855

855856
if (bio->bi_bdev) {
856857
if (bio->bi_bdev == bio_src->bi_bdev &&

block/blk-core.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/module.h>
1717
#include <linux/bio.h>
1818
#include <linux/blkdev.h>
19+
#include <linux/blk-copy.h>
1920
#include <linux/blk-pm.h>
2021
#include <linux/blk-integrity.h>
2122
#include <linux/highmem.h>
@@ -108,6 +109,8 @@ static const char *const blk_op_name[] = {
108109
REQ_OP_NAME(ZONE_FINISH),
109110
REQ_OP_NAME(ZONE_APPEND),
110111
REQ_OP_NAME(WRITE_ZEROES),
112+
REQ_OP_NAME(COPY_SRC),
113+
REQ_OP_NAME(COPY_DST),
111114
REQ_OP_NAME(DRV_IN),
112115
REQ_OP_NAME(DRV_OUT),
113116
};
@@ -782,6 +785,8 @@ void submit_bio_noacct(struct bio *bio)
782785
struct block_device *bdev = bio->bi_bdev;
783786
struct request_queue *q = bdev_get_queue(bdev);
784787
blk_status_t status = BLK_STS_IOERR;
788+
struct bio_copy_offload_ctx *copy_ctx;
789+
u32 bio_count;
785790

786791
might_sleep();
787792

@@ -875,6 +880,39 @@ void submit_bio_noacct(struct bio *bio)
875880
* requests.
876881
*/
877882
fallthrough;
883+
case REQ_OP_COPY_SRC:
884+
case REQ_OP_COPY_DST:
885+
copy_ctx = bio->bi_copy_ctx;
886+
WARN_ON_ONCE(copy_ctx->phase == BLKDEV_COPY_DONE);
887+
if (copy_ctx->phase == BLKDEV_COPY)
888+
break;
889+
/* If copy offloading is not supported, fail the bio. */
890+
if (!q->limits.max_copy_sectors) {
891+
scoped_guard(spinlock_irqsave, &copy_ctx->lock)
892+
copy_ctx->bio_count--;
893+
goto not_supported;
894+
}
895+
/*
896+
* If the block driver is a stacking driver that supports copy
897+
* offloading, submit the bio.
898+
*/
899+
if (q->limits.features & BLK_FEAT_STACKING_COPY_OFFL)
900+
break;
901+
/*
902+
* Append the bio at the end of the bio->bi_copy_ctx->bios list.
903+
*/
904+
scoped_guard(spinlock_irqsave, &copy_ctx->lock) {
905+
if (copy_ctx->biotail)
906+
copy_ctx->biotail->bi_next = bio;
907+
else
908+
copy_ctx->bios = bio;
909+
copy_ctx->biotail = bio;
910+
bio_count = --copy_ctx->bio_count;
911+
}
912+
WARN_ON_ONCE(bio_count < 0);
913+
if (bio_count == 0)
914+
copy_ctx->translation_complete(copy_ctx);
915+
return;
878916
default:
879917
goto not_supported;
880918
}

block/blk-merge.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,19 @@ struct bio *bio_split_discard(struct bio *bio, const struct queue_limits *lim,
207207
return __bio_split_discard(bio, lim, nsegs, max_sectors);
208208
}
209209

210+
struct bio *bio_split_copy(struct bio *bio, const struct queue_limits *lim,
211+
unsigned int *nsegs)
212+
{
213+
*nsegs = 1;
214+
if (bio_sectors(bio) <= lim->max_copy_sectors)
215+
return bio;
216+
217+
/* Splitting a REQ_OP_COPY_* bio is not supported. */
218+
bio->bi_status = BLK_STS_NOTSUPP;
219+
bio_endio(bio);
220+
return NULL;
221+
}
222+
210223
static inline unsigned int blk_boundary_sectors(const struct queue_limits *lim,
211224
bool is_atomic)
212225
{

block/blk.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ struct bio *bio_split_rw(struct bio *bio, const struct queue_limits *lim,
358358
unsigned *nr_segs);
359359
struct bio *bio_split_zone_append(struct bio *bio,
360360
const struct queue_limits *lim, unsigned *nr_segs);
361+
struct bio *bio_split_copy(struct bio *bio, const struct queue_limits *lim,
362+
unsigned int *nsegs);
361363

362364
/*
363365
* All drivers must accept single-segments bios that are smaller than PAGE_SIZE.
@@ -414,6 +416,9 @@ static inline struct bio *__bio_split_to_limits(struct bio *bio,
414416
return bio_split_discard(bio, lim, nr_segs);
415417
case REQ_OP_WRITE_ZEROES:
416418
return bio_split_write_zeroes(bio, lim, nr_segs);
419+
case REQ_OP_COPY_SRC:
420+
case REQ_OP_COPY_DST:
421+
return bio_split_copy(bio, lim, nr_segs);
417422
default:
418423
/* other operations can't be split */
419424
*nr_segs = 0;

include/linux/blk-copy.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#ifndef __LINUX_BLK_COPY_H
4+
#define __LINUX_BLK_COPY_H
5+
6+
#include <linux/blk_types.h>
7+
#include <linux/completion.h>
8+
#include <linux/list.h>
9+
#include <linux/spinlock_types.h>
10+
#include <linux/workqueue_types.h>
11+
12+
struct blk_copy_params;
13+
struct request;
14+
15+
enum blkdev_copy_phase {
16+
BLKDEV_TRANSLATE_LBAS,
17+
BLKDEV_COPY,
18+
BLKDEV_COPY_DONE,
19+
};
20+
21+
/*
22+
* struct bio_copy_offload_ctx - context information for blkdev_copy_offload()
23+
* @params: Input parameters passed to blkdev_copy_offload().
24+
* @len: Number of bytes associated with this copy context.
25+
* @phase: Copy offload phase: either translating LBAs or copying data.
26+
* @lock: Protects @bios, @biotail and @bio_count.
27+
* @bios: List with REQ_OP_COPY_* bios for which LBA translation completed.
28+
* @biotail: Last element in the @bios list.
29+
* @bio_count: Number bios for which LBA translation has not yet completed.
30+
* @status: bio completion status.
31+
* @translation_complete: Called after LBA translation has completed.
32+
* LBA translation has completed once bio_count drops to zero.
33+
*/
34+
struct bio_copy_offload_ctx {
35+
struct blk_copy_params *params;
36+
loff_t len;
37+
enum blkdev_copy_phase phase;
38+
spinlock_t lock;
39+
struct bio *bios __guarded_by(&lock);
40+
struct bio *biotail __guarded_by(&lock);
41+
u32 bio_count __guarded_by(&lock);
42+
blk_status_t status __guarded_by(&lock);
43+
void (*translation_complete)(struct bio_copy_offload_ctx *ctx);
44+
};
45+
46+
#endif /* __LINUX_BLK_COPY_H */

include/linux/blk_types.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ struct bio {
284284
atomic_t __bi_cnt; /* pin count */
285285

286286
struct bio_set *bi_pool;
287+
288+
void *bi_copy_ctx;
287289
};
288290

289291
#define BIO_RESET_BYTES offsetof(struct bio, bi_max_vecs)
@@ -370,6 +372,10 @@ enum req_op {
370372
/** @REQ_OP_ZONE_RESET_ALL: reset all the zone present on the device */
371373
REQ_OP_ZONE_RESET_ALL = (__force blk_opf_t)19,
372374

375+
/* copy offload source and destination operations */
376+
REQ_OP_COPY_SRC = (__force blk_opf_t)20,
377+
REQ_OP_COPY_DST = (__force blk_opf_t)21,
378+
373379
/* Driver private requests */
374380
/* private: */
375381
REQ_OP_DRV_IN = (__force blk_opf_t)34,
@@ -461,6 +467,17 @@ static inline bool op_is_write(blk_opf_t op)
461467
return !!(op & (__force blk_opf_t)1);
462468
}
463469

470+
static inline bool op_is_copy(blk_opf_t op)
471+
{
472+
switch (op & REQ_OP_MASK) {
473+
case REQ_OP_COPY_DST:
474+
case REQ_OP_COPY_SRC:
475+
return true;
476+
default:
477+
return false;
478+
}
479+
}
480+
464481
/*
465482
* Check if the bio or request is one that needs special treatment in the
466483
* flush state machine.

0 commit comments

Comments
 (0)