]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - block/blk-mq.c
blk-mq: fixup "Convert to new hotplug state machine"
[karo-tx-linux.git] / block / blk-mq.c
index e931a0e8e73dfb23761a0fa2f2819e43207dc07c..8c0f80198e5296e4fde65eec78ec271d93336372 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/sched/sysctl.h>
 #include <linux/delay.h>
 #include <linux/crash_dump.h>
+#include <linux/prefetch.h>
 
 #include <trace/events/block.h>
 
@@ -40,42 +41,23 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx);
  */
 static bool blk_mq_hctx_has_pending(struct blk_mq_hw_ctx *hctx)
 {
-       unsigned int i;
-
-       for (i = 0; i < hctx->ctx_map.size; i++)
-               if (hctx->ctx_map.map[i].word)
-                       return true;
-
-       return false;
+       return sbitmap_any_bit_set(&hctx->ctx_map);
 }
 
-static inline struct blk_align_bitmap *get_bm(struct blk_mq_hw_ctx *hctx,
-                                             struct blk_mq_ctx *ctx)
-{
-       return &hctx->ctx_map.map[ctx->index_hw / hctx->ctx_map.bits_per_word];
-}
-
-#define CTX_TO_BIT(hctx, ctx)  \
-       ((ctx)->index_hw & ((hctx)->ctx_map.bits_per_word - 1))
-
 /*
  * Mark this ctx as having pending work in this hardware queue
  */
 static void blk_mq_hctx_mark_pending(struct blk_mq_hw_ctx *hctx,
                                     struct blk_mq_ctx *ctx)
 {
-       struct blk_align_bitmap *bm = get_bm(hctx, ctx);
-
-       if (!test_bit(CTX_TO_BIT(hctx, ctx), &bm->word))
-               set_bit(CTX_TO_BIT(hctx, ctx), &bm->word);
+       if (!sbitmap_test_bit(&hctx->ctx_map, ctx->index_hw))
+               sbitmap_set_bit(&hctx->ctx_map, ctx->index_hw);
 }
 
 static void blk_mq_hctx_clear_pending(struct blk_mq_hw_ctx *hctx,
                                      struct blk_mq_ctx *ctx)
 {
-       struct blk_align_bitmap *bm = get_bm(hctx, ctx);
-
-       clear_bit(CTX_TO_BIT(hctx, ctx), &bm->word);
+       sbitmap_clear_bit(&hctx->ctx_map, ctx->index_hw);
 }
 
 void blk_mq_freeze_queue_start(struct request_queue *q)
@@ -321,7 +303,7 @@ static void __blk_mq_free_request(struct blk_mq_hw_ctx *hctx,
        rq->cmd_flags = 0;
 
        clear_bit(REQ_ATOM_STARTED, &rq->atomic_flags);
-       blk_mq_put_tag(hctx, tag, &ctx->last_tag);
+       blk_mq_put_tag(hctx, ctx, tag);
        blk_queue_exit(q);
 }
 
