blk-mq: untangle debugfs and sysfs
authorOmar Sandoval <osandov@fb.com>
Thu, 4 May 2017 14:17:21 +0000 (08:17 -0600)
committerJens Axboe <axboe@fb.com>
Thu, 4 May 2017 14:24:13 +0000 (08:24 -0600)
Originally, I tied debugfs registration/unregistration together with
sysfs. There's no reason to do this, and it's getting in the way of
letting schedulers define their own debugfs attributes. Instead, tie the
debugfs registration to the lifetime of the structures themselves.

The saner lifetimes mean we can also get rid of the extra mq directory
and move everything one level up. I.e., nvme0n1/mq/hctx0/tags is now
just nvme0n1/hctx0/tags.

Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
block/blk-core.c
block/blk-mq-debugfs.c
block/blk-mq-debugfs.h
block/blk-mq-sysfs.c
block/blk-mq.c
block/blk-sysfs.c
include/linux/blk-mq.h
include/linux/blkdev.h

index acdca6536562f5d8a99cc49f1e97f781312edb8c..c580b0138a7f3713486dc1005d47a75a357a24d2 100644 (file)
@@ -40,7 +40,6 @@
 
 #include "blk.h"
 #include "blk-mq.h"
-#include "blk-mq-debugfs.h"
 #include "blk-mq-sched.h"
 #include "blk-wbt.h"
 
@@ -562,13 +561,9 @@ void blk_cleanup_queue(struct request_queue *q)
         * prevent that q->request_fn() gets invoked after draining finished.
         */
        blk_freeze_queue(q);
-       if (!q->mq_ops) {
-               spin_lock_irq(lock);
+       spin_lock_irq(lock);
+       if (!q->mq_ops)
                __blk_drain_queue(q, true);
-       } else {
-               blk_mq_debugfs_unregister_mq(q);
-               spin_lock_irq(lock);
-       }
        queue_flag_set(QUEUE_FLAG_DEAD, q);
        spin_unlock_irq(lock);
 
index 1dc1847b53636c2f69f64ec183229609982110e4..260cf76e0705d2a998715b1565c13a0863e785ee 100644 (file)
@@ -687,19 +687,46 @@ static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = {
        {},
 };
 
+static bool debugfs_create_files(struct dentry *parent, void *data,
+                                const struct blk_mq_debugfs_attr *attr)
+{
+       d_inode(parent)->i_private = data;
+
+       for (; attr->name; attr++) {
+               if (!debugfs_create_file(attr->name, attr->mode, parent,
+                                        (void *)attr, &blk_mq_debugfs_fops))
+                       return false;
+       }
+       return true;
+}
+
 int blk_mq_debugfs_register(struct request_queue *q)
 {
+       struct blk_mq_hw_ctx *hctx;
+       int i;
+
        if (!blk_debugfs_root)
                return -ENOENT;
 
        q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent),
                                            blk_debugfs_root);
        if (!q->debugfs_dir)
-               goto err;
+               return -ENOMEM;
 
-       if (blk_mq_debugfs_register_mq(q))
+       if (!debugfs_create_files(q->debugfs_dir, q,
+                                 blk_mq_debugfs_queue_attrs))
                goto err;
 
+       /*
+        * blk_mq_init_hctx() attempted to do this already, but q->debugfs_dir
+        * didn't exist yet (because we don't know what to name the directory
+        * until the queue is registered to a gendisk).
+        */
+       queue_for_each_hw_ctx(q, hctx, i) {
+               if (!hctx->debugfs_dir && blk_mq_debugfs_register_hctx(q, hctx))
+                       goto err;
+       }
+
        return 0;
 
 err:
@@ -710,32 +737,17 @@ err:
 void blk_mq_debugfs_unregister(struct request_queue *q)
 {
        debugfs_remove_recursive(q->debugfs_dir);
-       q->mq_debugfs_dir = NULL;
        q->debugfs_dir = NULL;
 }
 
-static bool debugfs_create_files(struct dentry *parent, void *data,
-                                const struct blk_mq_debugfs_attr *attr)
-{
-       d_inode(parent)->i_private = data;
-
-       for (; attr->name; attr++) {
-               if (!debugfs_create_file(attr->name, attr->mode, parent,
-                                        (void *)attr, &blk_mq_debugfs_fops))
-                       return false;
-       }
-       return true;
-}
-
-static int blk_mq_debugfs_register_ctx(struct request_queue *q,
-                                      struct blk_mq_ctx *ctx,
-                                      struct dentry *hctx_dir)
+static int blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
+                                      struct blk_mq_ctx *ctx)
 {
        struct dentry *ctx_dir;
        char name[20];
 
        snprintf(name, sizeof(name), "cpu%u", ctx->cpu);
-       ctx_dir = debugfs_create_dir(name, hctx_dir);
+       ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir);
        if (!ctx_dir)
                return -ENOMEM;
 
@@ -745,59 +757,61 @@ static int blk_mq_debugfs_register_ctx(struct request_queue *q,
        return 0;
 }
 
