@@ -963,9 +963,6 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
if (old) {
old_registered = old->registered;
- if (old->uses_mq)
- blk_mq_sched_teardown(q);
-
if (!q->mq_ops)
blk_queue_bypass_start(q);
@@ -981,7 +978,14 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
/* allocate, init and register new elevator */
if (new_e) {
if (new_e->uses_mq) {
- err = blk_mq_sched_setup(q);
+ /*
+ * If we were previously using an I/O scheduler, the
+ * sched_tags are already allocated.
+ */
+ if (old)
+ err = 0;
+ else
+ err = blk_mq_sched_setup(q);
if (!err)
err = new_e->ops.mq.init_sched(q, new_e);
} else
@@ -997,6 +1001,12 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
/* done, kill the old one and finish */
if (old) {
+ /*
+ * If we switched to another I/O scheduler, then we shouldn't
+ * free sched_tags.
+ */
+ if (old->uses_mq && !new_e)
+ blk_mq_sched_teardown(q);
elevator_exit(old);
if (!q->mq_ops)
blk_queue_bypass_end(q);
@@ -1015,7 +1025,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
return 0;
fail_register:
- if (q->mq_ops)
+ if (q->mq_ops && !old)
blk_mq_sched_teardown(q);
elevator_exit(q->elevator);
fail_init: