@@ -616,15 +616,25 @@ static void debugfs_create_files(struct dentry *parent, void *data,
(void *)attr, &blk_mq_debugfs_fops);
}
+static __must_check struct dentry *blk_mq_get_queue_entry(
+ struct request_queue *q)
+{
+ return debugfs_lookup(q->disk->disk_name, blk_debugfs_root);
+}
+
void blk_mq_debugfs_register(struct request_queue *q)
{
+ struct dentry *queue_dir = blk_mq_get_queue_entry(q);
struct blk_mq_hw_ctx *hctx;
unsigned long i;
- debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs);
+ if (IS_ERR_OR_NULL(queue_dir))
+ return;
+
+ debugfs_create_files(queue_dir, q, blk_mq_debugfs_queue_attrs);
/*
- * blk_mq_init_sched() attempted to do this already, but q->debugfs_dir
+ * blk_mq_init_sched() attempted to do this already, but queue debugfs_dir
* didn't exist yet (because we don't know what to name the directory
* until the queue is registered to a gendisk).
*/
@@ -638,7 +648,7 @@ void blk_mq_debugfs_register(struct request_queue *q)
blk_mq_debugfs_register_sched_hctx(q, hctx);
}
- debugfs_create_dir("rqos", q->debugfs_dir);
+ debugfs_create_dir("rqos", queue_dir);
if (q->rq_qos) {
struct rq_qos *rqos = q->rq_qos;
@@ -648,15 +658,25 @@ void blk_mq_debugfs_register(struct request_queue *q)
rqos = rqos->next;
}
}
+
+ dput(queue_dir);
}
static __must_check struct dentry *blk_mq_get_hctx_entry(
struct blk_mq_hw_ctx *hctx)
{
+ struct dentry *queue_dir = blk_mq_get_queue_entry(hctx->queue);
+ struct dentry *dir;
char name[20];
+ if (IS_ERR_OR_NULL(queue_dir))
+ return NULL;
+
snprintf(name, sizeof(name), "hctx%u", hctx->queue_num);
- return debugfs_lookup(name, hctx->queue->debugfs_dir);
+ dir = debugfs_lookup(name, queue_dir);
+ dput(queue_dir);
+
+ return dir;
}
static __must_check struct dentry *blk_mq_get_hctx_sched_entry(
@@ -692,32 +712,32 @@ static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
void blk_mq_debugfs_register_hctx(struct request_queue *q,
struct blk_mq_hw_ctx *hctx)
{
+ struct dentry *queue_dir = blk_mq_get_queue_entry(q);
struct dentry *hctx_dir;
struct blk_mq_ctx *ctx;
char name[20];
int i;
- if (!q->debugfs_dir)
+ if (IS_ERR_OR_NULL(queue_dir))
return;
snprintf(name, sizeof(name), "hctx%u", hctx->queue_num);
- hctx_dir = debugfs_create_dir(name, q->debugfs_dir);
+ hctx_dir = debugfs_create_dir(name, queue_dir);
if (IS_ERR_OR_NULL(hctx_dir))
- return;
+ goto exit;
debugfs_create_files(hctx_dir, hctx, blk_mq_debugfs_hctx_attrs);
hctx_for_each_ctx(hctx, ctx, i)
blk_mq_debugfs_register_ctx(hctx, ctx);
+exit:
+ dput(queue_dir);
}
void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx)
{
struct dentry *hctx_dir;
- if (!hctx->queue->debugfs_dir)
- return;
-
hctx_dir = blk_mq_get_hctx_entry(hctx);
if (IS_ERR_OR_NULL(hctx_dir))
return;
@@ -746,6 +766,7 @@ void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
void blk_mq_debugfs_register_sched(struct request_queue *q)
{
+ struct dentry *queue_dir = blk_mq_get_queue_entry(q);
struct elevator_type *e = q->elevator->type;
struct dentry *sched_dir;
@@ -755,22 +776,29 @@ void blk_mq_debugfs_register_sched(struct request_queue *q)
* If the parent directory has not been created yet, return, we will be
* called again later on and the directory/files will be created then.
*/
- if (!q->debugfs_dir)
+ if (IS_ERR_OR_NULL(queue_dir))
return;
if (!e->queue_debugfs_attrs)
- return;
+ goto exit;
- sched_dir = debugfs_create_dir("sched", q->debugfs_dir);
+ sched_dir = debugfs_create_dir("sched", queue_dir);
debugfs_create_files(sched_dir, q, e->queue_debugfs_attrs);
+exit:
+ dput(queue_dir);
}
void blk_mq_debugfs_unregister_sched(struct request_queue *q)
{
+ struct dentry *queue_dir = blk_mq_get_queue_entry(q);
+
lockdep_assert_held(&q->debugfs_mutex);
- debugfs_lookup_and_remove("sched", q->debugfs_dir);
+ if (IS_ERR_OR_NULL(queue_dir))
+ return;
+ debugfs_lookup_and_remove("sched", queue_dir);
+ dput(queue_dir);
}
static const char *rq_qos_id_to_name(enum rq_qos_id id)
@@ -789,24 +817,33 @@ static const char *rq_qos_id_to_name(enum rq_qos_id id)
static __must_check struct dentry *blk_mq_debugfs_get_rqos_top(
struct request_queue *q)
{
- return debugfs_lookup("rqos", q->debugfs_dir);
+ struct dentry *queue_dir = blk_mq_get_queue_entry(q);
+ struct dentry *dir = NULL;
+
+ if (queue_dir)
+ dir = debugfs_lookup("rqos", queue_dir);
+ dput(queue_dir);
+ return dir;
}
void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos)
{
struct request_queue *q = rqos->disk->queue;
+ struct dentry *queue_dir = blk_mq_get_queue_entry(q);
struct dentry *rqos_top;
lockdep_assert_held(&q->debugfs_mutex);
- if (!q->debugfs_dir)
+ if (IS_ERR_OR_NULL(queue_dir))
return;
rqos_top = blk_mq_debugfs_get_rqos_top(q);
if (IS_ERR_OR_NULL(rqos_top))
- return;
+ goto exit;
debugfs_lookup_and_remove(rq_qos_id_to_name(rqos->id), rqos_top);
dput(rqos_top);
+exit:
+ dput(queue_dir);
}
void blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
@@ -862,8 +899,6 @@ void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx)
lockdep_assert_held(&hctx->queue->debugfs_mutex);
- if (!hctx->queue->debugfs_dir)
- return;
sched_dir = blk_mq_get_hctx_sched_entry(hctx);
if (sched_dir) {
debugfs_remove_recursive(sched_dir);
@@ -746,8 +746,7 @@ static void blk_debugfs_remove(struct gendisk *disk)
mutex_lock(&q->debugfs_mutex);
blk_trace_shutdown(q);
- debugfs_remove_recursive(q->debugfs_dir);
- q->debugfs_dir = NULL;
+ debugfs_lookup_and_remove(disk->disk_name, blk_debugfs_root);
mutex_unlock(&q->debugfs_mutex);
}
@@ -773,7 +772,7 @@ int blk_register_queue(struct gendisk *disk)
mutex_lock(&q->sysfs_lock);
mutex_lock(&q->debugfs_mutex);
- q->debugfs_dir = debugfs_create_dir(disk->disk_name, blk_debugfs_root);
+ debugfs_create_dir(disk->disk_name, blk_debugfs_root);
if (queue_is_mq(q))
blk_mq_debugfs_register(q);
mutex_unlock(&q->debugfs_mutex);
@@ -597,7 +597,6 @@ struct request_queue {
struct blk_mq_tag_set *tag_set;
struct list_head tag_set_list;
- struct dentry *debugfs_dir;
/*
* Serializes all debugfs metadata operations using the above dentries.
*/
@@ -311,17 +311,31 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
local_irq_restore(flags);
}
+static struct dentry *blk_get_queue_debugfs_dir(struct request_queue *q)
+{
+ struct dentry *dir = NULL;;
+
+ if (q->disk)
+ dir = debugfs_lookup(q->disk->disk_name, blk_debugfs_root);
+ return dir;
+}
+
static void blk_trace_free(struct request_queue *q, struct blk_trace *bt)
{
relay_close(bt->rchan);
/*
* If 'bt->dir' is not set, then both 'dropped' and 'msg' are created
- * under 'q->debugfs_dir', thus lookup and remove them.
+ * under block queue debugfs dir, thus lookup and remove them.
*/
if (!bt->dir) {
- debugfs_lookup_and_remove("dropped", q->debugfs_dir);
- debugfs_lookup_and_remove("msg", q->debugfs_dir);
+ struct dentry *dir = blk_get_queue_debugfs_dir(q);
+
+ if (!IS_ERR_OR_NULL(dir)) {
+ debugfs_lookup_and_remove("dropped", dir);
+ debugfs_lookup_and_remove("msg", dir);
+ dput(dir);
+ }
} else {
debugfs_remove(bt->dir);
}
@@ -517,6 +531,7 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
{
struct blk_trace *bt = NULL;
struct dentry *dir = NULL;
+ struct dentry *dir_to_drop = NULL;
int ret;
lockdep_assert_held(&q->debugfs_mutex);
@@ -563,7 +578,7 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
* directory that will be removed once the trace ends.
*/
if (bdev && !bdev_is_partition(bdev))
- dir = q->debugfs_dir;
+ dir_to_drop = dir = blk_get_queue_debugfs_dir(q);
else
bt->dir = dir = debugfs_create_dir(buts->name, blk_debugfs_root);
@@ -614,6 +629,8 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
err:
if (ret)
blk_trace_free(q, bt);
+ if (!IS_ERR_OR_NULL(dir_to_drop))
+ dput(dir_to_drop);
return ret;
}
For each rqos instance, its debugfs path is fixed, which can be queried from its block debugfs dentry & disk name directly, so it isn't necessary to cache it in request_queue instance because it isn't used in fast path. Signed-off-by: Ming Lei <ming.lei@redhat.com> --- block/blk-mq-debugfs.c | 73 ++++++++++++++++++++++++++++++----------- block/blk-sysfs.c | 5 ++- include/linux/blkdev.h | 1 - kernel/trace/blktrace.c | 25 +++++++++++--- 4 files changed, 77 insertions(+), 27 deletions(-)