If wbt is disabled by default and user configures wbt by sysfs, queue will be frozen first and then pcpu_alloc_mutex will be held in blk_stat_alloc_callback(). Fix this problem by allocating memory first before queue frozen. Signed-off-by: Yu Kuai --- block/blk-wbt.c | 94 ++++++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/block/blk-wbt.c b/block/blk-wbt.c index ba807649b29a..3777255b99ad 100644 --- a/block/blk-wbt.c +++ b/block/blk-wbt.c @@ -93,7 +93,7 @@ struct rq_wb { struct rq_depth rq_depth; }; -static int wbt_init(struct gendisk *disk); +static int wbt_init(struct gendisk *disk, struct rq_wb *rwb); static inline struct rq_wb *RQWB(struct rq_qos *rqos) { @@ -698,6 +698,35 @@ static void wbt_requeue(struct rq_qos *rqos, struct request *rq) } } +static int wbt_data_dir(const struct request *rq) +{ + const enum req_op op = req_op(rq); + + if (op == REQ_OP_READ) + return READ; + else if (op_is_write(op)) + return WRITE; + + /* don't account */ + return -1; +} + +static struct rq_wb *wbt_alloc(void) +{ + struct rq_wb *rwb = kzalloc(sizeof(*rwb), GFP_KERNEL); + + if (!rwb) + return NULL; + + rwb->cb = blk_stat_alloc_callback(wb_timer_fn, wbt_data_dir, 2, rwb); + if (!rwb->cb) { + kfree(rwb); + return NULL; + } + + return rwb; +} + /* * Enable wbt if defaults are configured that way */ @@ -726,8 +755,12 @@ void wbt_enable_default(struct gendisk *disk) if (!blk_queue_registered(q)) return; - if (queue_is_mq(q) && enable) - wbt_init(disk); + if (queue_is_mq(q) && enable) { + struct rq_wb *rwb = wbt_alloc(); + + if (rwb) + wbt_init(disk, rwb); + } } EXPORT_SYMBOL_GPL(wbt_enable_default); @@ -743,32 +776,24 @@ static u64 wbt_default_latency_nsec(struct request_queue *q) return 75000000ULL; } -static int wbt_data_dir(const struct request *rq) -{ - const enum req_op op = req_op(rq); - - if (op == REQ_OP_READ) - return READ; - else if (op_is_write(op)) - return WRITE; - - /* don't account */ - return -1; -} - static void wbt_queue_depth_changed(struct rq_qos *rqos) { RQWB(rqos)->rq_depth.queue_depth = blk_queue_depth(rqos->disk->queue); wbt_update_limits(RQWB(rqos)); } +static void wbt_free(struct rq_wb *rwb) +{ + blk_stat_free_callback(rwb->cb); + kfree(rwb); +} + static void wbt_exit(struct rq_qos *rqos) { struct rq_wb *rwb = RQWB(rqos); blk_stat_remove_callback(rqos->disk->queue, rwb->cb); - blk_stat_free_callback(rwb->cb); - kfree(rwb); + wbt_free(rwb); } /* @@ -892,22 +917,11 @@ static const struct rq_qos_ops wbt_rqos_ops = { #endif }; -static int wbt_init(struct gendisk *disk) +static int wbt_init(struct gendisk *disk, struct rq_wb *rwb) { struct request_queue *q = disk->queue; - struct rq_wb *rwb; - int i; int ret; - - rwb = kzalloc(sizeof(*rwb), GFP_KERNEL); - if (!rwb) - return -ENOMEM; - - rwb->cb = blk_stat_alloc_callback(wb_timer_fn, wbt_data_dir, 2, rwb); - if (!rwb->cb) { - kfree(rwb); - return -ENOMEM; - } + int i; for (i = 0; i < WBT_NUM_RWQ; i++) rq_wait_init(&rwb->rq_wait[i]); @@ -934,19 +948,24 @@ static int wbt_init(struct gendisk *disk) return 0; err_free: - blk_stat_free_callback(rwb->cb); - kfree(rwb); + wbt_free(rwb); return ret; - } int wbt_set_lat(struct gendisk *disk, s64 val) { struct request_queue *q = disk->queue; + struct rq_qos *rqos = wbt_rq_qos(q); + struct rq_wb *rwb = NULL; unsigned int memflags; - struct rq_qos *rqos; int ret = 0; + if (!rqos) { + rwb = wbt_alloc(); + if (!rwb) + return -ENOMEM; + } + /* * Ensure that the queue is idled, in case the latency update * ends up either enabling or disabling wbt completely. We can't @@ -956,9 +975,11 @@ int wbt_set_lat(struct gendisk *disk, s64 val) rqos = wbt_rq_qos(q); if (!rqos) { - ret = wbt_init(disk); + ret = wbt_init(disk, rwb); if (ret) goto out; + } else if (rwb) { + wbt_free(rwb); } if (val == -1) @@ -978,6 +999,5 @@ int wbt_set_lat(struct gendisk *disk, s64 val) blk_mq_unquiesce_queue(q); out: blk_mq_unfreeze_queue(q, memflags); - return ret; } -- 2.51.0