-static int blk_mq_debugfs_register_hctx(struct request_queue *q,
-                                       struct blk_mq_hw_ctx *hctx)
+int blk_mq_debugfs_register_hctx(struct request_queue *q,
+                                struct blk_mq_hw_ctx *hctx)
 {
        struct blk_mq_ctx *ctx;
-       struct dentry *hctx_dir;
        char name[20];
        int i;
 
+       if (!q->debugfs_dir)
+               return -ENOENT;
+
        snprintf(name, sizeof(name), "hctx%u", hctx->queue_num);
-       hctx_dir = debugfs_create_dir(name, q->mq_debugfs_dir);
-       if (!hctx_dir)
+       hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir);
+       if (!hctx->debugfs_dir)
                return -ENOMEM;
 
-       if (!debugfs_create_files(hctx_dir, hctx, blk_mq_debugfs_hctx_attrs))
-               return -ENOMEM;
+       if (!debugfs_create_files(hctx->debugfs_dir, hctx,
+                                 blk_mq_debugfs_hctx_attrs))
+               goto err;
 
        hctx_for_each_ctx(hctx, ctx, i) {
-               if (blk_mq_debugfs_register_ctx(q, ctx, hctx_dir))
-                       return -ENOMEM;
+               if (blk_mq_debugfs_register_ctx(hctx, ctx))
+                       goto err;
        }
 
        return 0;
+
+err:
+       blk_mq_debugfs_unregister_hctx(hctx);
+       return -ENOMEM;
+}
+
+void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx)
+{
+       debugfs_remove_recursive(hctx->debugfs_dir);
+       hctx->debugfs_dir = NULL;
 }
 
-int blk_mq_debugfs_register_mq(struct request_queue *q)
+int blk_mq_debugfs_register_hctxs(struct request_queue *q)
 {
        struct blk_mq_hw_ctx *hctx;
        int i;
 
-       if (!q->debugfs_dir)
-               return -ENOENT;
-
-       q->mq_debugfs_dir = debugfs_create_dir("mq", q->debugfs_dir);
-       if (!q->mq_debugfs_dir)
-               goto err;
-
-       if (!debugfs_create_files(q->mq_debugfs_dir, q, blk_mq_debugfs_queue_attrs))
-               goto err;
-
        queue_for_each_hw_ctx(q, hctx, i) {
                if (blk_mq_debugfs_register_hctx(q, hctx))
-                       goto err;
+                       return -ENOMEM;
        }
 
        return 0;
-
-err:
-       blk_mq_debugfs_unregister_mq(q);
-       return -ENOMEM;
 }
 
-void blk_mq_debugfs_unregister_mq(struct request_queue *q)
+void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
 {
-       debugfs_remove_recursive(q->mq_debugfs_dir);
-       q->mq_debugfs_dir = NULL;
+       struct blk_mq_hw_ctx *hctx;
+       int i;
+
+       queue_for_each_hw_ctx(q, hctx, i)
+               blk_mq_debugfs_unregister_hctx(hctx);
 }
index 00b0f71d0ae9ce74a91cb648abf03fd54d5e0697..596e9b16d3d1724f7ca9857c19e86320b3d8b05d 100644 (file)
@@ -4,8 +4,11 @@
 #ifdef CONFIG_BLK_DEBUG_FS
 int blk_mq_debugfs_register(struct request_queue *q);
 void blk_mq_debugfs_unregister(struct request_queue *q);
-int blk_mq_debugfs_register_mq(struct request_queue *q);
-void blk_mq_debugfs_unregister_mq(struct request_queue *q);
+int blk_mq_debugfs_register_hctx(struct request_queue *q,
+                                struct blk_mq_hw_ctx *hctx);
+void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx);
+int blk_mq_debugfs_register_hctxs(struct request_queue *q);
+void blk_mq_debugfs_unregister_hctxs(struct request_queue *q);
 #else
 static inline int blk_mq_debugfs_register(struct request_queue *q)
 {
@@ -16,12 +19,22 @@ static inline void blk_mq_debugfs_unregister(struct request_queue *q)
 {
 }
 
-static inline int blk_mq_debugfs_register_mq(struct request_queue *q)
+static inline int blk_mq_debugfs_register_hctx(struct request_queue *q,
+                                              struct blk_mq_hw_ctx *hctx)
 {
        return 0;
 }
 
-static inline void blk_mq_debugfs_unregister_mq(struct request_queue *q)
+static inline void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx)
+{
+}
+
+static inline int blk_mq_debugfs_register_hctxs(struct request_queue *q)
+{
+       return 0;
+}
+
+static inline void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
 {
 }
 #endif
index 71a237a90d434e2a8607e20fc57724d1298bae92..79969c3c234fd9db3f76f2186d3f7080e9f1e321 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/blk-mq.h>
 #include "blk-mq.h"
-#include "blk-mq-debugfs.h"
 #include "blk-mq-tag.h"
 
 static void blk_mq_sysfs_release(struct kobject *kobj)
