wbt_init() can be called from sysfs attribute and wbt_enable_default(), however the lock order are inversely. - queue_wb_lat_store() freeze queue first, and then wbt_init() hold rq_qos_mutex. In this case queue will be frozen again inside rq_qos_add(), however, in this case freeze queue recursively is inoperative; - wbt_enable_default() from elevator switch will hold rq_qos_mutex first, and then rq_qos_add() will freeze queue; Fix this problem by converting to use new helper rq_qos_add_frozen() in wbt_init(), and for wbt_enable_default(), freeze queue before calling wbt_init(). Fixes: a13bd91be223 ("block/rq_qos: protect rq_qos apis with a new lock") Signed-off-by: Yu Kuai --- block/blk-wbt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/block/blk-wbt.c b/block/blk-wbt.c index 4bf6f42bef2e..d852317c9cb1 100644 --- a/block/blk-wbt.c +++ b/block/blk-wbt.c @@ -19,6 +19,7 @@ * Copyright (C) 2016 Jens Axboe * */ +#include "linux/blk-mq.h" #include #include #include @@ -763,14 +764,18 @@ void wbt_enable_default(struct gendisk *disk) if (queue_is_mq(q) && enable) { struct rq_wb *rwb = wbt_alloc(); + unsigned int memflags; if (WARN_ON_ONCE(!rwb)) return; + memflags = blk_mq_freeze_queue(q); if (WARN_ON_ONCE(wbt_init(disk, rwb))) { + blk_mq_unfreeze_queue(q, memflags); wbt_free(rwb); return; } + blk_mq_unfreeze_queue(q, memflags); mutex_lock(&q->debugfs_mutex); blk_mq_debugfs_register_rq_qos(q); @@ -947,7 +952,7 @@ static int wbt_init(struct gendisk *disk, struct rq_wb *rwb) * Assign rwb and add the stats callback. */ mutex_lock(&q->rq_qos_mutex); - ret = rq_qos_add(&rwb->rqos, disk, RQ_QOS_WBT, &wbt_rqos_ops); + ret = rq_qos_add_frozen(&rwb->rqos, disk, RQ_QOS_WBT, &wbt_rqos_ops); mutex_unlock(&q->rq_qos_mutex); if (ret) return ret; -- 2.51.0