diff --git a/block/blk-mq.c b/block/blk-mq.c index 65340847b51e..e027b8ed6030 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -628,7 +628,20 @@ static void blk_mq_rq_timer(unsigned long priv) }; int i; - if (blk_queue_enter(q, GFP_NOWAIT)) + /* A deadlock might occur if a request is stuck requiring a + * timeout at the same time a queue freeze is waiting + * completion, since the timeout code would not be able to + * acquire the queue reference here. + * + * That's why we don't use blk_queue_enter here; instead, we use + * percpu_ref_tryget directly, because we need to be able to + * obtain a reference even in the short window between the queue + * starting to freeze, by dropping the first reference in + * blk_mq_freeze_queue_start, and the moment the last request is + * consumed, marked by the instant q_usage_counter reaches + * zero. + */ + if (!percpu_ref_tryget(&q->q_usage_counter)) return; blk_mq_queue_tag_busy_iter(q, blk_mq_check_expired, &data);