]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
blk-mq: Abort suspend when wakeup events are pending
authorCong Zhang <cong.zhang@oss.qualcomm.com>
Wed, 3 Dec 2025 03:34:21 +0000 (11:34 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 19 Jan 2026 12:09:39 +0000 (13:09 +0100)
[ Upstream commit c196bf43d706592d8801a7513603765080e495fb ]

During system suspend, wakeup capable IRQs for block device can be
delayed, which can cause blk_mq_hctx_notify_offline() to hang
indefinitely while waiting for pending request to complete.
Skip the request waiting loop and abort suspend when wakeup events are
pending to prevent the deadlock.

Fixes: bf0beec0607d ("blk-mq: drain I/O when all CPUs in a hctx are offline")
Signed-off-by: Cong Zhang <cong.zhang@oss.qualcomm.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
block/blk-mq.c

index 46cb802cfcf0522b19c3a515e4daf3a77063dbe4..48827708200b3219f73873323f4acbed9751abce 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sched/sysctl.h>
 #include <linux/sched/topology.h>
 #include <linux/sched/signal.h>
+#include <linux/suspend.h>
 #include <linux/delay.h>
 #include <linux/crash_dump.h>
 #include <linux/prefetch.h>
@@ -2585,6 +2586,7 @@ static int blk_mq_hctx_notify_offline(unsigned int cpu, struct hlist_node *node)
 {
        struct blk_mq_hw_ctx *hctx = hlist_entry_safe(node,
                        struct blk_mq_hw_ctx, cpuhp_online);
+       int ret = 0;
 
        if (!cpumask_test_cpu(cpu, hctx->cpumask) ||
            !blk_mq_last_cpu_in_hctx(cpu, hctx))
@@ -2606,12 +2608,24 @@ static int blk_mq_hctx_notify_offline(unsigned int cpu, struct hlist_node *node)
         * frozen and there are no requests.
         */
        if (percpu_ref_tryget(&hctx->queue->q_usage_counter)) {
-               while (blk_mq_hctx_has_requests(hctx))
+               while (blk_mq_hctx_has_requests(hctx)) {
+                       /*
+                        * The wakeup capable IRQ handler of block device is
+                        * not called during suspend. Skip the loop by checking
+                        * pm_wakeup_pending to prevent the deadlock and improve
+                        * suspend latency.
+                        */
+                       if (pm_wakeup_pending()) {
+                               clear_bit(BLK_MQ_S_INACTIVE, &hctx->state);
+                               ret = -EBUSY;
+                               break;
+                       }
                        msleep(5);
+               }
                percpu_ref_put(&hctx->queue->q_usage_counter);
        }
 
-       return 0;
+       return ret;
 }
 
 static int blk_mq_hctx_notify_online(unsigned int cpu, struct hlist_node *node)