2 * Copyright (C) 2017 Facebook
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 #include <linux/kernel.h>
18 #include <linux/blkdev.h>
19 #include <linux/debugfs.h>
21 #include <linux/blk-mq.h>
24 struct blk_mq_debugfs_attr
{
27 const struct file_operations
*fops
;
30 static struct dentry
*block_debugfs_root
;
32 static int hctx_state_show(struct seq_file
*m
, void *v
)
34 struct blk_mq_hw_ctx
*hctx
= m
->private;
36 seq_printf(m
, "0x%lx\n", hctx
->state
);
40 static int hctx_state_open(struct inode
*inode
, struct file
*file
)
42 return single_open(file
, hctx_state_show
, inode
->i_private
);
45 static const struct file_operations hctx_state_fops
= {
46 .open
= hctx_state_open
,
49 .release
= single_release
,
52 static int hctx_flags_show(struct seq_file
*m
, void *v
)
54 struct blk_mq_hw_ctx
*hctx
= m
->private;
56 seq_printf(m
, "0x%lx\n", hctx
->flags
);
60 static int hctx_flags_open(struct inode
*inode
, struct file
*file
)
62 return single_open(file
, hctx_flags_show
, inode
->i_private
);
65 static const struct file_operations hctx_flags_fops
= {
66 .open
= hctx_flags_open
,
69 .release
= single_release
,
72 static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs
[] = {
73 {"state", 0400, &hctx_state_fops
},
74 {"flags", 0400, &hctx_flags_fops
},
77 static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs
[] = {
80 int blk_mq_debugfs_register(struct request_queue
*q
, const char *name
)
82 if (!block_debugfs_root
)
85 q
->debugfs_dir
= debugfs_create_dir(name
, block_debugfs_root
);
89 if (blk_mq_debugfs_register_hctxs(q
))
95 blk_mq_debugfs_unregister(q
);
99 void blk_mq_debugfs_unregister(struct request_queue
*q
)
101 debugfs_remove_recursive(q
->debugfs_dir
);
102 q
->mq_debugfs_dir
= NULL
;
103 q
->debugfs_dir
= NULL
;
106 static int blk_mq_debugfs_register_ctx(struct request_queue
*q
,
107 struct blk_mq_ctx
*ctx
,
108 struct dentry
*hctx_dir
)
110 struct dentry
*ctx_dir
;
114 snprintf(name
, sizeof(name
), "cpu%u", ctx
->cpu
);
115 ctx_dir
= debugfs_create_dir(name
, hctx_dir
);
119 for (i
= 0; i
< ARRAY_SIZE(blk_mq_debugfs_ctx_attrs
); i
++) {
120 const struct blk_mq_debugfs_attr
*attr
;
122 attr
= &blk_mq_debugfs_ctx_attrs
[i
];
123 if (!debugfs_create_file(attr
->name
, attr
->mode
, ctx_dir
, ctx
,
131 static int blk_mq_debugfs_register_hctx(struct request_queue
*q
,
132 struct blk_mq_hw_ctx
*hctx
)
134 struct blk_mq_ctx
*ctx
;
135 struct dentry
*hctx_dir
;
139 snprintf(name
, sizeof(name
), "%u", hctx
->queue_num
);
140 hctx_dir
= debugfs_create_dir(name
, q
->mq_debugfs_dir
);
144 for (i
= 0; i
< ARRAY_SIZE(blk_mq_debugfs_hctx_attrs
); i
++) {
145 const struct blk_mq_debugfs_attr
*attr
;
147 attr
= &blk_mq_debugfs_hctx_attrs
[i
];
148 if (!debugfs_create_file(attr
->name
, attr
->mode
, hctx_dir
, hctx
,
153 hctx_for_each_ctx(hctx
, ctx
, i
) {
154 if (blk_mq_debugfs_register_ctx(q
, ctx
, hctx_dir
))
161 int blk_mq_debugfs_register_hctxs(struct request_queue
*q
)
163 struct blk_mq_hw_ctx
*hctx
;
169 q
->mq_debugfs_dir
= debugfs_create_dir("mq", q
->debugfs_dir
);
170 if (!q
->mq_debugfs_dir
)
173 queue_for_each_hw_ctx(q
, hctx
, i
) {
174 if (blk_mq_debugfs_register_hctx(q
, hctx
))
181 blk_mq_debugfs_unregister_hctxs(q
);
185 void blk_mq_debugfs_unregister_hctxs(struct request_queue
*q
)
187 debugfs_remove_recursive(q
->mq_debugfs_dir
);
188 q
->mq_debugfs_dir
= NULL
;
191 void blk_mq_debugfs_init(void)
193 block_debugfs_root
= debugfs_create_dir("block", NULL
);