diff options
author | Mike Snitzer <snitzer@redhat.com> | 2016-05-24 21:16:51 -0400 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2016-06-10 15:16:02 -0400 |
commit | e83068a5faafb8ca65d3b58bd1e1e3959ce1ddce (patch) | |
tree | 9158ec7acad94d7035153f84e8ff53205caf7315 | |
parent | bf661be1fcf9b1da8abc81a56ff41ce5964ce896 (diff) |
dm mpath: add optional "queue_mode" feature
Allow a user to specify an optional feature 'queue_mode <mode>' where
<mode> may be "bio", "rq" or "mq" -- which corresponds to bio-based,
request_fn rq-based, and blk-mq rq-based respectively.
If the queue_mode feature isn't specified the default for the
"multipath" target is still "rq" but if dm_mod.use_blk_mq is set to Y
it'll default to mode "mq".
This new queue_mode feature introduces the ability for each multipath
device to have its own queue_mode (whereas before this feature all
multipath devices effectively had to have the same queue_mode).
This commit also goes a long way to eliminate the awkward (ab)use of
DM_TYPE_*, the associated filter_md_type() and other relatively fragile
and difficult to maintain code.
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
-rw-r--r-- | drivers/md/dm-mpath.c | 149 | ||||
-rw-r--r-- | drivers/md/dm-rq.c | 19 | ||||
-rw-r--r-- | drivers/md/dm-rq.h | 2 | ||||
-rw-r--r-- | drivers/md/dm-table.c | 67 | ||||
-rw-r--r-- | drivers/md/dm.c | 15 | ||||
-rw-r--r-- | drivers/md/dm.h | 10 | ||||
-rw-r--r-- | include/linux/device-mapper.h | 16 |
7 files changed, 159 insertions, 119 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 2d10ff780d84..7eac080fcb18 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -90,6 +90,8 @@ struct multipath { | |||
90 | atomic_t pg_init_in_progress; /* Only one pg_init allowed at once */ | 90 | atomic_t pg_init_in_progress; /* Only one pg_init allowed at once */ |
91 | atomic_t pg_init_count; /* Number of times pg_init called */ | 91 | atomic_t pg_init_count; /* Number of times pg_init called */ |
92 | 92 | ||
93 | unsigned queue_mode; | ||
94 | |||
93 | /* | 95 | /* |
94 | * We must use a mempool of dm_mpath_io structs so that we | 96 | * We must use a mempool of dm_mpath_io structs so that we |
95 | * can resubmit bios on error. | 97 | * can resubmit bios on error. |
@@ -131,7 +133,6 @@ static void process_queued_bios(struct work_struct *work); | |||
131 | #define MPATHF_PG_INIT_DISABLED 4 /* pg_init is not currently allowed */ | 133 | #define MPATHF_PG_INIT_DISABLED 4 /* pg_init is not currently allowed */ |
132 | #define MPATHF_PG_INIT_REQUIRED 5 /* pg_init needs calling? */ | 134 | #define MPATHF_PG_INIT_REQUIRED 5 /* pg_init needs calling? */ |
133 | #define MPATHF_PG_INIT_DELAY_RETRY 6 /* Delay pg_init retry? */ | 135 | #define MPATHF_PG_INIT_DELAY_RETRY 6 /* Delay pg_init retry? */ |
134 | #define MPATHF_BIO_BASED 7 /* Device is bio-based? */ | ||
135 | 136 | ||
136 | /*----------------------------------------------- | 137 | /*----------------------------------------------- |
137 | * Allocation routines | 138 | * Allocation routines |
@@ -191,8 +192,7 @@ static void free_priority_group(struct priority_group *pg, | |||
191 | kfree(pg); | 192 | kfree(pg); |
192 | } | 193 | } |
193 | 194 | ||
194 | static struct multipath *alloc_multipath(struct dm_target *ti, bool use_blk_mq, | 195 | static struct multipath *alloc_multipath(struct dm_target *ti) |
195 | bool bio_based) | ||
196 | { | 196 | { |
197 | struct multipath *m; | 197 | struct multipath *m; |
198 | 198 | ||
@@ -210,25 +210,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti, bool use_blk_mq, | |||
210 | mutex_init(&m->work_mutex); | 210 | mutex_init(&m->work_mutex); |
211 | 211 | ||
212 | m->mpio_pool = NULL; | 212 | m->mpio_pool = NULL; |
213 | if (!use_blk_mq && !bio_based) { | 213 | m->queue_mode = DM_TYPE_NONE; |
214 | unsigned min_ios = dm_get_reserved_rq_based_ios(); | ||
215 | |||
216 | m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache); | ||
217 | if (!m->mpio_pool) { | ||
218 | kfree(m); | ||
219 | return NULL; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | if (bio_based) { | ||
224 | INIT_WORK(&m->process_queued_bios, process_queued_bios); | ||
225 | set_bit(MPATHF_BIO_BASED, &m->flags); | ||
226 | /* | ||
227 | * bio-based doesn't support any direct scsi_dh management; | ||
228 | * it just discovers if a scsi_dh is attached. | ||
229 | */ | ||
230 | set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); | ||
231 | } | ||
232 | 214 | ||
233 | m->ti = ti; | 215 | m->ti = ti; |
234 | ti->private = m; | 216 | ti->private = m; |
@@ -237,6 +219,39 @@ static struct multipath *alloc_multipath(struct dm_target *ti, bool use_blk_mq, | |||
237 | return m; | 219 | return m; |
238 | } | 220 | } |
239 | 221 | ||
222 | static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m) | ||
223 | { | ||
224 | if (m->queue_mode == DM_TYPE_NONE) { | ||
225 | /* | ||
226 | * Default to request-based. | ||
227 | */ | ||
228 | if (dm_use_blk_mq(dm_table_get_md(ti->table))) | ||
229 | m->queue_mode = DM_TYPE_MQ_REQUEST_BASED; | ||
230 | else | ||
231 | m->queue_mode = DM_TYPE_REQUEST_BASED; | ||
232 | } | ||
233 | |||
234 | if (m->queue_mode == DM_TYPE_REQUEST_BASED) { | ||
235 | unsigned min_ios = dm_get_reserved_rq_based_ios(); | ||
236 | |||
237 | m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache); | ||
238 | if (!m->mpio_pool) | ||
239 | return -ENOMEM; | ||
240 | } | ||
241 | else if (m->queue_mode == DM_TYPE_BIO_BASED) { | ||
242 | INIT_WORK(&m->process_queued_bios, process_queued_bios); | ||
243 | /* | ||
244 | * bio-based doesn't support any direct scsi_dh management; | ||
245 | * it just discovers if a scsi_dh is attached. | ||
246 | */ | ||
247 | set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); | ||
248 | } | ||
249 | |||
250 | dm_table_set_type(ti->table, m->queue_mode); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
240 | static void free_multipath(struct multipath *m) | 255 | static void free_multipath(struct multipath *m) |
241 | { | 256 | { |
242 | struct priority_group *pg, *tmp; | 257 | struct priority_group *pg, *tmp; |
@@ -653,7 +668,7 @@ static int multipath_map_bio(struct dm_target *ti, struct bio *bio) | |||
653 | 668 | ||
654 | static void process_queued_bios_list(struct multipath *m) | 669 | static void process_queued_bios_list(struct multipath *m) |
655 | { | 670 | { |
656 | if (test_bit(MPATHF_BIO_BASED, &m->flags)) | 671 | if (m->queue_mode == DM_TYPE_BIO_BASED) |
657 | queue_work(kmultipathd, &m->process_queued_bios); | 672 | queue_work(kmultipathd, &m->process_queued_bios); |
658 | } | 673 | } |
659 | 674 | ||
@@ -964,7 +979,7 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) | |||
964 | if (!hw_argc) | 979 | if (!hw_argc) |
965 | return 0; | 980 | return 0; |
966 | 981 | ||
967 | if (test_bit(MPATHF_BIO_BASED, &m->flags)) { | 982 | if (m->queue_mode == DM_TYPE_BIO_BASED) { |
968 | dm_consume_args(as, hw_argc); | 983 | dm_consume_args(as, hw_argc); |
969 | DMERR("bio-based multipath doesn't allow hardware handler args"); | 984 | DMERR("bio-based multipath doesn't allow hardware handler args"); |
970 | return 0; | 985 | return 0; |
@@ -1005,7 +1020,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) | |||
1005 | const char *arg_name; | 1020 | const char *arg_name; |
1006 | 1021 | ||
1007 | static struct dm_arg _args[] = { | 1022 | static struct dm_arg _args[] = { |
1008 | {0, 6, "invalid number of feature args"}, | 1023 | {0, 8, "invalid number of feature args"}, |
1009 | {1, 50, "pg_init_retries must be between 1 and 50"}, | 1024 | {1, 50, "pg_init_retries must be between 1 and 50"}, |
1010 | {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, | 1025 | {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, |
1011 | }; | 1026 | }; |
@@ -1045,6 +1060,24 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) | |||
1045 | continue; | 1060 | continue; |
1046 | } | 1061 | } |
1047 | 1062 | ||
1063 | if (!strcasecmp(arg_name, "queue_mode") && | ||
1064 | (argc >= 1)) { | ||
1065 | const char *queue_mode_name = dm_shift_arg(as); | ||
1066 | |||
1067 | if (!strcasecmp(queue_mode_name, "bio")) | ||
1068 | m->queue_mode = DM_TYPE_BIO_BASED; | ||
1069 | else if (!strcasecmp(queue_mode_name, "rq")) | ||
1070 | m->queue_mode = DM_TYPE_REQUEST_BASED; | ||
1071 | else if (!strcasecmp(queue_mode_name, "mq")) | ||
1072 | m->queue_mode = DM_TYPE_MQ_REQUEST_BASED; | ||
1073 | else { | ||
1074 | ti->error = "Unknown 'queue_mode' requested"; | ||
1075 | r = -EINVAL; | ||
1076 | } | ||
1077 | argc--; | ||
1078 | continue; | ||
1079 | } | ||
1080 | |||
1048 | ti->error = "Unrecognised multipath feature request"; | 1081 | ti->error = "Unrecognised multipath feature request"; |
1049 | r = -EINVAL; | 1082 | r = -EINVAL; |
1050 | } while (argc && !r); | 1083 | } while (argc && !r); |
@@ -1052,8 +1085,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) | |||
1052 | return r; | 1085 | return r; |
1053 | } | 1086 | } |
1054 | 1087 | ||
1055 | static int __multipath_ctr(struct dm_target *ti, unsigned int argc, | 1088 | static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) |
1056 | char **argv, bool bio_based) | ||
1057 | { | 1089 | { |
1058 | /* target arguments */ | 1090 | /* target arguments */ |
1059 | static struct dm_arg _args[] = { | 1091 | static struct dm_arg _args[] = { |
@@ -1066,12 +1098,11 @@ static int __multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
1066 | struct dm_arg_set as; | 1098 | struct dm_arg_set as; |
1067 | unsigned pg_count = 0; | 1099 | unsigned pg_count = 0; |
1068 | unsigned next_pg_num; | 1100 | unsigned next_pg_num; |
1069 | bool use_blk_mq = dm_use_blk_mq(dm_table_get_md(ti->table)); | ||
1070 | 1101 | ||
1071 | as.argc = argc; | 1102 | as.argc = argc; |
1072 | as.argv = argv; | 1103 | as.argv = argv; |
1073 | 1104 | ||
1074 | m = alloc_multipath(ti, use_blk_mq, bio_based); | 1105 | m = alloc_multipath(ti); |
1075 | if (!m) { | 1106 | if (!m) { |
1076 | ti->error = "can't allocate multipath"; | 1107 | ti->error = "can't allocate multipath"; |
1077 | return -EINVAL; | 1108 | return -EINVAL; |
@@ -1081,6 +1112,10 @@ static int __multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
1081 | if (r) | 1112 | if (r) |
1082 | goto bad; | 1113 | goto bad; |
1083 | 1114 | ||
1115 | r = alloc_multipath_stage2(ti, m); | ||
1116 | if (r) | ||
1117 | goto bad; | ||
1118 | |||
1084 | r = parse_hw_handler(&as, m); | 1119 | r = parse_hw_handler(&as, m); |
1085 | if (r) | 1120 | if (r) |
1086 | goto bad; | 1121 | goto bad; |
@@ -1130,9 +1165,9 @@ static int __multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
1130 | ti->num_flush_bios = 1; | 1165 | ti->num_flush_bios = 1; |
1131 | ti->num_discard_bios = 1; | 1166 | ti->num_discard_bios = 1; |
1132 | ti->num_write_same_bios = 1; | 1167 | ti->num_write_same_bios = 1; |
1133 | if (bio_based) | 1168 | if (m->queue_mode == DM_TYPE_BIO_BASED) |
1134 | ti->per_io_data_size = multipath_per_bio_data_size(); | 1169 | ti->per_io_data_size = multipath_per_bio_data_size(); |
1135 | else if (use_blk_mq) | 1170 | else if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED) |
1136 | ti->per_io_data_size = sizeof(struct dm_mpath_io); | 1171 | ti->per_io_data_size = sizeof(struct dm_mpath_io); |
1137 | 1172 | ||
1138 | return 0; | 1173 | return 0; |
@@ -1142,16 +1177,6 @@ static int __multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
1142 | return r; | 1177 | return r; |
1143 | } | 1178 | } |
1144 | 1179 | ||
1145 | static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) | ||
1146 | { | ||
1147 | return __multipath_ctr(ti, argc, argv, false); | ||
1148 | } | ||
1149 | |||
1150 | static int multipath_bio_ctr(struct dm_target *ti, unsigned argc, char **argv) | ||
1151 | { | ||
1152 | return __multipath_ctr(ti, argc, argv, true); | ||
1153 | } | ||
1154 | |||
1155 | static void multipath_wait_for_pg_init_completion(struct multipath *m) | 1180 | static void multipath_wait_for_pg_init_completion(struct multipath *m) |
1156 | { | 1181 | { |
1157 | DECLARE_WAITQUEUE(wait, current); | 1182 | DECLARE_WAITQUEUE(wait, current); |
@@ -1700,7 +1725,9 @@ static void multipath_status(struct dm_target *ti, status_type_t type, | |||
1700 | DMEMIT("%u ", test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) + | 1725 | DMEMIT("%u ", test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) + |
1701 | (m->pg_init_retries > 0) * 2 + | 1726 | (m->pg_init_retries > 0) * 2 + |
1702 | (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2 + | 1727 | (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2 + |
1703 | test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags)); | 1728 | test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags) + |
1729 | (m->queue_mode != DM_TYPE_REQUEST_BASED) * 2); | ||
1730 | |||
1704 | if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) | 1731 | if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) |
1705 | DMEMIT("queue_if_no_path "); | 1732 | DMEMIT("queue_if_no_path "); |
1706 | if (m->pg_init_retries) | 1733 | if (m->pg_init_retries) |
@@ -1709,6 +1736,16 @@ static void multipath_status(struct dm_target *ti, status_type_t type, | |||
1709 | DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs); | 1736 | DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs); |
1710 | if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags)) | 1737 | if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags)) |
1711 | DMEMIT("retain_attached_hw_handler "); | 1738 | DMEMIT("retain_attached_hw_handler "); |
1739 | if (m->queue_mode != DM_TYPE_REQUEST_BASED) { | ||
1740 | switch(m->queue_mode) { | ||
1741 | case DM_TYPE_BIO_BASED: | ||
1742 | DMEMIT("queue_mode bio "); | ||
1743 | break; | ||
1744 | case DM_TYPE_MQ_REQUEST_BASED: | ||
1745 | DMEMIT("queue_mode mq "); | ||
1746 | break; | ||
1747 | } | ||
1748 | } | ||
1712 | } | 1749 | } |
1713 | 1750 | ||
1714 | if (!m->hw_handler_name || type == STATUSTYPE_INFO) | 1751 | if (!m->hw_handler_name || type == STATUSTYPE_INFO) |
@@ -1995,7 +2032,7 @@ static int multipath_busy(struct dm_target *ti) | |||
1995 | *---------------------------------------------------------------*/ | 2032 | *---------------------------------------------------------------*/ |
1996 | static struct target_type multipath_target = { | 2033 | static struct target_type multipath_target = { |
1997 | .name = "multipath", | 2034 | .name = "multipath", |
1998 | .version = {1, 11, 0}, | 2035 | .version = {1, 12, 0}, |
1999 | .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE, | 2036 | .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE, |
2000 | .module = THIS_MODULE, | 2037 | .module = THIS_MODULE, |
2001 | .ctr = multipath_ctr, | 2038 | .ctr = multipath_ctr, |
@@ -2004,22 +2041,6 @@ static struct target_type multipath_target = { | |||
2004 | .clone_and_map_rq = multipath_clone_and_map, | 2041 | .clone_and_map_rq = multipath_clone_and_map, |
2005 | .release_clone_rq = multipath_release_clone, | 2042 | .release_clone_rq = multipath_release_clone, |
2006 | .rq_end_io = multipath_end_io, | 2043 | .rq_end_io = multipath_end_io, |
2007 | .presuspend = multipath_presuspend, | ||
2008 | .postsuspend = multipath_postsuspend, | ||
2009 | .resume = multipath_resume, | ||
2010 | .status = multipath_status, | ||
2011 | .message = multipath_message, | ||
2012 | .prepare_ioctl = multipath_prepare_ioctl, | ||
2013 | .iterate_devices = multipath_iterate_devices, | ||
2014 | .busy = multipath_busy, | ||
2015 | }; | ||
2016 | |||
2017 | static struct target_type multipath_bio_target = { | ||
2018 | .name = "multipath-bio", | ||
2019 | .version = {1, 0, 0}, | ||
2020 | .module = THIS_MODULE, | ||
2021 | .ctr = multipath_bio_ctr, | ||
2022 | .dtr = multipath_dtr, | ||
2023 | .map = multipath_map_bio, | 2044 | .map = multipath_map_bio, |
2024 | .end_io = multipath_end_io_bio, | 2045 | .end_io = multipath_end_io_bio, |
2025 | .presuspend = multipath_presuspend, | 2046 | .presuspend = multipath_presuspend, |
@@ -2048,13 +2069,6 @@ static int __init dm_multipath_init(void) | |||
2048 | goto bad_register_target; | 2069 | goto bad_register_target; |
2049 | } | 2070 | } |
2050 | 2071 | ||
2051 | r = dm_register_target(&multipath_bio_target); | ||
2052 | if (r < 0) { | ||
2053 | DMERR("bio-based register failed %d", r); | ||
2054 | r = -EINVAL; | ||
2055 | goto bad_register_bio_based_target; | ||
2056 | } | ||
2057 | |||
2058 | kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0); | 2072 | kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0); |
2059 | if (!kmultipathd) { | 2073 | if (!kmultipathd) { |
2060 | DMERR("failed to create workqueue kmpathd"); | 2074 | DMERR("failed to create workqueue kmpathd"); |
@@ -2081,8 +2095,6 @@ static int __init dm_multipath_init(void) | |||
2081 | bad_alloc_kmpath_handlerd: | 2095 | bad_alloc_kmpath_handlerd: |
2082 | destroy_workqueue(kmultipathd); | 2096 | destroy_workqueue(kmultipathd); |
2083 | bad_alloc_kmultipathd: | 2097 | bad_alloc_kmultipathd: |
2084 | dm_unregister_target(&multipath_bio_target); | ||
2085 | bad_register_bio_based_target: | ||
2086 | dm_unregister_target(&multipath_target); | 2098 | dm_unregister_target(&multipath_target); |
2087 | bad_register_target: | 2099 | bad_register_target: |
2088 | kmem_cache_destroy(_mpio_cache); | 2100 | kmem_cache_destroy(_mpio_cache); |
@@ -2096,7 +2108,6 @@ static void __exit dm_multipath_exit(void) | |||
2096 | destroy_workqueue(kmultipathd); | 2108 | destroy_workqueue(kmultipathd); |
2097 | 2109 | ||
2098 | dm_unregister_target(&multipath_target); | 2110 | dm_unregister_target(&multipath_target); |
2099 | dm_unregister_target(&multipath_bio_target); | ||
2100 | kmem_cache_destroy(_mpio_cache); | 2111 | kmem_cache_destroy(_mpio_cache); |
2101 | } | 2112 | } |
2102 | 2113 | ||
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index 787c81b16a26..266f7b674108 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c | |||
@@ -230,7 +230,14 @@ static void free_rq_clone(struct request *clone) | |||
230 | 230 | ||
231 | blk_rq_unprep_clone(clone); | 231 | blk_rq_unprep_clone(clone); |
232 | 232 | ||
233 | if (md->type == DM_TYPE_MQ_REQUEST_BASED) | 233 | /* |
234 | * It is possible for a clone_old_rq() allocated clone to | ||
235 | * get passed in -- it may not yet have a request_queue. | ||
236 | * This is known to occur if the error target replaces | ||
237 | * a multipath target that has a request_fn queue stacked | ||
238 | * on blk-mq queue(s). | ||
239 | */ | ||
240 | if (clone->q && clone->q->mq_ops) | ||
234 | /* stacked on blk-mq queue(s) */ | 241 | /* stacked on blk-mq queue(s) */ |
235 | tio->ti->type->release_clone_rq(clone); | 242 | tio->ti->type->release_clone_rq(clone); |
236 | else if (!md->queue->mq_ops) | 243 | else if (!md->queue->mq_ops) |
@@ -561,7 +568,7 @@ static struct dm_rq_target_io *dm_old_prep_tio(struct request *rq, | |||
561 | * Must clone a request if this .request_fn DM device | 568 | * Must clone a request if this .request_fn DM device |
562 | * is stacked on .request_fn device(s). | 569 | * is stacked on .request_fn device(s). |
563 | */ | 570 | */ |
564 | if (!dm_table_mq_request_based(table)) { | 571 | if (!dm_table_all_blk_mq_devices(table)) { |
565 | if (!clone_old_rq(rq, md, tio, gfp_mask)) { | 572 | if (!clone_old_rq(rq, md, tio, gfp_mask)) { |
566 | dm_put_live_table(md, srcu_idx); | 573 | dm_put_live_table(md, srcu_idx); |
567 | free_old_rq_tio(tio); | 574 | free_old_rq_tio(tio); |
@@ -711,7 +718,7 @@ ssize_t dm_attr_rq_based_seq_io_merge_deadline_store(struct mapped_device *md, | |||
711 | { | 718 | { |
712 | unsigned deadline; | 719 | unsigned deadline; |
713 | 720 | ||
714 | if (!dm_request_based(md) || md->use_blk_mq) | 721 | if (dm_get_md_type(md) != DM_TYPE_REQUEST_BASED) |
715 | return count; | 722 | return count; |
716 | 723 | ||
717 | if (kstrtouint(buf, 10, &deadline)) | 724 | if (kstrtouint(buf, 10, &deadline)) |
@@ -886,12 +893,13 @@ static struct blk_mq_ops dm_mq_ops = { | |||
886 | .init_request = dm_mq_init_request, | 893 | .init_request = dm_mq_init_request, |
887 | }; | 894 | }; |
888 | 895 | ||
889 | int dm_mq_init_request_queue(struct mapped_device *md, struct dm_target *immutable_tgt) | 896 | int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t) |
890 | { | 897 | { |
891 | struct request_queue *q; | 898 | struct request_queue *q; |
899 | struct dm_target *immutable_tgt; | ||
892 | int err; | 900 | int err; |
893 | 901 | ||
894 | if (dm_get_md_type(md) == DM_TYPE_REQUEST_BASED) { | 902 | if (!dm_table_all_blk_mq_devices(t)) { |
895 | DMERR("request-based dm-mq may only be stacked on blk-mq device(s)"); | 903 | DMERR("request-based dm-mq may only be stacked on blk-mq device(s)"); |
896 | return -EINVAL; | 904 | return -EINVAL; |
897 | } | 905 | } |
@@ -908,6 +916,7 @@ int dm_mq_init_request_queue(struct mapped_device *md, struct dm_target *immutab | |||
908 | md->tag_set->driver_data = md; | 916 | md->tag_set->driver_data = md; |
909 | 917 | ||
910 | md->tag_set->cmd_size = sizeof(struct dm_rq_target_io); | 918 | md->tag_set->cmd_size = sizeof(struct dm_rq_target_io); |
919 | immutable_tgt = dm_table_get_immutable_target(t); | ||
911 | if (immutable_tgt && immutable_tgt->per_io_data_size) { | 920 | if (immutable_tgt && immutable_tgt->per_io_data_size) { |
912 | /* any target-specific per-io data is immediately after the tio */ | 921 | /* any target-specific per-io data is immediately after the tio */ |
913 | md->tag_set->cmd_size += immutable_tgt->per_io_data_size; | 922 | md->tag_set->cmd_size += immutable_tgt->per_io_data_size; |
diff --git a/drivers/md/dm-rq.h b/drivers/md/dm-rq.h index 1559f6486024..9e6f0a3773d4 100644 --- a/drivers/md/dm-rq.h +++ b/drivers/md/dm-rq.h | |||
@@ -49,7 +49,7 @@ bool dm_use_blk_mq_default(void); | |||
49 | bool dm_use_blk_mq(struct mapped_device *md); | 49 | bool dm_use_blk_mq(struct mapped_device *md); |
50 | 50 | ||
51 | int dm_old_init_request_queue(struct mapped_device *md); | 51 | int dm_old_init_request_queue(struct mapped_device *md); |
52 | int dm_mq_init_request_queue(struct mapped_device *md, struct dm_target *immutable_tgt); | 52 | int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t); |
53 | void dm_mq_cleanup_mapped_device(struct mapped_device *md); | 53 | void dm_mq_cleanup_mapped_device(struct mapped_device *md); |
54 | 54 | ||
55 | void dm_start_queue(struct request_queue *q); | 55 | void dm_start_queue(struct request_queue *q); |
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index a682d51111dd..88f01744ac16 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -43,8 +43,10 @@ struct dm_table { | |||
43 | struct dm_target *targets; | 43 | struct dm_target *targets; |
44 | 44 | ||
45 | struct target_type *immutable_target_type; | 45 | struct target_type *immutable_target_type; |
46 | unsigned integrity_supported:1; | 46 | |
47 | unsigned singleton:1; | 47 | bool integrity_supported:1; |
48 | bool singleton:1; | ||
49 | bool all_blk_mq:1; | ||
48 | 50 | ||
49 | /* | 51 | /* |
50 | * Indicates the rw permissions for the new logical | 52 | * Indicates the rw permissions for the new logical |
@@ -206,6 +208,7 @@ int dm_table_create(struct dm_table **result, fmode_t mode, | |||
206 | return -ENOMEM; | 208 | return -ENOMEM; |
207 | } | 209 | } |
208 | 210 | ||
211 | t->type = DM_TYPE_NONE; | ||
209 | t->mode = mode; | 212 | t->mode = mode; |
210 | t->md = md; | 213 | t->md = md; |
211 | *result = t; | 214 | *result = t; |
@@ -703,7 +706,7 @@ int dm_table_add_target(struct dm_table *t, const char *type, | |||
703 | dm_device_name(t->md), type); | 706 | dm_device_name(t->md), type); |
704 | return -EINVAL; | 707 | return -EINVAL; |
705 | } | 708 | } |
706 | t->singleton = 1; | 709 | t->singleton = true; |
707 | } | 710 | } |
708 | 711 | ||
709 | if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) { | 712 | if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) { |
@@ -830,16 +833,29 @@ static bool __table_type_request_based(unsigned table_type) | |||
830 | table_type == DM_TYPE_MQ_REQUEST_BASED); | 833 | table_type == DM_TYPE_MQ_REQUEST_BASED); |
831 | } | 834 | } |
832 | 835 | ||
833 | static int dm_table_set_type(struct dm_table *t) | 836 | void dm_table_set_type(struct dm_table *t, unsigned type) |
837 | { | ||
838 | t->type = type; | ||
839 | } | ||
840 | EXPORT_SYMBOL_GPL(dm_table_set_type); | ||
841 | |||
842 | static int dm_table_determine_type(struct dm_table *t) | ||
834 | { | 843 | { |
835 | unsigned i; | 844 | unsigned i; |
836 | unsigned bio_based = 0, request_based = 0, hybrid = 0; | 845 | unsigned bio_based = 0, request_based = 0, hybrid = 0; |
837 | bool use_blk_mq = false; | 846 | bool verify_blk_mq = false; |
838 | struct dm_target *tgt; | 847 | struct dm_target *tgt; |
839 | struct dm_dev_internal *dd; | 848 | struct dm_dev_internal *dd; |
840 | struct list_head *devices; | 849 | struct list_head *devices = dm_table_get_devices(t); |
841 | unsigned live_md_type = dm_get_md_type(t->md); | 850 | unsigned live_md_type = dm_get_md_type(t->md); |
842 | 851 | ||
852 | if (t->type != DM_TYPE_NONE) { | ||
853 | /* target already set the table's type */ | ||
854 | if (t->type == DM_TYPE_BIO_BASED) | ||
855 | return 0; | ||
856 | goto verify_rq_based; | ||
857 | } | ||
858 | |||
843 | for (i = 0; i < t->num_targets; i++) { | 859 | for (i = 0; i < t->num_targets; i++) { |
844 | tgt = t->targets + i; | 860 | tgt = t->targets + i; |
845 | if (dm_target_hybrid(tgt)) | 861 | if (dm_target_hybrid(tgt)) |
@@ -876,6 +892,19 @@ static int dm_table_set_type(struct dm_table *t) | |||
876 | 892 | ||
877 | BUG_ON(!request_based); /* No targets in this table */ | 893 | BUG_ON(!request_based); /* No targets in this table */ |
878 | 894 | ||
895 | if (list_empty(devices) && __table_type_request_based(live_md_type)) { | ||
896 | /* inherit live MD type */ | ||
897 | t->type = live_md_type; | ||
898 | return 0; | ||
899 | } | ||
900 | |||
901 | /* | ||
902 | * The only way to establish DM_TYPE_MQ_REQUEST_BASED is by | ||
903 | * having a compatible target use dm_table_set_type. | ||
904 | */ | ||
905 | t->type = DM_TYPE_REQUEST_BASED; | ||
906 | |||
907 | verify_rq_based: | ||
879 | /* | 908 | /* |
880 | * Request-based dm supports only tables that have a single target now. | 909 | * Request-based dm supports only tables that have a single target now. |
881 | * To support multiple targets, request splitting support is needed, | 910 | * To support multiple targets, request splitting support is needed, |
@@ -888,7 +917,6 @@ static int dm_table_set_type(struct dm_table *t) | |||
888 | } | 917 | } |
889 | 918 | ||
890 | /* Non-request-stackable devices can't be used for request-based dm */ | 919 | /* Non-request-stackable devices can't be used for request-based dm */ |
891 | devices = dm_table_get_devices(t); | ||
892 | list_for_each_entry(dd, devices, list) { | 920 | list_for_each_entry(dd, devices, list) { |
893 | struct request_queue *q = bdev_get_queue(dd->dm_dev->bdev); | 921 | struct request_queue *q = bdev_get_queue(dd->dm_dev->bdev); |
894 | 922 | ||
@@ -899,10 +927,10 @@ static int dm_table_set_type(struct dm_table *t) | |||
899 | } | 927 | } |
900 | 928 | ||
901 | if (q->mq_ops) | 929 | if (q->mq_ops) |
902 | use_blk_mq = true; | 930 | verify_blk_mq = true; |
903 | } | 931 | } |
904 | 932 | ||
905 | if (use_blk_mq) { | 933 | if (verify_blk_mq) { |
906 | /* verify _all_ devices in the table are blk-mq devices */ | 934 | /* verify _all_ devices in the table are blk-mq devices */ |
907 | list_for_each_entry(dd, devices, list) | 935 | list_for_each_entry(dd, devices, list) |
908 | if (!bdev_get_queue(dd->dm_dev->bdev)->mq_ops) { | 936 | if (!bdev_get_queue(dd->dm_dev->bdev)->mq_ops) { |
@@ -910,14 +938,9 @@ static int dm_table_set_type(struct dm_table *t) | |||
910 | " are blk-mq request-stackable"); | 938 | " are blk-mq request-stackable"); |
911 | return -EINVAL; | 939 | return -EINVAL; |
912 | } | 940 | } |
913 | t->type = DM_TYPE_MQ_REQUEST_BASED; | ||
914 | 941 | ||
915 | } else if (list_empty(devices) && __table_type_request_based(live_md_type)) { | 942 | t->all_blk_mq = true; |
916 | /* inherit live MD type */ | 943 | } |
917 | t->type = live_md_type; | ||
918 | |||
919 | } else | ||
920 | t->type = DM_TYPE_REQUEST_BASED; | ||
921 | 944 | ||
922 | return 0; | 945 | return 0; |
923 | } | 946 | } |
@@ -961,9 +984,9 @@ bool dm_table_request_based(struct dm_table *t) | |||
961 | return __table_type_request_based(dm_table_get_type(t)); | 984 | return __table_type_request_based(dm_table_get_type(t)); |
962 | } | 985 | } |
963 | 986 | ||
964 | bool dm_table_mq_request_based(struct dm_table *t) | 987 | bool dm_table_all_blk_mq_devices(struct dm_table *t) |
965 | { | 988 | { |
966 | return dm_table_get_type(t) == DM_TYPE_MQ_REQUEST_BASED; | 989 | return t->all_blk_mq; |
967 | } | 990 | } |
968 | 991 | ||
969 | static int dm_table_alloc_md_mempools(struct dm_table *t, struct mapped_device *md) | 992 | static int dm_table_alloc_md_mempools(struct dm_table *t, struct mapped_device *md) |
@@ -1106,7 +1129,7 @@ static int dm_table_register_integrity(struct dm_table *t) | |||
1106 | return 0; | 1129 | return 0; |
1107 | 1130 | ||
1108 | if (!integrity_profile_exists(dm_disk(md))) { | 1131 | if (!integrity_profile_exists(dm_disk(md))) { |
1109 | t->integrity_supported = 1; | 1132 | t->integrity_supported = true; |
1110 | /* | 1133 | /* |
1111 | * Register integrity profile during table load; we can do | 1134 | * Register integrity profile during table load; we can do |
1112 | * this because the final profile must match during resume. | 1135 | * this because the final profile must match during resume. |
@@ -1129,7 +1152,7 @@ static int dm_table_register_integrity(struct dm_table *t) | |||
1129 | } | 1152 | } |
1130 | 1153 | ||
1131 | /* Preserve existing integrity profile */ | 1154 | /* Preserve existing integrity profile */ |
1132 | t->integrity_supported = 1; | 1155 | t->integrity_supported = true; |
1133 | return 0; | 1156 | return 0; |
1134 | } | 1157 | } |
1135 | 1158 | ||
@@ -1141,9 +1164,9 @@ int dm_table_complete(struct dm_table *t) | |||
1141 | { | 1164 | { |
1142 | int r; | 1165 | int r; |
1143 | 1166 | ||
1144 | r = dm_table_set_type(t); | 1167 | r = dm_table_determine_type(t); |
1145 | if (r) { | 1168 | if (r) { |
1146 | DMERR("unable to set table type"); | 1169 | DMERR("unable to determine table type"); |
1147 | return r; | 1170 | return r; |
1148 | } | 1171 | } |
1149 | 1172 | ||
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 8f22527134e9..2c907bc10fe9 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -1738,23 +1738,14 @@ struct queue_limits *dm_get_queue_limits(struct mapped_device *md) | |||
1738 | } | 1738 | } |
1739 | EXPORT_SYMBOL_GPL(dm_get_queue_limits); | 1739 | EXPORT_SYMBOL_GPL(dm_get_queue_limits); |
1740 | 1740 | ||
1741 | static unsigned filter_md_type(unsigned type, struct mapped_device *md) | ||
1742 | { | ||
1743 | if (type == DM_TYPE_BIO_BASED) | ||
1744 | return type; | ||
1745 | |||
1746 | return !md->use_blk_mq ? DM_TYPE_REQUEST_BASED : DM_TYPE_MQ_REQUEST_BASED; | ||
1747 | } | ||
1748 | |||
1749 | /* | 1741 | /* |
1750 | * Setup the DM device's queue based on md's type | 1742 | * Setup the DM device's queue based on md's type |
1751 | */ | 1743 | */ |
1752 | int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t) | 1744 | int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t) |
1753 | { | 1745 | { |
1754 | int r; | 1746 | int r; |
1755 | unsigned md_type = filter_md_type(dm_get_md_type(md), md); | ||
1756 | 1747 | ||
1757 | switch (md_type) { | 1748 | switch (dm_get_md_type(md)) { |
1758 | case DM_TYPE_REQUEST_BASED: | 1749 | case DM_TYPE_REQUEST_BASED: |
1759 | r = dm_old_init_request_queue(md); | 1750 | r = dm_old_init_request_queue(md); |
1760 | if (r) { | 1751 | if (r) { |
@@ -1763,7 +1754,7 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t) | |||
1763 | } | 1754 | } |
1764 | break; | 1755 | break; |
1765 | case DM_TYPE_MQ_REQUEST_BASED: | 1756 | case DM_TYPE_MQ_REQUEST_BASED: |
1766 | r = dm_mq_init_request_queue(md, dm_table_get_immutable_target(t)); | 1757 | r = dm_mq_init_request_queue(md, t); |
1767 | if (r) { | 1758 | if (r) { |
1768 | DMERR("Cannot initialize queue for request-based dm-mq mapped device"); | 1759 | DMERR("Cannot initialize queue for request-based dm-mq mapped device"); |
1769 | return r; | 1760 | return r; |
@@ -2472,8 +2463,6 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned t | |||
2472 | if (!pools) | 2463 | if (!pools) |
2473 | return NULL; | 2464 | return NULL; |
2474 | 2465 | ||
2475 | type = filter_md_type(type, md); | ||
2476 | |||
2477 | switch (type) { | 2466 | switch (type) { |
2478 | case DM_TYPE_BIO_BASED: | 2467 | case DM_TYPE_BIO_BASED: |
2479 | cachep = _io_cache; | 2468 | cachep = _io_cache; |
diff --git a/drivers/md/dm.h b/drivers/md/dm.h index b611b3064a7c..2e0e4a53a312 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h | |||
@@ -34,14 +34,6 @@ | |||
34 | #define DM_STATUS_NOFLUSH_FLAG (1 << 0) | 34 | #define DM_STATUS_NOFLUSH_FLAG (1 << 0) |
35 | 35 | ||
36 | /* | 36 | /* |
37 | * Type of table and mapped_device's mempool | ||
38 | */ | ||
39 | #define DM_TYPE_NONE 0 | ||
40 | #define DM_TYPE_BIO_BASED 1 | ||
41 | #define DM_TYPE_REQUEST_BASED 2 | ||
42 | #define DM_TYPE_MQ_REQUEST_BASED 3 | ||
43 | |||
44 | /* | ||
45 | * List of devices that a metadevice uses and should open/close. | 37 | * List of devices that a metadevice uses and should open/close. |
46 | */ | 38 | */ |
47 | struct dm_dev_internal { | 39 | struct dm_dev_internal { |
@@ -77,7 +69,7 @@ struct target_type *dm_table_get_immutable_target_type(struct dm_table *t); | |||
77 | struct dm_target *dm_table_get_immutable_target(struct dm_table *t); | 69 | struct dm_target *dm_table_get_immutable_target(struct dm_table *t); |
78 | struct dm_target *dm_table_get_wildcard_target(struct dm_table *t); | 70 | struct dm_target *dm_table_get_wildcard_target(struct dm_table *t); |
79 | bool dm_table_request_based(struct dm_table *t); | 71 | bool dm_table_request_based(struct dm_table *t); |
80 | bool dm_table_mq_request_based(struct dm_table *t); | 72 | bool dm_table_all_blk_mq_devices(struct dm_table *t); |
81 | void dm_table_free_md_mempools(struct dm_table *t); | 73 | void dm_table_free_md_mempools(struct dm_table *t); |
82 | struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); | 74 | struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); |
83 | 75 | ||
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 0830c9e86f0d..2ce339212b6e 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h | |||
@@ -19,6 +19,14 @@ struct dm_table; | |||
19 | struct mapped_device; | 19 | struct mapped_device; |
20 | struct bio_vec; | 20 | struct bio_vec; |
21 | 21 | ||
22 | /* | ||
23 | * Type of table, mapped_device's mempool and request_queue | ||
24 | */ | ||
25 | #define DM_TYPE_NONE 0 | ||
26 | #define DM_TYPE_BIO_BASED 1 | ||
27 | #define DM_TYPE_REQUEST_BASED 2 | ||
28 | #define DM_TYPE_MQ_REQUEST_BASED 3 | ||
29 | |||
22 | typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t; | 30 | typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t; |
23 | 31 | ||
24 | union map_info { | 32 | union map_info { |
@@ -444,6 +452,14 @@ int dm_table_add_target(struct dm_table *t, const char *type, | |||
444 | void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callbacks *cb); | 452 | void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callbacks *cb); |
445 | 453 | ||
446 | /* | 454 | /* |
455 | * Target can use this to set the table's type. | ||
456 | * Can only ever be called from a target's ctr. | ||
457 | * Useful for "hybrid" target (supports both bio-based | ||
458 | * and request-based). | ||
459 | */ | ||
460 | void dm_table_set_type(struct dm_table *t, unsigned type); | ||
461 | |||
462 | /* | ||
447 | * Finally call this to make the table ready for use. | 463 | * Finally call this to make the table ready for use. |
448 | */ | 464 | */ |
449 | int dm_table_complete(struct dm_table *t); | 465 | int dm_table_complete(struct dm_table *t); |