@@ -259,8 +258,6 @@ static void __blk_mq_unregister_dev(struct device *dev, struct request_queue *q)
        queue_for_each_hw_ctx(q, hctx, i)
                blk_mq_unregister_hctx(hctx);
 
-       blk_mq_debugfs_unregister_mq(q);
-
        kobject_uevent(&q->mq_kobj, KOBJ_REMOVE);
        kobject_del(&q->mq_kobj);
        kobject_put(&dev->kobj);
@@ -319,8 +316,6 @@ int __blk_mq_register_dev(struct device *dev, struct request_queue *q)
 
        kobject_uevent(&q->mq_kobj, KOBJ_ADD);
 
-       blk_mq_debugfs_register(q);
-
        queue_for_each_hw_ctx(q, hctx, i) {
                ret = blk_mq_register_hctx(hctx);
                if (ret)
@@ -336,8 +331,6 @@ unreg:
        while (--i >= 0)
                blk_mq_unregister_hctx(q->queue_hw_ctx[i]);
 
-       blk_mq_debugfs_unregister_mq(q);
-
        kobject_uevent(&q->mq_kobj, KOBJ_REMOVE);
        kobject_del(&q->mq_kobj);
        kobject_put(&dev->kobj);
@@ -365,8 +358,6 @@ void blk_mq_sysfs_unregister(struct request_queue *q)
        if (!q->mq_sysfs_init_done)
                goto unlock;
 
-       blk_mq_debugfs_unregister_mq(q);
-
        queue_for_each_hw_ctx(q, hctx, i)
                blk_mq_unregister_hctx(hctx);
 
@@ -383,8 +374,6 @@ int blk_mq_sysfs_register(struct request_queue *q)
        if (!q->mq_sysfs_init_done)
                goto unlock;
 
-       blk_mq_debugfs_register_mq(q);
-
        queue_for_each_hw_ctx(q, hctx, i) {
                ret = blk_mq_register_hctx(hctx);
                if (ret)
index 03a7471056829de6ba0a4a5d42ff4ad1fc5bc387..5d4ce7eb8dbfb9100b7cfc7b673a64a1ab4822ad 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/blk-mq.h>
 #include "blk.h"
 #include "blk-mq.h"
+#include "blk-mq-debugfs.h"
 #include "blk-mq-tag.h"
 #include "blk-stat.h"
 #include "blk-wbt.h"
@@ -1862,6 +1863,8 @@ static void blk_mq_exit_hctx(struct request_queue *q,
                struct blk_mq_tag_set *set,
                struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx)
 {
+       blk_mq_debugfs_unregister_hctx(hctx);
+
        blk_mq_tag_idle(hctx);
 
        if (set->ops->exit_request)
@@ -1948,6 +1951,8 @@ static int blk_mq_init_hctx(struct request_queue *q,
        if (hctx->flags & BLK_MQ_F_BLOCKING)
                init_srcu_struct(&hctx->queue_rq_srcu);
 
+       blk_mq_debugfs_register_hctx(q, hctx);
+
        return 0;
 
  free_fq:
@@ -2385,6 +2390,7 @@ static void blk_mq_queue_reinit(struct request_queue *q,
 {
        WARN_ON_ONCE(!atomic_read(&q->mq_freeze_depth));
 
+       blk_mq_debugfs_unregister_hctxs(q);
        blk_mq_sysfs_unregister(q);
 
        /*
@@ -2396,6 +2402,7 @@ static void blk_mq_queue_reinit(struct request_queue *q,
        blk_mq_map_swqueue(q, online_mask);
 
        blk_mq_sysfs_register(q);
+       blk_mq_debugfs_register_hctxs(q);
 }
 
 /*
index 9995355121d7cc41368f85fbc75ac16d6c971bfc..504fee9400523e206f987542d59abf8167e31c7e 100644 (file)
@@ -890,6 +890,8 @@ int blk_register_queue(struct gendisk *disk)
        if (q->mq_ops)
                __blk_mq_register_dev(dev, q);
 
+       blk_mq_debugfs_register(q);
+
        kobject_uevent(&q->kobj, KOBJ_ADD);
 
        wbt_enable_default(q);
index a104832e7ae5e448ac2b2faeaffcd5fdc6f4dda6..de8ed9aaa156247f2b3459fc514db61b7645b6f0 100644 (file)
@@ -57,6 +57,10 @@ struct blk_mq_hw_ctx {
        unsigned long           poll_considered;
        unsigned long           poll_invoked;
        unsigned long           poll_success;
+
+#ifdef CONFIG_BLK_DEBUG_FS
+       struct dentry           *debugfs_dir;
+#endif
 };
 
 struct blk_mq_tag_set {
index 83d28623645f33f0b54596116905012bcc800826..b49a79a29e58c39183f00146964917d4314a9f58 100644 (file)
@@ -579,7 +579,6 @@ struct request_queue {
 
 #ifdef CONFIG_BLK_DEBUG_FS
        struct dentry           *debugfs_dir;
-       struct dentry           *mq_debugfs_dir;
 #endif
 
        bool                    mq_sysfs_init_done;