Skip to content

Commit e5863d9

Browse files
committed
dm: allocate requests in target when stacking on blk-mq devices
For blk-mq request-based DM the responsibility of allocating a cloned request is transfered from DM core to the target type. Doing so enables the cloned request to be allocated from the appropriate blk-mq request_queue's pool (only the DM target, e.g. multipath, can know which block device to send a given cloned request to). Care was taken to preserve compatibility with old-style block request completion that requires request-based DM _not_ acquire the clone request's queue lock in the completion path. As such, there are now 2 different request-based DM target_type interfaces: 1) the original .map_rq() interface will continue to be used for non-blk-mq devices -- the preallocated clone request is passed in from DM core. 2) a new .clone_and_map_rq() and .release_clone_rq() will be used for blk-mq devices -- blk_get_request() and blk_put_request() are used respectively from these hooks. dm_table_set_type() was updated to detect if the request-based target is being stacked on blk-mq devices, if so DM_TYPE_MQ_REQUEST_BASED is set. DM core disallows switching the DM table's type after it is set. This means that there is no mixing of non-blk-mq and blk-mq devices within the same request-based DM table. [This patch was started by Keith and later heavily modified by Mike] Tested-by: Bart Van Assche <[email protected]> Signed-off-by: Keith Busch <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent 466d89a commit e5863d9

File tree

7 files changed

+185
-48
lines changed

7 files changed

+185
-48
lines changed

drivers/md/dm-mpath.c

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "dm-path-selector.h"
1212
#include "dm-uevent.h"
1313

