Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

blk-mq: Abort suspend when wakeup events are pending

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>

authored by

Cong Zhang and committed by
Jens Axboe
c196bf43 71075d25

+16 -2
+16 -2
block/blk-mq.c
··· 23 23 #include <linux/cache.h> 24 24 #include <linux/sched/topology.h> 25 25 #include <linux/sched/signal.h> 26 + #include <linux/suspend.h> 26 27 #include <linux/delay.h> 27 28 #include <linux/crash_dump.h> 28 29 #include <linux/prefetch.h> ··· 3719 3718 { 3720 3719 struct blk_mq_hw_ctx *hctx = hlist_entry_safe(node, 3721 3720 struct blk_mq_hw_ctx, cpuhp_online); 3721 + int ret = 0; 3722 3722 3723 3723 if (blk_mq_hctx_has_online_cpu(hctx, cpu)) 3724 3724 return 0; ··· 3740 3738 * frozen and there are no requests. 3741 3739 */ 3742 3740 if (percpu_ref_tryget(&hctx->queue->q_usage_counter)) { 3743 - while (blk_mq_hctx_has_requests(hctx)) 3741 + while (blk_mq_hctx_has_requests(hctx)) { 3742 + /* 3743 + * The wakeup capable IRQ handler of block device is 3744 + * not called during suspend. Skip the loop by checking 3745 + * pm_wakeup_pending to prevent the deadlock and improve 3746 + * suspend latency. 3747 + */ 3748 + if (pm_wakeup_pending()) { 3749 + clear_bit(BLK_MQ_S_INACTIVE, &hctx->state); 3750 + ret = -EBUSY; 3751 + break; 3752 + } 3744 3753 msleep(5); 3754 + } 3745 3755 percpu_ref_put(&hctx->queue->q_usage_counter); 3746 3756 } 3747 3757 3748 - return 0; 3758 + return ret; 3749 3759 } 3750 3760 3751 3761 /*