]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - block/blk-mq-debugfs.c
Merge tag 'acpi-extra-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / block / blk-mq-debugfs.c
index 347fbb8e059cf3e3e45b5b8071fa529f94038835..803aed4d72216f5e23a585cb6d027115fa603ff9 100644 (file)
 #include <linux/blk-mq.h>
 #include "blk.h"
 #include "blk-mq.h"
+#include "blk-mq-debugfs.h"
 #include "blk-mq-tag.h"
 
-struct blk_mq_debugfs_attr {
-       const char *name;
-       umode_t mode;
-       int (*show)(void *, struct seq_file *);
-       ssize_t (*write)(void *, const char __user *, size_t, loff_t *);
-       /* Set either .show or .seq_ops. */
-       const struct seq_operations *seq_ops;
-};
-
 static int blk_flags_show(struct seq_file *m, const unsigned long flags,
                          const char *const *flag_name, int flag_name_count)
 {
@@ -275,9 +267,8 @@ static const char *const rqf_name[] = {
 };
 #undef RQF_NAME
 
-static int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
+int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq)
 {
-       struct request *rq = list_entry_rq(v);
        const struct blk_mq_ops *const mq_ops = rq->q->mq_ops;
        const unsigned int op = rq->cmd_flags & REQ_OP_MASK;
 
@@ -299,6 +290,13 @@ static int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
        seq_puts(m, "}\n");
        return 0;
 }
+EXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show);
+
+int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
+{
+       return __blk_mq_debugfs_rq_show(m, list_entry_rq(v));
+}
+EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show);
 
 static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos)
        __acquires(&hctx->lock)
@@ -686,19 +684,49 @@ 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;
+               if (q->elevator && !hctx->sched_debugfs_dir &&
+                   blk_mq_debugfs_register_sched_hctx(q, hctx))
+                       goto err;
+       }
+
        return 0;
 
 err:
@@ -709,32 +737,18 @@ err:
 void blk_mq_debugfs_unregister(struct request_queue *q)
 {
        debugfs_remove_recursive(q->debugfs_dir);
-       q->mq_debugfs_dir = NULL;
+       q->sched_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;
 
@@ -744,59 +758,122 @@ 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))
+               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->sched_debugfs_dir = NULL;
+       hctx->debugfs_dir = NULL;
+}
+
+int blk_mq_debugfs_register_hctxs(struct request_queue *q)
+{
+       struct blk_mq_hw_ctx *hctx;
+       int i;
+
+       queue_for_each_hw_ctx(q, hctx, i) {
+               if (blk_mq_debugfs_register_hctx(q, hctx))
                        return -ENOMEM;
        }
 
        return 0;
 }
 
-int blk_mq_debugfs_register_mq(struct request_queue *q)
+void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
 {
        struct blk_mq_hw_ctx *hctx;
        int i;
 
+       queue_for_each_hw_ctx(q, hctx, i)
+               blk_mq_debugfs_unregister_hctx(hctx);
+}
+
+int blk_mq_debugfs_register_sched(struct request_queue *q)
+{
+       struct elevator_type *e = q->elevator->type;
+
        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 (!e->queue_debugfs_attrs)
+               return 0;
 
-       if (!debugfs_create_files(q->mq_debugfs_dir, q, blk_mq_debugfs_queue_attrs))
-               goto err;
+       q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir);
+       if (!q->sched_debugfs_dir)
+               return -ENOMEM;
 
-       queue_for_each_hw_ctx(q, hctx, i) {
-               if (blk_mq_debugfs_register_hctx(q, hctx))
-                       goto err;
-       }
+       if (!debugfs_create_files(q->sched_debugfs_dir, q,
+                                 e->queue_debugfs_attrs))
+               goto err;
 
        return 0;
 
 err:
-       blk_mq_debugfs_unregister_mq(q);
+       blk_mq_debugfs_unregister_sched(q);
        return -ENOMEM;
 }
 
-void blk_mq_debugfs_unregister_mq(struct request_queue *q)
+void blk_mq_debugfs_unregister_sched(struct request_queue *q)
+{
+       debugfs_remove_recursive(q->sched_debugfs_dir);
+       q->sched_debugfs_dir = NULL;
+}
+
+int blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
+                                      struct blk_mq_hw_ctx *hctx)
+{
+       struct elevator_type *e = q->elevator->type;
+
+       if (!hctx->debugfs_dir)
+               return -ENOENT;
+
+       if (!e->hctx_debugfs_attrs)
+               return 0;
+
+       hctx->sched_debugfs_dir = debugfs_create_dir("sched",
+                                                    hctx->debugfs_dir);
+       if (!hctx->sched_debugfs_dir)
+               return -ENOMEM;
+
+       if (!debugfs_create_files(hctx->sched_debugfs_dir, hctx,
+                                 e->hctx_debugfs_attrs))
+               return -ENOMEM;
+
+       return 0;
+}
+
+void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx)
 {
-       debugfs_remove_recursive(q->mq_debugfs_dir);
-       q->mq_debugfs_dir = NULL;
+       debugfs_remove_recursive(hctx->sched_debugfs_dir);
+       hctx->sched_debugfs_dir = NULL;
 }