14+
#include <linux/blkdev.h>
1415
#include <linux/ctype.h>
1516
#include <linux/init.h>
1617
#include <linux/mempool.h>
@@ -378,12 +379,13 @@ static int __must_push_back(struct multipath *m)
378379
/*
379380
* Map cloned requests
380381
*/
381-
static int multipath_map(struct dm_target *ti, struct request *clone,
382-
union map_info *map_context)
382+
static int __multipath_map(struct dm_target *ti, struct request *clone,
383+
union map_info *map_context,
384+
struct request *rq, struct request **__clone)
383385
{
384386
struct multipath *m = (struct multipath *) ti->private;
385387
int r = DM_MAPIO_REQUEUE;
386-
size_t nr_bytes = blk_rq_bytes(clone);
388+
size_t nr_bytes = clone ? blk_rq_bytes(clone) : blk_rq_bytes(rq);
387389
struct pgpath *pgpath;
388390
struct block_device *bdev;
389391
struct dm_mpath_io *mpio;
@@ -416,12 +418,25 @@ static int multipath_map(struct dm_target *ti, struct request *clone,
416418

417419
bdev = pgpath->path.dev->bdev;
418420

419-
clone->q = bdev_get_queue(bdev);
420-
clone->rq_disk = bdev->bd_disk;
421-
clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
422-
423421
spin_unlock_irq(&m->lock);
424422

423+
if (clone) {
424+
/* Old request-based interface: allocated clone is passed in */
425+
clone->q = bdev_get_queue(bdev);
426+
clone->rq_disk = bdev->bd_disk;
427+
clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
428+
} else {
429+
/* blk-mq request-based interface */
430+
*__clone = blk_get_request(bdev_get_queue(bdev),
431+
rq_data_dir(rq), GFP_KERNEL);
432+
if (IS_ERR(*__clone))
433+
/* ENOMEM, requeue */
434+
return r;
435+
(*__clone)->bio = (*__clone)->biotail = NULL;
436+
(*__clone)->rq_disk = bdev->bd_disk;
437+
(*__clone)->cmd_flags |= REQ_FAILFAST_TRANSPORT;
438+
}
439+
425440
if (pgpath->pg->ps.type->start_io)
426441
pgpath->pg->ps.type->start_io(&pgpath->pg->ps,
427442
&pgpath->path,
@@ -434,6 +449,24 @@ static int multipath_map(struct dm_target *ti, struct request *clone,
434449
return r;
435450
}
436451

452+
static int multipath_map(struct dm_target *ti, struct request *clone,
453+
union map_info *map_context)
454+
{
455+
return __multipath_map(ti, clone, map_context, NULL, NULL);
456+
}
457+
458+
static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
459+
union map_info *map_context,
460+
struct request **clone)
461+
{
462+
return __multipath_map(ti, NULL, map_context, rq, clone);
463+
}
464+
465+
static void multipath_release_clone(struct request *clone)
466+
{
467+
blk_put_request(clone);
468+
}
469+
437470
/*
438471
* If we run out of usable paths, should we queue I/O or error it?
439472
*/
@@ -1670,11 +1703,13 @@ static int multipath_busy(struct dm_target *ti)
16701703
*---------------------------------------------------------------*/
16711704
static struct target_type multipath_target = {
16721705
.name = "multipath",
1673-
.version = {1, 7, 0},
1706+
.version = {1, 8, 0},
16741707
.module = THIS_MODULE,
16751708
.ctr = multipath_ctr,
16761709
.dtr = multipath_dtr,
16771710
.map_rq = multipath_map,
1711+
.clone_and_map_rq = multipath_clone_and_map,
1712+
.release_clone_rq = multipath_release_clone,
16781713
.rq_end_io = multipath_end_io,
16791714
.presuspend = multipath_presuspend,
16801715
.postsuspend = multipath_postsuspend,

drivers/md/dm-table.c

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,7 @@ static int dm_table_set_type(struct dm_table *t)
827827
{
828828
unsigned i;
829829
unsigned bio_based = 0, request_based = 0, hybrid = 0;
830+
bool use_blk_mq = false;
830831
struct dm_target *tgt;
831832
struct dm_dev_internal *dd;
832833
struct list_head *devices;
@@ -872,11 +873,26 @@ static int dm_table_set_type(struct dm_table *t)
872873
/* Non-request-stackable devices can't be used for request-based dm */
873874
devices = dm_table_get_devices(t);
874875
list_for_each_entry(dd, devices, list) {
875-
if (!blk_queue_stackable(bdev_get_queue(dd->dm_dev->bdev))) {
876-
DMWARN("table load rejected: including"
877-
" non-request-stackable devices");
876+
struct request_queue *q = bdev_get_queue(dd->dm_dev->bdev);
877+
878+
if (!blk_queue_stackable(q)) {
879+
DMERR("table load rejected: including"
880+
" non-request-stackable devices");
878881
return -EINVAL;
879882
}
883+
884+
if (q->mq_ops)
885+
use_blk_mq = true;
886+
}
887+
888+
if (use_blk_mq) {
889+
/* verify _all_ devices in the table are blk-mq devices */
890+
list_for_each_entry(dd, devices, list)
891+
if (!bdev_get_queue(dd->dm_dev->bdev)->mq_ops) {
892+
DMERR("table load rejected: not all devices"
893+
" are blk-mq request-stackable");
894+
return -EINVAL;
895+
}
880896
}
881897

882898
/*
@@ -890,7 +906,7 @@ static int dm_table_set_type(struct dm_table *t)
890906
return -EINVAL;
891907
}
892908

893-
t->type = DM_TYPE_REQUEST_BASED;
909+
t->type = !use_blk_mq ? DM_TYPE_REQUEST_BASED : DM_TYPE_MQ_REQUEST_BASED;
894910

895911
return 0;
896912
}
@@ -907,7 +923,15 @@ struct target_type *dm_table_get_immutable_target_type(struct dm_table *t)
907923

908924
bool dm_table_request_based(struct dm_table *t)
909925
{
910-
return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED;
926+
unsigned table_type = dm_table_get_type(t);
927+
928+
return (table_type == DM_TYPE_REQUEST_BASED ||
929+
table_type == DM_TYPE_MQ_REQUEST_BASED);
930+
}
931+
932+
bool dm_table_mq_request_based(struct dm_table *t)
933+
{
934+
return dm_table_get_type(t) == DM_TYPE_MQ_REQUEST_BASED;
911935
}
912936

913937
static int dm_table_alloc_md_mempools(struct dm_table *t)

drivers/md/dm-target.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,26 @@ static int io_err_map_rq(struct dm_target *ti, struct request *clone,
137137
return -EIO;
138138
}
139139

140+
static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq,
141+
union map_info *map_context,
142+
struct request **clone)
143+
{
144+
return -EIO;
145+
}
146+
147+
static void io_err_release_clone_rq(struct request *clone)
148+
{
149+
}
150+
140151
static struct target_type error_target = {
141152
.name = "error",
142-
.version = {1, 2, 0},
153+
.version = {1, 3, 0},
143154
.ctr = io_err_ctr,
144155
.dtr = io_err_dtr,
145156
.map = io_err_map,
146157
.map_rq = io_err_map_rq,
158+
.clone_and_map_rq = io_err_clone_and_map_rq,
159+
.release_clone_rq = io_err_release_clone_rq,
147160
};
148161

149162
int __init dm_target_init(void)

0 commit comments

Comments
 (0)