blk-mq: Create hctx for each present CPU 84/290884/2 accepted/tizen/unified/20230406.165743
authorChristoph Hellwig <hch@lst.de>
Mon, 26 Jun 2017 10:20:57 +0000 (12:20 +0200)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Wed, 5 Apr 2023 01:20:19 +0000 (10:20 +0900)
Currently we only create hctx for online CPUs, which can lead to a lot
of churn due to frequent soft offline / online operations.  Instead
allocate one for each present CPU to avoid this and dramatically simplify
the code.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jens Axboe <axboe@kernel.dk>
Cc: Keith Busch <keith.busch@intel.com>
Cc: linux-block@vger.kernel.org
Cc: linux-nvme@lists.infradead.org
Link: http://lkml.kernel.org/r/20170626102058.10200-3-hch@lst.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Oleksandr Natalenko <oleksandr@natalenko.name>
Cc: Mike Galbraith <efault@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[sw0312.kim: backport mainline commit 4b855ad37194 to fix possible deadlock in blk-mq for cpu hotplug]
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Change-Id: I019f976ab755a38f4c783e94c73a4ff60114a648

block/blk-mq.c
block/blk-mq.h
include/linux/cpuhotplug.h

index 5c9f747..58e0890 100644 (file)
@@ -31,9 +31,6 @@
 #include "blk-mq.h"
 #include "blk-mq-tag.h"
 
-static DEFINE_MUTEX(all_q_mutex);
-static LIST_HEAD(all_q_list);
-
 /*
  * Check if any of the ctx's have pending work in this hardware queue
  */
@@ -1733,8 +1730,8 @@ static void blk_mq_init_cpu_queues(struct request_queue *q,
                INIT_LIST_HEAD(&__ctx->rq_list);
                __ctx->queue = q;
 
-               /* If the cpu isn't online, the cpu is mapped to first hctx */
-               if (!cpu_online(i))
+               /* If the cpu isn't present, the cpu is mapped to first hctx */
+               if (!cpu_present(i))
                        continue;
 
                hctx = blk_mq_map_queue(q, i);
@@ -1748,8 +1745,7 @@ static void blk_mq_init_cpu_queues(struct request_queue *q,
        }
 }
 
-static void blk_mq_map_swqueue(struct request_queue *q,
-                              const struct cpumask *online_mask)
+static void blk_mq_map_swqueue(struct request_queue *q)
 {
        unsigned int i;
        struct blk_mq_hw_ctx *hctx;
@@ -1767,13 +1763,11 @@ static void blk_mq_map_swqueue(struct request_queue *q,
        }
 
        /*
-        * Map software to hardware queues
+        * Map software to hardware queues.
+        *
+        * If the cpu isn't present, the cpu is mapped to first hctx.
         */
-       for_each_possible_cpu(i) {
-               /* If the cpu isn't online, the cpu is mapped to first hctx */
-               if (!cpumask_test_cpu(i, online_mask))
-                       continue;
-
+       for_each_present_cpu(i) {
                ctx = per_cpu_ptr(q->queue_ctx, i);
                hctx = blk_mq_map_queue(q, i);
 
@@ -2038,16 +2032,8 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
                blk_queue_softirq_done(q, set->ops->complete);
 
        blk_mq_init_cpu_queues(q, set->nr_hw_queues);
-
-       get_online_cpus();
-       mutex_lock(&all_q_mutex);
-
-       list_add_tail(&q->all_q_node, &all_q_list);
        blk_mq_add_queue_tag_set(set, q);
-       blk_mq_map_swqueue(q, cpu_online_mask);
-
-       mutex_unlock(&all_q_mutex);
-       put_online_cpus();
+       blk_mq_map_swqueue(q);
 
        return q;
 
@@ -2065,19 +2051,13 @@ void blk_mq_free_queue(struct request_queue *q)
 {
        struct blk_mq_tag_set   *set = q->tag_set;
 
-       mutex_lock(&all_q_mutex);
-       list_del_init(&q->all_q_node);
-       mutex_unlock(&all_q_mutex);
-
        blk_mq_del_queue_tag_set(q);
-
        blk_mq_exit_hw_queues(q, set, set->nr_hw_queues);
        blk_mq_free_hw_queues(q, set);
 }
 
 /* Basically redo blk_mq_init_queue with queue frozen */
-static void blk_mq_queue_reinit(struct request_queue *q,
-                               const struct cpumask *online_mask)
+static void blk_mq_queue_reinit(struct request_queue *q)
 {
        WARN_ON_ONCE(!atomic_read(&q->mq_freeze_depth));
 
@@ -2089,82 +2069,11 @@ static void blk_mq_queue_reinit(struct request_queue *q,
         * involves free and re-allocate memory, worthy doing?)
         */
 
-       blk_mq_map_swqueue(q, online_mask);
+       blk_mq_map_swqueue(q);
 
        blk_mq_sysfs_register(q);
 }
 
-/*
- * 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;
-
-       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
-        * one by one may take a long time.  Start freezing all queues in
-        * one swoop and then wait for the completions so that freezing can
-        * take place in parallel.
-        */
-       list_for_each_entry(q, &all_q_list, all_q_node)
-               blk_mq_freeze_queue_start(q);
-       list_for_each_entry(q, &all_q_list, all_q_node) {
-               blk_mq_freeze_queue_wait(q);
-
-               /*
-                * timeout handler can't touch hw queue during the
-                * reinitialization
-                */
-               del_timer_sync(&q->timeout);
-       }
-
-       list_for_each_entry(q, &all_q_list, all_q_node)
-               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);
-}
-
-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)
 {
        int i;
@@ -2365,7 +2274,7 @@ void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues)
                else
                        blk_queue_make_request(q, blk_sq_make_request);
 
-               blk_mq_queue_reinit(q, cpu_online_mask);
+               blk_mq_queue_reinit(q);
        }
 
        list_for_each_entry(q, &set->tag_list, tag_set_list)
@@ -2373,24 +2282,10 @@ void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues)
 }
 EXPORT_SYMBOL_GPL(blk_mq_update_nr_hw_queues);
 
-void blk_mq_disable_hotplug(void)
-{
-       mutex_lock(&all_q_mutex);
-}
-
-void blk_mq_enable_hotplug(void)
-{
-       mutex_unlock(&all_q_mutex);
-}
-
 static int __init blk_mq_init(void)
 {
        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);
index a2cc41a..b54b0d9 100644 (file)
@@ -30,12 +30,6 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr);
 void blk_mq_wake_waiters(struct request_queue *q);
 
 /*
- * CPU hotplug helpers
- */
-void blk_mq_enable_hotplug(void);
-void blk_mq_disable_hotplug(void);
-
-/*
  * CPU -> queue mappings
  */
 int blk_mq_map_queues(struct blk_mq_tag_set *set);
index 1ab0273..2d83f15 100644 (file)
@@ -47,7 +47,6 @@ enum cpuhp_state {
        CPUHP_NOTIFY_PREPARE,
        CPUHP_ARM_SHMOBILE_SCU_PREPARE,
        CPUHP_SH_SH3X_PREPARE,
-       CPUHP_BLK_MQ_PREPARE,
        CPUHP_TIMERS_PREPARE,
        CPUHP_NOTF_ERR_INJ_PREPARE,
        CPUHP_MIPS_SOC_PREPARE,