blk-mq-debugfs: support rq_qos
authorMing Lei <ming.lei@redhat.com>
Mon, 17 Dec 2018 01:46:00 +0000 (09:46 +0800)
committerJens Axboe <axboe@kernel.dk>
Mon, 17 Dec 2018 02:53:47 +0000 (19:53 -0700)
blk-mq-debugfs has been proved as very helpful for debug some
tough issues, such as IO hang.

We have seen blk-wbt related IO hang several times, even inside
Red Hat BZ, there is such report not sovled yet, so this patch
adds support debugfs on rq_qos.

Cc: Bart Van Assche <bart.vanassche@wdc.com>
Cc: Omar Sandoval <osandov@fb.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-mq-debugfs.c
block/blk-mq-debugfs.h
block/blk-rq-qos.c
block/blk-rq-qos.h
include/linux/blkdev.h

index a32bb79d6c95de7aba70c58653b77eb0349e9409..2793e91bc7a42a74b2256e949b56a98c25f65a96 100644 (file)
@@ -23,6 +23,7 @@
 #include "blk-mq.h"
 #include "blk-mq-debugfs.h"
 #include "blk-mq-tag.h"
+#include "blk-rq-qos.h"
 
 static void print_stat(struct seq_file *m, struct blk_rq_stat *stat)
 {
@@ -856,6 +857,15 @@ int blk_mq_debugfs_register(struct request_queue *q)
                        goto err;
        }
 
+       if (q->rq_qos) {
+               struct rq_qos *rqos = q->rq_qos;
+
+               while (rqos) {
+                       blk_mq_debugfs_register_rqos(rqos);
+                       rqos = rqos->next;
+               }
+       }
+
        return 0;
 
 err:
@@ -978,6 +988,50 @@ void blk_mq_debugfs_unregister_sched(struct request_queue *q)
        q->sched_debugfs_dir = NULL;
 }
 
+void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos)
+{
+       debugfs_remove_recursive(rqos->debugfs_dir);
+       rqos->debugfs_dir = NULL;
+}
+
+int blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
+{
+       struct request_queue *q = rqos->q;
+       const char *dir_name = rq_qos_id_to_name(rqos->id);
+
+       if (!q->debugfs_dir)
+               return -ENOENT;
+
+       if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs)
+               return 0;
+
+       if (!q->rqos_debugfs_dir) {
+               q->rqos_debugfs_dir = debugfs_create_dir("rqos",
+                                                        q->debugfs_dir);
+               if (!q->rqos_debugfs_dir)
+                       return -ENOMEM;
+       }
+
+       rqos->debugfs_dir = debugfs_create_dir(dir_name,
+                                              rqos->q->rqos_debugfs_dir);
+       if (!rqos->debugfs_dir)
+               return -ENOMEM;
+
+       if (!debugfs_create_files(rqos->debugfs_dir, rqos,
+                                 rqos->ops->debugfs_attrs))
+               goto err;
+       return 0;
+ err:
+       blk_mq_debugfs_unregister_rqos(rqos);
+       return -ENOMEM;
+}
+
+void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q)
+{
+       debugfs_remove_recursive(q->rqos_debugfs_dir);
+       q->rqos_debugfs_dir = NULL;
+}
+
 int blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
                                       struct blk_mq_hw_ctx *hctx)
 {
index a9160be12be05a527c0d968a6534e4a244f989e1..8c9012a578c1228c74f48dda5abfb88a5fb621a5 100644 (file)
@@ -31,6 +31,10 @@ void blk_mq_debugfs_unregister_sched(struct request_queue *q);
 int blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
                                       struct blk_mq_hw_ctx *hctx);
 void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx);
+
+int blk_mq_debugfs_register_rqos(struct rq_qos *rqos);
+void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos);
+void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q);
 #else
 static inline int blk_mq_debugfs_register(struct request_queue *q)
 {
@@ -78,6 +82,19 @@ static inline int blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
 static inline void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx)
 {
 }
+
+static inline int blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
+{
+       return 0;
+}
+
+static inline void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos)
+{
+}
+
+static inline void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q)
+{
+}
 #endif
 
 #ifdef CONFIG_BLK_DEBUG_FS_ZONED
index e932ef9d27188150f31cdd3ed9a652b280b97f71..d169d7188fa6401df41857cde779f34ad453ad9e 100644 (file)
@@ -264,6 +264,8 @@ void rq_qos_wait(struct rq_wait *rqw, void *private_data,
 
 void rq_qos_exit(struct request_queue *q)
 {
+       blk_mq_debugfs_unregister_queue_rqos(q);
+
        while (q->rq_qos) {
                struct rq_qos *rqos = q->rq_qos;
                q->rq_qos = rqos->next;
index 8678875de420ee0bdf74e3683cffdd170465222c..3c85f26d38462d73df48994e8c875f30ade15c18 100644 (file)
@@ -7,6 +7,10 @@
 #include <linux/atomic.h>
 #include <linux/wait.h>
 
+#include "blk-mq-debugfs.h"
+
+struct blk_mq_debugfs_attr;
+
 enum rq_qos_id {
        RQ_QOS_WBT,
        RQ_QOS_CGROUP,
@@ -22,6 +26,9 @@ struct rq_qos {
        struct request_queue *q;
        enum rq_qos_id id;
        struct rq_qos *next;
+#ifdef CONFIG_BLK_DEBUG_FS
+       struct dentry *debugfs_dir;
+#endif
 };
 
 struct rq_qos_ops {
@@ -33,6 +40,7 @@ struct rq_qos_ops {
        void (*done_bio)(struct rq_qos *, struct bio *);
        void (*cleanup)(struct rq_qos *, struct bio *);
        void (*exit)(struct rq_qos *);
+       const struct blk_mq_debugfs_attr *debugfs_attrs;
 };
 
 struct rq_depth {
@@ -66,6 +74,17 @@ static inline struct rq_qos *blkcg_rq_qos(struct request_queue *q)
        return rq_qos_id(q, RQ_QOS_CGROUP);
 }
 
+static inline const char *rq_qos_id_to_name(enum rq_qos_id id)
+{
+       switch (id) {
+       case RQ_QOS_WBT:
+               return "wbt";
+       case RQ_QOS_CGROUP:
+               return "cgroup";
+       }
+       return "unknown";
+}
+
 static inline void rq_wait_init(struct rq_wait *rq_wait)
 {
        atomic_set(&rq_wait->inflight, 0);
@@ -76,6 +95,9 @@ static inline void rq_qos_add(struct request_queue *q, struct rq_qos *rqos)
 {
        rqos->next = q->rq_qos;
        q->rq_qos = rqos;
+
+       if (rqos->ops->debugfs_attrs)
+               blk_mq_debugfs_register_rqos(rqos);
 }
 
 static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos)
@@ -91,6 +113,8 @@ static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos)
                }
                prev = cur;
        }
+
+       blk_mq_debugfs_unregister_rqos(rqos);
 }
 
 typedef bool (acquire_inflight_cb_t)(struct rq_wait *rqw, void *private_data);
index 81f1b105946bc2a0a737c16620546677b3c80938..45552e6eae1e345a320ae0539cce1c28f744b9b7 100644 (file)
@@ -560,6 +560,7 @@ struct request_queue {
 #ifdef CONFIG_BLK_DEBUG_FS
        struct dentry           *debugfs_dir;
        struct dentry           *sched_debugfs_dir;
+       struct dentry           *rqos_debugfs_dir;
 #endif
 
        bool                    mq_sysfs_init_done;