@@ -501,7 +483,7 @@ EXPORT_SYMBOL(blk_mq_requeue_request);
 static void blk_mq_requeue_work(struct work_struct *work)
 {
        struct request_queue *q =
-               container_of(work, struct request_queue, requeue_work);
+               container_of(work, struct request_queue, requeue_work.work);
        LIST_HEAD(rq_list);
        struct request *rq, *next;
        unsigned long flags;
@@ -556,16 +538,24 @@ EXPORT_SYMBOL(blk_mq_add_to_requeue_list);
 
 void blk_mq_cancel_requeue_work(struct request_queue *q)
 {
-       cancel_work_sync(&q->requeue_work);
+       cancel_delayed_work_sync(&q->requeue_work);
 }
 EXPORT_SYMBOL_GPL(blk_mq_cancel_requeue_work);
 
 void blk_mq_kick_requeue_list(struct request_queue *q)
 {
-       kblockd_schedule_work(&q->requeue_work);
+       kblockd_schedule_delayed_work(&q->requeue_work, 0);
 }
 EXPORT_SYMBOL(blk_mq_kick_requeue_list);
 
+void blk_mq_delay_kick_requeue_list(struct request_queue *q,
+                                   unsigned long msecs)
+{
+       kblockd_schedule_delayed_work(&q->requeue_work,
+                                     msecs_to_jiffies(msecs));
+}
+EXPORT_SYMBOL(blk_mq_delay_kick_requeue_list);
+
 void blk_mq_abort_requeue_list(struct request_queue *q)
 {
        unsigned long flags;
@@ -588,8 +578,10 @@ EXPORT_SYMBOL(blk_mq_abort_requeue_list);
 
 struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag)
 {
-       if (tag < tags->nr_tags)
+       if (tag < tags->nr_tags) {
+               prefetch(tags->rqs[tag]);
                return tags->rqs[tag];
+       }
 
        return NULL;
 }
@@ -744,38 +736,44 @@ static bool blk_mq_attempt_merge(struct request_queue *q,
        return false;
 }
 
+struct flush_busy_ctx_data {
+       struct blk_mq_hw_ctx *hctx;
+       struct list_head *list;
+};
+
+static bool flush_busy_ctx(struct sbitmap *sb, unsigned int bitnr, void *data)
+{
+       struct flush_busy_ctx_data *flush_data = data;
+       struct blk_mq_hw_ctx *hctx = flush_data->hctx;
+       struct blk_mq_ctx *ctx = hctx->ctxs[bitnr];
+
+       sbitmap_clear_bit(sb, bitnr);
+       spin_lock(&ctx->lock);
+       list_splice_tail_init(&ctx->rq_list, flush_data->list);
+       spin_unlock(&ctx->lock);
+       return true;
+}
+
 /*
  * Process software queues that have been marked busy, splicing them
  * to the for-dispatch
  */
 static void flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list)
 {
-       struct blk_mq_ctx *ctx;
-       int i;
-
-       for (i = 0; i < hctx->ctx_map.size; i++) {
-               struct blk_align_bitmap *bm = &hctx->ctx_map.map[i];
-               unsigned int off, bit;
-
-               if (!bm->word)
-                       continue;
+       struct flush_busy_ctx_data data = {
+               .hctx = hctx,
+               .list = list,
+       };
 
-               bit = 0;
-               off = i * hctx->ctx_map.bits_per_word;
-               do {
-                       bit = find_next_bit(&bm->word, bm->depth, bit);
-                       if (bit >= bm->depth)
-                               break;
+       sbitmap_for_each_set(&hctx->ctx_map, flush_busy_ctx, &data);
+}
 
-                       ctx = hctx->ctxs[bit + off];
-                       clear_bit(bit, &bm->word);
-                       spin_lock(&ctx->lock);
-                       list_splice_tail_init(&ctx->rq_list, list);
-                       spin_unlock(&ctx->lock);
+static inline unsigned int queued_to_index(unsigned int queued)
+{
+       if (!queued)
+               return 0;
 
-                       bit++;
-               } while (1);
-       }
+       return min(BLK_MQ_MAX_DISPATCH_ORDER - 1, ilog2(queued) + 1);
 }
 
 /*
@@ -793,11 +791,12 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
        struct list_head *dptr;
        int queued;
 
-       WARN_ON(!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask));
-
        if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
                return;
 
+       WARN_ON(!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask) &&
+               cpu_online(hctx->next_cpu));
+
        hctx->run++;
 
        /*
@@ -865,10 +864,7 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
                        dptr = &driver_list;
        }
 
-       if (!queued)
-               hctx->dispatched[0]++;
-       else if (queued < (1 << (BLK_MQ_MAX_DISPATCH_ORDER - 1)))
-               hctx->dispatched[ilog2(queued) + 1]++;
+       hctx->dispatched[queued_to_index(queued)]++;
 
        /*
         * Any items that need requeuing? Stuff them into hctx->dispatch,
@@ -935,8 +931,7 @@ void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
                put_cpu();
        }
 
-       kblockd_schedule_delayed_work_on(blk_mq_hctx_next_cpu(hctx),
-                       &hctx->run_work, 0);
+       kblockd_schedule_work_on(blk_mq_hctx_next_cpu(hctx), &hctx->run_work);
 }
 
 void blk_mq_run_hw_queues(struct request_queue *q, bool async)
@@ -957,7 +952,7 @@ EXPORT_SYMBOL(blk_mq_run_hw_queues);
 
 void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx)
 {
-       cancel_delayed_work(&hctx->run_work);
+       cancel_work(&hctx->run_work);
        cancel_delayed_work(&hctx->delay_work);
        set_bit(BLK_MQ_S_STOPPED, &hctx->state);
 }
@@ -1010,7 +1005,7 @@ static void blk_mq_run_work_fn(struct work_struct *work)
 {
        struct blk_mq_hw_ctx *hctx;
 
-       hctx = container_of(work, struct blk_mq_hw_ctx, run_work.work);
+       hctx = container_of(work, struct blk_mq_hw_ctx, run_work);
 
        __blk_mq_run_hw_queue(hctx);
 }
@@ -1036,10 +1031,11 @@ void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs)
 EXPORT_SYMBOL(blk_mq_delay_queue);
 
 static inline void __blk_mq_insert_req_list(struct blk_mq_hw_ctx *hctx,
-                                           struct blk_mq_ctx *ctx,
                                            struct request *rq,
                                            bool at_head)
 {
+       struct blk_mq_ctx *ctx = rq->mq_ctx;
+
        trace_block_rq_insert(hctx->queue, rq);
 
        if (at_head)
@@ -1053,20 +1049,16 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
 {
        struct blk_mq_ctx *ctx = rq->mq_ctx;
 
-       __blk_mq_insert_req_list(hctx, ctx, rq, at_head);
+       __blk_mq_insert_req_list(hctx, rq, at_head);
        blk_mq_hctx_mark_pending(hctx, ctx);
 }
 
 void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
-               bool async)
+                          bool async)
 {
+       struct blk_mq_ctx *ctx = rq->mq_ctx;
        struct request_queue *q = rq->q;
        struct blk_mq_hw_ctx *hctx;
-       struct blk_mq_ctx *ctx = rq->mq_ctx, *current_ctx;
-
-       current_ctx = blk_mq_get_ctx(q);
-       if (!cpu_online(ctx->cpu))
-               rq->mq_ctx = ctx = current_ctx;
 
        hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
@@ -1076,8 +1068,6 @@ void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
 
        if (run_queue)
                blk_mq_run_hw_queue(hctx, async);
-
-       blk_mq_put_ctx(current_ctx);
 }
 
 static void blk_mq_insert_requests(struct request_queue *q,
@@ -1088,14 +1078,9 @@ static void blk_mq_insert_requests(struct request_queue *q,
 
 {
        struct blk_mq_hw_ctx *hctx;
-       struct blk_mq_ctx *current_ctx;
 
        trace_block_unplug(q, depth, !from_schedule);
 
-       current_ctx = blk_mq_get_ctx(q);
-
-       if (!cpu_online(ctx->cpu))
-               ctx = current_ctx;
        hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
        /*
@@ -1107,15 +1092,14 @@ static void blk_mq_insert_requests(struct request_queue *q,
                struct request *rq;
 
                rq = list_first_entry(list, struct request, queuelist);
+               BUG_ON(rq->mq_ctx != ctx);
                list_del_init(&rq->queuelist);
-               rq->mq_ctx = ctx;
-               __blk_mq_insert_req_list(hctx, ctx, rq, false);
+               __blk_mq_insert_req_list(hctx, rq, false);
        }
        blk_mq_hctx_mark_pending(hctx, ctx);
        spin_unlock(&ctx->lock);
 
        blk_mq_run_hw_queue(hctx, from_schedule);
-       blk_mq_put_ctx(current_ctx);
 }
 
 static int plug_ctx_cmp(void *priv, struct list_head *a, struct list_head *b)
@@ -1604,42 +1588,19 @@ fail:
        return NULL;
 }
 
-static void blk_mq_free_bitmap(struct blk_mq_ctxmap *bitmap)
-{
-       kfree(bitmap->map);
-}
-
-static int blk_mq_alloc_bitmap(struct blk_mq_ctxmap *bitmap, int node)
-{
-       unsigned int bpw = 8, total, num_maps, i;
-
-       bitmap->bits_per_word = bpw;
-
-       num_maps = ALIGN(nr_cpu_ids, bpw) / bpw;
-       bitmap->map = kzalloc_node(num_maps * sizeof(struct blk_align_bitmap),
-                                       GFP_KERNEL, node);
-       if (!bitmap->map)
-               return -ENOMEM;
-
-       total = nr_cpu_ids;
-       for (i = 0; i < num_maps; i++) {
-               bitmap->map[i].depth = min(total, bitmap->bits_per_word);
-               total -= bitmap->map[i].depth;
-       }
-
-       return 0;
-}
-
-static int blk_mq_hctx_cpu_offline(struct blk_mq_hw_ctx *hctx, int cpu)
+/*
+ * 'cpu' is going away. splice any existing rq_list entries from this
+ * software queue to the hw queue dispatch list, and ensure that it
+ * gets run.
+ */
+static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node)
 {
-       struct request_queue *q = hctx->queue;
+       struct blk_mq_hw_ctx *hctx;
        struct blk_mq_ctx *ctx;
        LIST_HEAD(tmp);
 
-       /*
-        * Move ctx entries to new CPU, if this one is going away.
-        */
-       ctx = __blk_mq_get_ctx(q, cpu);
+       hctx = hlist_entry_safe(node, struct blk_mq_hw_ctx, cpuhp_dead);
+       ctx = __blk_mq_get_ctx(hctx->queue, cpu);
 
        spin_lock(&ctx->lock);
        if (!list_empty(&ctx->rq_list)) {
@@ -1649,43 +1610,20 @@ static int blk_mq_hctx_cpu_offline(struct blk_mq_hw_ctx *hctx, int cpu)
        spin_unlock(&ctx->lock);
 
        if (list_empty(&tmp))
-               return NOTIFY_OK;
-
-       ctx = blk_mq_get_ctx(q);
-       spin_lock(&ctx->lock);
-
-       while (!list_empty(&tmp)) {
-               struct request *rq;
-
-               rq = list_first_entry(&tmp, struct request, queuelist);
-               rq->mq_ctx = ctx;
-               list_move_tail(&rq->queuelist, &ctx->rq_list);
-       }
-
-       hctx = q->mq_ops->map_queue(q, ctx->cpu);
-       blk_mq_hctx_mark_pending(hctx, ctx);
+               return 0;
 
-       spin_unlock(&ctx->lock);
+       spin_lock(&hctx->lock);
+       list_splice_tail_init(&tmp, &hctx->dispatch);
+       spin_unlock(&hctx->lock);
 
        blk_mq_run_hw_queue(hctx, true);
-       blk_mq_put_ctx(ctx);
-       return NOTIFY_OK;
+       return 0;
 }
 
-static int blk_mq_hctx_notify(void *data, unsigned long action,
-                             unsigned int cpu)
+static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx)
 {
-       struct blk_mq_hw_ctx *hctx = data;
-
-       if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
-               return blk_mq_hctx_cpu_offline(hctx, cpu);
-
-       /*
-        * In case of CPU online, tags may be reallocated
-        * in blk_mq_map_swqueue() after mapping is updated.
-        */
-
-       return NOTIFY_OK;
+       cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD,
+                                           &hctx->cpuhp_dead);
 }
 
 /* hctx->ctxs will be freed in queue's release handler */
