diff options
author | Ming Lei <ming.lei@redhat.com> | 2018-12-16 20:46:00 -0500 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-12-16 21:53:47 -0500 |
commit | cc56694f132a8f5fa9334e3afe990de8c3378866 (patch) | |
tree | c67715ced5609fdcd34e95c3dcc24e6bc8ae494a | |
parent | f9824952ee1cd02ae1a74e35e0e8653f8a4db772 (diff) |
blk-mq-debugfs: support rq_qos
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>
-rw-r--r-- | block/blk-mq-debugfs.c | 54 | ||||
-rw-r--r-- | block/blk-mq-debugfs.h | 17 | ||||
-rw-r--r-- | block/blk-rq-qos.c | 2 | ||||
-rw-r--r-- | block/blk-rq-qos.h | 24 | ||||
-rw-r--r-- | include/linux/blkdev.h | 1 |
5 files changed, 98 insertions, 0 deletions
diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c index a32bb79d6c95..2793e91bc7a4 100644 --- a/block/blk-mq-debugfs.c +++ b/block/blk-mq-debugfs.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "blk-mq.h" | 23 | #include "blk-mq.h" |
24 | #include "blk-mq-debugfs.h" | 24 | #include "blk-mq-debugfs.h" |
25 | #include "blk-mq-tag.h" | 25 | #include "blk-mq-tag.h" |
26 | #include "blk-rq-qos.h" | ||
26 | 27 | ||
27 | static void print_stat(struct seq_file *m, struct blk_rq_stat *stat) | 28 | static void print_stat(struct seq_file *m, struct blk_rq_stat *stat) |
28 | { | 29 | { |
@@ -856,6 +857,15 @@ int blk_mq_debugfs_register(struct request_queue *q) | |||
856 | goto err; | 857 | goto err; |
857 | } | 858 | } |
858 | 859 | ||
860 | if (q->rq_qos) { | ||
861 | struct rq_qos *rqos = q->rq_qos; | ||
862 | |||
863 | while (rqos) { | ||
864 | blk_mq_debugfs_register_rqos(rqos); | ||
865 | rqos = rqos->next; | ||
866 | } | ||
867 | } | ||
868 | |||
859 | return 0; | 869 | return 0; |
860 | 870 | ||
861 | err: | 871 | err: |
@@ -978,6 +988,50 @@ void blk_mq_debugfs_unregister_sched(struct request_queue *q) | |||
978 | q->sched_debugfs_dir = NULL; | 988 | q->sched_debugfs_dir = NULL; |
979 | } | 989 | } |
980 | 990 | ||
991 | void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos) | ||
992 | { | ||
993 | debugfs_remove_recursive(rqos->debugfs_dir); | ||
994 | rqos->debugfs_dir = NULL; | ||
995 | } | ||
996 | |||
997 | int blk_mq_debugfs_register_rqos(struct rq_qos *rqos) | ||
998 | { | ||
999 | struct request_queue *q = rqos->q; | ||
1000 | const char *dir_name = rq_qos_id_to_name(rqos->id); | ||
1001 | |||
1002 | if (!q->debugfs_dir) | ||
1003 | return -ENOENT; | ||
1004 | |||
1005 | if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs) | ||
1006 | return 0; | ||
1007 | |||
1008 | if (!q->rqos_debugfs_dir) { | ||
1009 | q->rqos_debugfs_dir = debugfs_create_dir("rqos", | ||
1010 | q->debugfs_dir); | ||
1011 | if (!q->rqos_debugfs_dir) | ||
1012 | return -ENOMEM; | ||
1013 | } | ||
1014 | |||
1015 | rqos->debugfs_dir = debugfs_create_dir(dir_name, | ||
1016 | rqos->q->rqos_debugfs_dir); | ||
1017 | if (!rqos->debugfs_dir) | ||
1018 | return -ENOMEM; | ||
1019 | |||
1020 | if (!debugfs_create_files(rqos->debugfs_dir, rqos, | ||
1021 | rqos->ops->debugfs_attrs)) | ||
1022 | goto err; | ||
1023 | return 0; | ||
1024 | err: | ||
1025 | blk_mq_debugfs_unregister_rqos(rqos); | ||
1026 | return -ENOMEM; | ||
1027 | } | ||
1028 | |||
1029 | void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q) | ||
1030 | { | ||
1031 | debugfs_remove_recursive(q->rqos_debugfs_dir); | ||
1032 | q->rqos_debugfs_dir = NULL; | ||
1033 | } | ||
1034 | |||
981 | int blk_mq_debugfs_register_sched_hctx(struct request_queue *q, | 1035 | int blk_mq_debugfs_register_sched_hctx(struct request_queue *q, |
982 | struct blk_mq_hw_ctx *hctx) | 1036 | struct blk_mq_hw_ctx *hctx) |
983 | { | 1037 | { |
diff --git a/block/blk-mq-debugfs.h b/block/blk-mq-debugfs.h index a9160be12be0..8c9012a578c1 100644 --- a/block/blk-mq-debugfs.h +++ b/block/blk-mq-debugfs.h | |||
@@ -31,6 +31,10 @@ void blk_mq_debugfs_unregister_sched(struct request_queue *q); | |||
31 | int blk_mq_debugfs_register_sched_hctx(struct request_queue *q, | 31 | int blk_mq_debugfs_register_sched_hctx(struct request_queue *q, |
32 | struct blk_mq_hw_ctx *hctx); | 32 | struct blk_mq_hw_ctx *hctx); |
33 | void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx); | 33 | void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx); |
34 | |||
35 | int blk_mq_debugfs_register_rqos(struct rq_qos *rqos); | ||
36 | void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos); | ||
37 | void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q); | ||
34 | #else | 38 | #else |
35 | static inline int blk_mq_debugfs_register(struct request_queue *q) | 39 | static inline int blk_mq_debugfs_register(struct request_queue *q) |
36 | { | 40 | { |
@@ -78,6 +82,19 @@ static inline int blk_mq_debugfs_register_sched_hctx(struct request_queue *q, | |||
78 | static inline void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx) | 82 | static inline void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx) |
79 | { | 83 | { |
80 | } | 84 | } |
85 | |||
86 | static inline int blk_mq_debugfs_register_rqos(struct rq_qos *rqos) | ||
87 | { | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static inline void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos) | ||
92 | { | ||
93 | } | ||
94 | |||
95 | static inline void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q) | ||
96 | { | ||
97 | } | ||
81 | #endif | 98 | #endif |
82 | 99 | ||
83 | #ifdef CONFIG_BLK_DEBUG_FS_ZONED | 100 | #ifdef CONFIG_BLK_DEBUG_FS_ZONED |
diff --git a/block/blk-rq-qos.c b/block/blk-rq-qos.c index e932ef9d2718..d169d7188fa6 100644 --- a/block/blk-rq-qos.c +++ b/block/blk-rq-qos.c | |||
@@ -264,6 +264,8 @@ void rq_qos_wait(struct rq_wait *rqw, void *private_data, | |||
264 | 264 | ||
265 | void rq_qos_exit(struct request_queue *q) | 265 | void rq_qos_exit(struct request_queue *q) |
266 | { | 266 | { |
267 | blk_mq_debugfs_unregister_queue_rqos(q); | ||
268 | |||
267 | while (q->rq_qos) { | 269 | while (q->rq_qos) { |
268 | struct rq_qos *rqos = q->rq_qos; | 270 | struct rq_qos *rqos = q->rq_qos; |
269 | q->rq_qos = rqos->next; | 271 | q->rq_qos = rqos->next; |
diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h index 8678875de420..3c85f26d3846 100644 --- a/block/blk-rq-qos.h +++ b/block/blk-rq-qos.h | |||
@@ -7,6 +7,10 @@ | |||
7 | #include <linux/atomic.h> | 7 | #include <linux/atomic.h> |
8 | #include <linux/wait.h> | 8 | #include <linux/wait.h> |
9 | 9 | ||
10 | #include "blk-mq-debugfs.h" | ||
11 | |||
12 | struct blk_mq_debugfs_attr; | ||
13 | |||
10 | enum rq_qos_id { | 14 | enum rq_qos_id { |
11 | RQ_QOS_WBT, | 15 | RQ_QOS_WBT, |
12 | RQ_QOS_CGROUP, | 16 | RQ_QOS_CGROUP, |
@@ -22,6 +26,9 @@ struct rq_qos { | |||
22 | struct request_queue *q; | 26 | struct request_queue *q; |
23 | enum rq_qos_id id; | 27 | enum rq_qos_id id; |
24 | struct rq_qos *next; | 28 | struct rq_qos *next; |
29 | #ifdef CONFIG_BLK_DEBUG_FS | ||
30 | struct dentry *debugfs_dir; | ||
31 | #endif | ||
25 | }; | 32 | }; |
26 | 33 | ||
27 | struct rq_qos_ops { | 34 | struct rq_qos_ops { |
@@ -33,6 +40,7 @@ struct rq_qos_ops { | |||
33 | void (*done_bio)(struct rq_qos *, struct bio *); | 40 | void (*done_bio)(struct rq_qos *, struct bio *); |
34 | void (*cleanup)(struct rq_qos *, struct bio *); | 41 | void (*cleanup)(struct rq_qos *, struct bio *); |
35 | void (*exit)(struct rq_qos *); | 42 | void (*exit)(struct rq_qos *); |
43 | const struct blk_mq_debugfs_attr *debugfs_attrs; | ||
36 | }; | 44 | }; |
37 | 45 | ||
38 | struct rq_depth { | 46 | struct rq_depth { |
@@ -66,6 +74,17 @@ static inline struct rq_qos *blkcg_rq_qos(struct request_queue *q) | |||
66 | return rq_qos_id(q, RQ_QOS_CGROUP); | 74 | return rq_qos_id(q, RQ_QOS_CGROUP); |
67 | } | 75 | } |
68 | 76 | ||
77 | static inline const char *rq_qos_id_to_name(enum rq_qos_id id) | ||
78 | { | ||
79 | switch (id) { | ||
80 | case RQ_QOS_WBT: | ||
81 | return "wbt"; | ||
82 | case RQ_QOS_CGROUP: | ||
83 | return "cgroup"; | ||
84 | } | ||
85 | return "unknown"; | ||
86 | } | ||
87 | |||
69 | static inline void rq_wait_init(struct rq_wait *rq_wait) | 88 | static inline void rq_wait_init(struct rq_wait *rq_wait) |
70 | { | 89 | { |
71 | atomic_set(&rq_wait->inflight, 0); | 90 | atomic_set(&rq_wait->inflight, 0); |
@@ -76,6 +95,9 @@ static inline void rq_qos_add(struct request_queue *q, struct rq_qos *rqos) | |||
76 | { | 95 | { |
77 | rqos->next = q->rq_qos; | 96 | rqos->next = q->rq_qos; |
78 | q->rq_qos = rqos; | 97 | q->rq_qos = rqos; |
98 | |||
99 | if (rqos->ops->debugfs_attrs) | ||
100 | blk_mq_debugfs_register_rqos(rqos); | ||
79 | } | 101 | } |
80 | 102 | ||
81 | static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos) | 103 | 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) | |||
91 | } | 113 | } |
92 | prev = cur; | 114 | prev = cur; |
93 | } | 115 | } |
116 | |||
117 | blk_mq_debugfs_unregister_rqos(rqos); | ||
94 | } | 118 | } |
95 | 119 | ||
96 | typedef bool (acquire_inflight_cb_t)(struct rq_wait *rqw, void *private_data); | 120 | typedef bool (acquire_inflight_cb_t)(struct rq_wait *rqw, void *private_data); |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 81f1b105946b..45552e6eae1e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -560,6 +560,7 @@ struct request_queue { | |||
560 | #ifdef CONFIG_BLK_DEBUG_FS | 560 | #ifdef CONFIG_BLK_DEBUG_FS |
561 | struct dentry *debugfs_dir; | 561 | struct dentry *debugfs_dir; |
562 | struct dentry *sched_debugfs_dir; | 562 | struct dentry *sched_debugfs_dir; |
563 | struct dentry *rqos_debugfs_dir; | ||
563 | #endif | 564 | #endif |
564 | 565 | ||
565 | bool mq_sysfs_init_done; | 566 | bool mq_sysfs_init_done; |