Skip to content

Commit b0fd271

Browse files
Kiyoshi UedaJens Axboe
authored andcommitted
block: add request clone interface (v2)
This patch adds the following 2 interfaces for request-stacking drivers: - blk_rq_prep_clone(struct request *clone, struct request *orig, struct bio_set *bs, gfp_t gfp_mask, int (*bio_ctr)(struct bio *, struct bio*, void *), void *data) * Clones bios in the original request to the clone request (bio_ctr is called for each cloned bios.) * Copies attributes of the original request to the clone request. The actual data parts (e.g. ->cmd, ->buffer, ->sense) are not copied. - blk_rq_unprep_clone(struct request *clone) * Frees cloned bios from the clone request. Request stacking drivers (e.g. request-based dm) need to make a clone request for a submitted request and dispatch it to other devices. To allocate request for the clone, request stacking drivers may not be able to use blk_get_request() because the allocation may be done in an irq-disabled context. So blk_rq_prep_clone() takes a request allocated by the caller as an argument. For each clone bio in the clone request, request stacking drivers should be able to set up their own completion handler. So blk_rq_prep_clone() takes a callback function which is called for each clone bio, and a pointer for private data which is passed to the callback. NOTE: blk_rq_prep_clone() doesn't copy any actual data of the original request. Pages are shared between original bios and cloned bios. So caller must not complete the original request before the clone request. Signed-off-by: Kiyoshi Ueda <[email protected]> Signed-off-by: Jun'ichi Nomura <[email protected]> Cc: Boaz Harrosh <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 5e50b9e commit b0fd271

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

block/blk-core.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2295,6 +2295,106 @@ int blk_lld_busy(struct request_queue *q)
22952295
}
22962296
EXPORT_SYMBOL_GPL(blk_lld_busy);
22972297

2298+
/**
2299+
* blk_rq_unprep_clone - Helper function to free all bios in a cloned request
2300+
* @rq: the clone request to be cleaned up
2301+
*
2302+
* Description:
2303+
* Free all bios in @rq for a cloned request.
2304+
*/
2305+
void blk_rq_unprep_clone(struct request *rq)
2306+
{
2307+
struct bio *bio;
2308+
2309+
while ((bio = rq->bio) != NULL) {
2310+
rq->bio = bio->bi_next;
2311+
2312+
bio_put(bio);
2313+
}
2314+
}
2315+
EXPORT_SYMBOL_GPL(blk_rq_unprep_clone);
2316+
2317+
/*
2318+
* Copy attributes of the original request to the clone request.
2319+
* The actual data parts (e.g. ->cmd, ->buffer, ->sense) are not copied.
2320+
*/
2321+
static void __blk_rq_prep_clone(struct request *dst, struct request *src)
2322+
{
2323+
dst->cpu = src->cpu;
2324+
dst->cmd_flags = (rq_data_dir(src) | REQ_NOMERGE);
2325+
dst->cmd_type = src->cmd_type;
2326+
dst->__sector = blk_rq_pos(src);
2327+
dst->__data_len = blk_rq_bytes(src);
2328+
dst->nr_phys_segments = src->nr_phys_segments;
2329+
dst->ioprio = src->ioprio;
2330+
dst->extra_len = src->extra_len;
2331+
}
2332+
2333+
/**
2334+
* blk_rq_prep_clone - Helper function to setup clone request
2335+
* @rq: the request to be setup
2336+
* @rq_src: original request to be cloned
2337+
* @bs: bio_set that bios for clone are allocated from
2338+
* @gfp_mask: memory allocation mask for bio
2339+
* @bio_ctr: setup function to be called for each clone bio.
2340+
* Returns %0 for success, non %0 for failure.
2341+
* @data: private data to be passed to @bio_ctr
2342+
*
2343+
* Description:
2344+
* Clones bios in @rq_src to @rq, and copies attributes of @rq_src to @rq.
2345+
* The actual data parts of @rq_src (e.g. ->cmd, ->buffer, ->sense)
2346+
* are not copied, and copying such parts is the caller's responsibility.
2347+
* Also, pages which the original bios are pointing to are not copied
2348+
* and the cloned bios just point same pages.
2349+
* So cloned bios must be completed before original bios, which means
2350+
* the caller must complete @rq before @rq_src.
2351+
*/
2352+
int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
2353+
struct bio_set *bs, gfp_t gfp_mask,
2354+
int (*bio_ctr)(struct bio *, struct bio *, void *),
2355+
void *data)
2356+
{
2357+
struct bio *bio, *bio_src;
2358+
2359+
if (!bs)
2360+
bs = fs_bio_set;
2361+
2362+
blk_rq_init(NULL, rq);
2363+
2364+
__rq_for_each_bio(bio_src, rq_src) {
2365+
bio = bio_alloc_bioset(gfp_mask, bio_src->bi_max_vecs, bs);
2366+
if (!bio)
2367+
goto free_and_out;
2368+
2369+
__bio_clone(bio, bio_src);
2370+
2371+
if (bio_integrity(bio_src) &&
2372+
bio_integrity_clone(bio, bio_src, gfp_mask))
2373+
goto free_and_out;
2374+
2375+
if (bio_ctr && bio_ctr(bio, bio_src, data))
2376+
goto free_and_out;
2377+
2378+
if (rq->bio) {
2379+
rq->biotail->bi_next = bio;
2380+
rq->biotail = bio;
2381+
} else
2382+
rq->bio = rq->biotail = bio;
2383+
}
2384+
2385+
__blk_rq_prep_clone(rq, rq_src);
2386+
2387+
return 0;
2388+
2389+
free_and_out:
2390+
if (bio)
2391+
bio_free(bio, bs);
2392+
blk_rq_unprep_clone(rq);
2393+
2394+
return -ENOMEM;
2395+
}
2396+
EXPORT_SYMBOL_GPL(blk_rq_prep_clone);
2397+
22982398
int kblockd_schedule_work(struct request_queue *q, struct work_struct *work)
22992399
{
23002400
return queue_work(kblockd_workqueue, work);

include/linux/blkdev.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,11 @@ extern void blk_insert_request(struct request_queue *, struct request *, int, vo
765765
extern void blk_requeue_request(struct request_queue *, struct request *);
766766
extern int blk_rq_check_limits(struct request_queue *q, struct request *rq);
767767
extern int blk_lld_busy(struct request_queue *q);
768+
extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
769+
struct bio_set *bs, gfp_t gfp_mask,
770+
int (*bio_ctr)(struct bio *, struct bio *, void *),
771+
void *data);
772+
extern void blk_rq_unprep_clone(struct request *rq);
768773
extern int blk_insert_cloned_request(struct request_queue *q,
769774
struct request *rq);
770775
extern void blk_plug_device(struct request_queue *);

0 commit comments

Comments
 (0)