@@ -1705,9 +1643,9 @@ static void blk_mq_exit_hctx(struct request_queue *q,
        if (set->ops->exit_hctx)
                set->ops->exit_hctx(hctx, hctx_idx);
 
-       blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
+       blk_mq_remove_cpuhp(hctx);
        blk_free_flush_queue(hctx->fq);
-       blk_mq_free_bitmap(&hctx->ctx_map);
+       sbitmap_free(&hctx->ctx_map);
 }
 
 static void blk_mq_exit_hw_queues(struct request_queue *q,
@@ -1744,7 +1682,7 @@ static int blk_mq_init_hctx(struct request_queue *q,
        if (node == NUMA_NO_NODE)
                node = hctx->numa_node = set->numa_node;
 
-       INIT_DELAYED_WORK(&hctx->run_work, blk_mq_run_work_fn);
+       INIT_WORK(&hctx->run_work, blk_mq_run_work_fn);
        INIT_DELAYED_WORK(&hctx->delay_work, blk_mq_delay_work_fn);
        spin_lock_init(&hctx->lock);
        INIT_LIST_HEAD(&hctx->dispatch);
@@ -1752,9 +1690,7 @@ static int blk_mq_init_hctx(struct request_queue *q,
        hctx->queue_num = hctx_idx;
        hctx->flags = set->flags & ~BLK_MQ_F_TAG_SHARED;
 
-       blk_mq_init_cpu_notifier(&hctx->cpu_notifier,
-                                       blk_mq_hctx_notify, hctx);
-       blk_mq_register_cpu_notifier(&hctx->cpu_notifier);
+       cpuhp_state_add_instance_nocalls(CPUHP_BLK_MQ_DEAD, &hctx->cpuhp_dead);
 
        hctx->tags = set->tags[hctx_idx];
 
@@ -1767,7 +1703,8 @@ static int blk_mq_init_hctx(struct request_queue *q,
        if (!hctx->ctxs)
                goto unregister_cpu_notifier;
 
-       if (blk_mq_alloc_bitmap(&hctx->ctx_map, node))
+       if (sbitmap_init_node(&hctx->ctx_map, nr_cpu_ids, ilog2(8), GFP_KERNEL,
+                             node))
                goto free_ctxs;
 
        hctx->nr_ctx = 0;
@@ -1794,12 +1731,11 @@ static int blk_mq_init_hctx(struct request_queue *q,
        if (set->ops->exit_hctx)
                set->ops->exit_hctx(hctx, hctx_idx);
  free_bitmap:
-       blk_mq_free_bitmap(&hctx->ctx_map);
+       sbitmap_free(&hctx->ctx_map);
  free_ctxs:
        kfree(hctx->ctxs);
  unregister_cpu_notifier:
-       blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
-
+       blk_mq_remove_cpuhp(hctx);
        return -1;
 }
 
@@ -1870,8 +1806,6 @@ static void blk_mq_map_swqueue(struct request_queue *q,
        mutex_unlock(&q->sysfs_lock);
 
        queue_for_each_hw_ctx(q, hctx, i) {
-               struct blk_mq_ctxmap *map = &hctx->ctx_map;
-
                /*
                 * If no software queues are mapped to this hardware queue,
                 * disable it and free the request entries.
@@ -1897,7 +1831,7 @@ static void blk_mq_map_swqueue(struct request_queue *q,
                 * This is more accurate and more efficient than looping
                 * over all possibly mapped software queues.
                 */
-               map->size = DIV_ROUND_UP(hctx->nr_ctx, map->bits_per_word);
+               sbitmap_resize(&hctx->ctx_map, hctx->nr_ctx);
 
                /*
                 * Initialize batch roundrobin counts
@@ -2104,7 +2038,7 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
 
        q->sg_reserved_size = INT_MAX;
 
-       INIT_WORK(&q->requeue_work, blk_mq_requeue_work);
+       INIT_DELAYED_WORK(&q->requeue_work, blk_mq_requeue_work);
        INIT_LIST_HEAD(&q->requeue_list);
        spin_lock_init(&q->requeue_lock);
 
@@ -2182,50 +2116,18 @@ static void blk_mq_queue_reinit(struct request_queue *q,
        blk_mq_sysfs_register(q);
 }
 
-static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
-                                     unsigned long action, void *hcpu)
+/*
+ * New online cpumask which is going to be set in this hotplug event.
+ * Declare this cpumasks as global as cpu-hotplug operation is invoked
+ * one-by-one and dynamically allocating this could result in a failure.
+ */
+static struct cpumask cpuhp_online_new;
+
+static void blk_mq_queue_reinit_work(void)
 {
        struct request_queue *q;
-       int cpu = (unsigned long)hcpu;
-       /*
-        * New online cpumask which is going to be set in this hotplug event.
-        * Declare this cpumasks as global as cpu-hotplug operation is invoked
-        * one-by-one and dynamically allocating this could result in a failure.
-        */
-       static struct cpumask online_new;
-
-       /*
-        * Before hotadded cpu starts handling requests, new mappings must
-        * be established.  Otherwise, these requests in hw queue might
-        * never be dispatched.
-        *
-        * For example, there is a single hw queue (hctx) and two CPU queues
-        * (ctx0 for CPU0, and ctx1 for CPU1).
-        *
-        * Now CPU1 is just onlined and a request is inserted into
-        * ctx1->rq_list and set bit0 in pending bitmap as ctx1->index_hw is
-        * still zero.
-        *
-        * And then while running hw queue, flush_busy_ctxs() finds bit0 is
-        * set in pending bitmap and tries to retrieve requests in
-        * hctx->ctxs[0]->rq_list.  But htx->ctxs[0] is a pointer to ctx0,
-        * so the request in ctx1->rq_list is ignored.
-        */
-       switch (action & ~CPU_TASKS_FROZEN) {
-       case CPU_DEAD:
-       case CPU_UP_CANCELED:
-               cpumask_copy(&online_new, cpu_online_mask);
-               break;
-       case CPU_UP_PREPARE:
-               cpumask_copy(&online_new, cpu_online_mask);
-               cpumask_set_cpu(cpu, &online_new);
-               break;
-       default:
-               return NOTIFY_OK;
-       }
 
        mutex_lock(&all_q_mutex);
-
        /*
         * We need to freeze and reinit all existing queues.  Freezing
         * involves synchronous wait for an RCU grace period and doing it
@@ -2246,13 +2148,43 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
        }
 
        list_for_each_entry(q, &all_q_list, all_q_node)
-               blk_mq_queue_reinit(q, &online_new);
+               blk_mq_queue_reinit(q, &cpuhp_online_new);
 
        list_for_each_entry(q, &all_q_list, all_q_node)
                blk_mq_unfreeze_queue(q);
 
        mutex_unlock(&all_q_mutex);
-       return NOTIFY_OK;
+}
+
+static int blk_mq_queue_reinit_dead(unsigned int cpu)
+{
+       cpumask_copy(&cpuhp_online_new, cpu_online_mask);
+       blk_mq_queue_reinit_work();
+       return 0;
+}
+
+/*
+ * Before hotadded cpu starts handling requests, new mappings must be
+ * established.  Otherwise, these requests in hw queue might never be
+ * dispatched.
+ *
+ * For example, there is a single hw queue (hctx) and two CPU queues (ctx0
+ * for CPU0, and ctx1 for CPU1).
+ *
+ * Now CPU1 is just onlined and a request is inserted into ctx1->rq_list
+ * and set bit0 in pending bitmap as ctx1->index_hw is still zero.
+ *
+ * And then while running hw queue, flush_busy_ctxs() finds bit0 is set in
+ * pending bitmap and tries to retrieve requests in hctx->ctxs[0]->rq_list.
+ * But htx->ctxs[0] is a pointer to ctx0, so the request in ctx1->rq_list
+ * is ignored.
+ */
+static int blk_mq_queue_reinit_prepare(unsigned int cpu)
+{
+       cpumask_copy(&cpuhp_online_new, cpu_online_mask);
+       cpumask_set_cpu(cpu, &cpuhp_online_new);
+       blk_mq_queue_reinit_work();
+       return 0;
 }
 
 static int __blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
@@ -2454,10 +2386,12 @@ void blk_mq_enable_hotplug(void)
 
 static int __init blk_mq_init(void)
 {
-       blk_mq_cpu_init();
-
-       hotcpu_notifier(blk_mq_queue_reinit_notify, 0);
+       cpuhp_setup_state_multi(CPUHP_BLK_MQ_DEAD, "block/mq:dead", NULL,
+                               blk_mq_hctx_notify_dead);
 
+       cpuhp_setup_state_nocalls(CPUHP_BLK_MQ_PREPARE, "block/mq:prepare",
+                                 blk_mq_queue_reinit_prepare,
+                                 blk_mq_queue_reinit_dead);
        return 0;
 }
 subsys_initcall(blk_mq_init);