Currently rq-qos debugfs entries are created from rq_qos_add(), while rq_qos_add() can be called while queue is still frozen. This can deadlock because creating new entries can trigger fs reclaim. Fix this problem by delaying creating rq-qos debugfs entries after queue is unfrozen. - For wbt, 1) it can be initialized by default, fix it by calling new helper after wbt_init() from wbt_enable_default; 2) it can be initialized by sysfs, fix it by calling new helper after queue is unfrozen from queue_wb_lat_store(). - For iocost and iolatency, they can only be initialized by blkcg configuration, fix by calling the new helper from blkg_conf_end(). Signed-off-by: Yu Kuai --- block/blk-cgroup.c | 38 +++++++++++++++++++++++++++++--------- block/blk-rq-qos.c | 7 ------- block/blk-sysfs.c | 4 ++++ block/blk-wbt.c | 6 +++++- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 3cffb68ba5d8..ad3bd43b2859 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -33,6 +33,7 @@ #include "blk-cgroup.h" #include "blk-ioprio.h" #include "blk-throttle.h" +#include "blk-mq-debugfs.h" static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu); @@ -966,14 +967,7 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, } EXPORT_SYMBOL_GPL(blkg_conf_prep); -/** - * blkg_conf_exit - clean up per-blkg config update - * @ctx: blkg_conf_ctx initialized with blkg_conf_init() - * - * Clean up after per-blkg config update. This function must be called on all - * blkg_conf_ctx's initialized with blkg_conf_init(). - */ -void blkg_conf_exit(struct blkg_conf_ctx *ctx) +static void __blkg_conf_exit(struct blkg_conf_ctx *ctx) __releases(&ctx->bdev->bd_queue->queue_lock) __releases(&ctx->bdev->bd_queue->rq_qos_mutex) { @@ -986,6 +980,26 @@ void blkg_conf_exit(struct blkg_conf_ctx *ctx) mutex_unlock(&ctx->bdev->bd_queue->rq_qos_mutex); blkdev_put_no_open(ctx->bdev); ctx->body = NULL; + } +} + +/** + * blkg_conf_exit - clean up per-blkg config update + * @ctx: blkg_conf_ctx initialized with blkg_conf_init() + * + * Clean up after per-blkg config update. This function must be called on all + * blkg_conf_ctx's initialized with blkg_conf_init(). + */ +void blkg_conf_exit(struct blkg_conf_ctx *ctx) +{ + __blkg_conf_exit(ctx); + if (ctx->bdev) { + struct request_queue *q = ctx->bdev->bd_queue; + + mutex_lock(&q->debugfs_mutex); + blk_mq_debugfs_register_rq_qos(q); + mutex_unlock(&q->debugfs_mutex); + ctx->bdev = NULL; } } @@ -1000,8 +1014,14 @@ void blkg_conf_exit_frozen(struct blkg_conf_ctx *ctx, unsigned long memflags) if (ctx->bdev) { struct request_queue *q = ctx->bdev->bd_queue; - blkg_conf_exit(ctx); + __blkg_conf_exit(ctx); blk_mq_unfreeze_queue(q, memflags); + + mutex_lock(&q->debugfs_mutex); + blk_mq_debugfs_register_rq_qos(q); + mutex_unlock(&q->debugfs_mutex); + + ctx->bdev = NULL; } } diff --git a/block/blk-rq-qos.c b/block/blk-rq-qos.c index 654478dfbc20..d7ce99ce2e80 100644 --- a/block/blk-rq-qos.c +++ b/block/blk-rq-qos.c @@ -347,13 +347,6 @@ int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id, blk_queue_flag_set(QUEUE_FLAG_QOS_ENABLED, q); blk_mq_unfreeze_queue(q, memflags); - - if (rqos->ops->debugfs_attrs) { - mutex_lock(&q->debugfs_mutex); - blk_mq_debugfs_register_rqos(rqos); - mutex_unlock(&q->debugfs_mutex); - } - return 0; ebusy: blk_mq_unfreeze_queue(q, memflags); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 5c2d29ac6570..fb165f2977e6 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -722,6 +722,10 @@ static ssize_t queue_wb_lat_store(struct gendisk *disk, const char *page, out: blk_mq_unfreeze_queue(q, memflags); + mutex_lock(&q->debugfs_mutex); + blk_mq_debugfs_register_rq_qos(q); + mutex_unlock(&q->debugfs_mutex); + return ret; } diff --git a/block/blk-wbt.c b/block/blk-wbt.c index eb8037bae0bd..b1ab0f297f24 100644 --- a/block/blk-wbt.c +++ b/block/blk-wbt.c @@ -724,8 +724,12 @@ void wbt_enable_default(struct gendisk *disk) if (!blk_queue_registered(q)) return; - if (queue_is_mq(q) && enable) + if (queue_is_mq(q) && enable) { wbt_init(disk); + mutex_lock(&q->debugfs_mutex); + blk_mq_debugfs_register_rq_qos(q); + mutex_unlock(&q->debugfs_mutex); + } } EXPORT_SYMBOL_GPL(wbt_enable_default); -- 2.51.0