xref: /linux/block/blk-mq-debugfs.c (revision 950cd7e9ffdc44c340b8914126b39cc079f0c844)
107e4feadSOmar Sandoval /*
207e4feadSOmar Sandoval  * Copyright (C) 2017 Facebook
307e4feadSOmar Sandoval  *
407e4feadSOmar Sandoval  * This program is free software; you can redistribute it and/or
507e4feadSOmar Sandoval  * modify it under the terms of the GNU General Public
607e4feadSOmar Sandoval  * License v2 as published by the Free Software Foundation.
707e4feadSOmar Sandoval  *
807e4feadSOmar Sandoval  * This program is distributed in the hope that it will be useful,
907e4feadSOmar Sandoval  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1007e4feadSOmar Sandoval  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1107e4feadSOmar Sandoval  * General Public License for more details.
1207e4feadSOmar Sandoval  *
1307e4feadSOmar Sandoval  * You should have received a copy of the GNU General Public License
1407e4feadSOmar Sandoval  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
1507e4feadSOmar Sandoval  */
1607e4feadSOmar Sandoval 
1707e4feadSOmar Sandoval #include <linux/kernel.h>
1807e4feadSOmar Sandoval #include <linux/blkdev.h>
1907e4feadSOmar Sandoval #include <linux/debugfs.h>
2007e4feadSOmar Sandoval 
2107e4feadSOmar Sandoval #include <linux/blk-mq.h>
2207e4feadSOmar Sandoval #include "blk-mq.h"
2307e4feadSOmar Sandoval 
2407e4feadSOmar Sandoval struct blk_mq_debugfs_attr {
2507e4feadSOmar Sandoval 	const char *name;
2607e4feadSOmar Sandoval 	umode_t mode;
2707e4feadSOmar Sandoval 	const struct file_operations *fops;
2807e4feadSOmar Sandoval };
2907e4feadSOmar Sandoval 
3007e4feadSOmar Sandoval static struct dentry *block_debugfs_root;
3107e4feadSOmar Sandoval 
32*950cd7e9SOmar Sandoval static int blk_mq_debugfs_seq_open(struct inode *inode, struct file *file,
33*950cd7e9SOmar Sandoval 				   const struct seq_operations *ops)
34*950cd7e9SOmar Sandoval {
35*950cd7e9SOmar Sandoval 	struct seq_file *m;
36*950cd7e9SOmar Sandoval 	int ret;
37*950cd7e9SOmar Sandoval 
38*950cd7e9SOmar Sandoval 	ret = seq_open(file, ops);
39*950cd7e9SOmar Sandoval 	if (!ret) {
40*950cd7e9SOmar Sandoval 		m = file->private_data;
41*950cd7e9SOmar Sandoval 		m->private = inode->i_private;
42*950cd7e9SOmar Sandoval 	}
43*950cd7e9SOmar Sandoval 	return ret;
44*950cd7e9SOmar Sandoval }
45*950cd7e9SOmar Sandoval 
469abb2ad2SOmar Sandoval static int hctx_state_show(struct seq_file *m, void *v)
479abb2ad2SOmar Sandoval {
489abb2ad2SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
499abb2ad2SOmar Sandoval 
509abb2ad2SOmar Sandoval 	seq_printf(m, "0x%lx\n", hctx->state);
519abb2ad2SOmar Sandoval 	return 0;
529abb2ad2SOmar Sandoval }
539abb2ad2SOmar Sandoval 
549abb2ad2SOmar Sandoval static int hctx_state_open(struct inode *inode, struct file *file)
559abb2ad2SOmar Sandoval {
569abb2ad2SOmar Sandoval 	return single_open(file, hctx_state_show, inode->i_private);
579abb2ad2SOmar Sandoval }
589abb2ad2SOmar Sandoval 
599abb2ad2SOmar Sandoval static const struct file_operations hctx_state_fops = {
609abb2ad2SOmar Sandoval 	.open		= hctx_state_open,
619abb2ad2SOmar Sandoval 	.read		= seq_read,
629abb2ad2SOmar Sandoval 	.llseek		= seq_lseek,
639abb2ad2SOmar Sandoval 	.release	= single_release,
649abb2ad2SOmar Sandoval };
659abb2ad2SOmar Sandoval 
669abb2ad2SOmar Sandoval static int hctx_flags_show(struct seq_file *m, void *v)
679abb2ad2SOmar Sandoval {
689abb2ad2SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
699abb2ad2SOmar Sandoval 
709abb2ad2SOmar Sandoval 	seq_printf(m, "0x%lx\n", hctx->flags);
719abb2ad2SOmar Sandoval 	return 0;
729abb2ad2SOmar Sandoval }
739abb2ad2SOmar Sandoval 
749abb2ad2SOmar Sandoval static int hctx_flags_open(struct inode *inode, struct file *file)
759abb2ad2SOmar Sandoval {
769abb2ad2SOmar Sandoval 	return single_open(file, hctx_flags_show, inode->i_private);
779abb2ad2SOmar Sandoval }
789abb2ad2SOmar Sandoval 
799abb2ad2SOmar Sandoval static const struct file_operations hctx_flags_fops = {
809abb2ad2SOmar Sandoval 	.open		= hctx_flags_open,
819abb2ad2SOmar Sandoval 	.read		= seq_read,
829abb2ad2SOmar Sandoval 	.llseek		= seq_lseek,
839abb2ad2SOmar Sandoval 	.release	= single_release,
849abb2ad2SOmar Sandoval };
859abb2ad2SOmar Sandoval 
86*950cd7e9SOmar Sandoval static int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
87*950cd7e9SOmar Sandoval {
88*950cd7e9SOmar Sandoval 	struct request *rq = list_entry_rq(v);
89*950cd7e9SOmar Sandoval 
90*950cd7e9SOmar Sandoval 	seq_printf(m, "%p\n", rq);
91*950cd7e9SOmar Sandoval 	return 0;
92*950cd7e9SOmar Sandoval }
93*950cd7e9SOmar Sandoval 
94*950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos)
95*950cd7e9SOmar Sandoval {
96*950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
97*950cd7e9SOmar Sandoval 
98*950cd7e9SOmar Sandoval 	spin_lock(&hctx->lock);
99*950cd7e9SOmar Sandoval 	return seq_list_start(&hctx->dispatch, *pos);
100*950cd7e9SOmar Sandoval }
101*950cd7e9SOmar Sandoval 
102*950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos)
103*950cd7e9SOmar Sandoval {
104*950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
105*950cd7e9SOmar Sandoval 
106*950cd7e9SOmar Sandoval 	return seq_list_next(v, &hctx->dispatch, pos);
107*950cd7e9SOmar Sandoval }
108*950cd7e9SOmar Sandoval 
109*950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v)
110*950cd7e9SOmar Sandoval {
111*950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
112*950cd7e9SOmar Sandoval 
113*950cd7e9SOmar Sandoval 	spin_unlock(&hctx->lock);
114*950cd7e9SOmar Sandoval }
115*950cd7e9SOmar Sandoval 
116*950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = {
117*950cd7e9SOmar Sandoval 	.start	= hctx_dispatch_start,
118*950cd7e9SOmar Sandoval 	.next	= hctx_dispatch_next,
119*950cd7e9SOmar Sandoval 	.stop	= hctx_dispatch_stop,
120*950cd7e9SOmar Sandoval 	.show	= blk_mq_debugfs_rq_show,
121*950cd7e9SOmar Sandoval };
122*950cd7e9SOmar Sandoval 
123*950cd7e9SOmar Sandoval static int hctx_dispatch_open(struct inode *inode, struct file *file)
124*950cd7e9SOmar Sandoval {
125*950cd7e9SOmar Sandoval 	return blk_mq_debugfs_seq_open(inode, file, &hctx_dispatch_seq_ops);
126*950cd7e9SOmar Sandoval }
127*950cd7e9SOmar Sandoval 
128*950cd7e9SOmar Sandoval static const struct file_operations hctx_dispatch_fops = {
129*950cd7e9SOmar Sandoval 	.open		= hctx_dispatch_open,
130*950cd7e9SOmar Sandoval 	.read		= seq_read,
131*950cd7e9SOmar Sandoval 	.llseek		= seq_lseek,
132*950cd7e9SOmar Sandoval 	.release	= seq_release,
133*950cd7e9SOmar Sandoval };
134*950cd7e9SOmar Sandoval 
135*950cd7e9SOmar Sandoval static void *ctx_rq_list_start(struct seq_file *m, loff_t *pos)
136*950cd7e9SOmar Sandoval {
137*950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
138*950cd7e9SOmar Sandoval 
139*950cd7e9SOmar Sandoval 	spin_lock(&ctx->lock);
140*950cd7e9SOmar Sandoval 	return seq_list_start(&ctx->rq_list, *pos);
141*950cd7e9SOmar Sandoval }
142*950cd7e9SOmar Sandoval 
143*950cd7e9SOmar Sandoval static void *ctx_rq_list_next(struct seq_file *m, void *v, loff_t *pos)
144*950cd7e9SOmar Sandoval {
145*950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
146*950cd7e9SOmar Sandoval 
147*950cd7e9SOmar Sandoval 	return seq_list_next(v, &ctx->rq_list, pos);
148*950cd7e9SOmar Sandoval }
149*950cd7e9SOmar Sandoval 
150*950cd7e9SOmar Sandoval static void ctx_rq_list_stop(struct seq_file *m, void *v)
151*950cd7e9SOmar Sandoval {
152*950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
153*950cd7e9SOmar Sandoval 
154*950cd7e9SOmar Sandoval 	spin_unlock(&ctx->lock);
155*950cd7e9SOmar Sandoval }
156*950cd7e9SOmar Sandoval 
157*950cd7e9SOmar Sandoval static const struct seq_operations ctx_rq_list_seq_ops = {
158*950cd7e9SOmar Sandoval 	.start	= ctx_rq_list_start,
159*950cd7e9SOmar Sandoval 	.next	= ctx_rq_list_next,
160*950cd7e9SOmar Sandoval 	.stop	= ctx_rq_list_stop,
161*950cd7e9SOmar Sandoval 	.show	= blk_mq_debugfs_rq_show,
162*950cd7e9SOmar Sandoval };
163*950cd7e9SOmar Sandoval 
164*950cd7e9SOmar Sandoval static int ctx_rq_list_open(struct inode *inode, struct file *file)
165*950cd7e9SOmar Sandoval {
166*950cd7e9SOmar Sandoval 	return blk_mq_debugfs_seq_open(inode, file, &ctx_rq_list_seq_ops);
167*950cd7e9SOmar Sandoval }
168*950cd7e9SOmar Sandoval 
169*950cd7e9SOmar Sandoval static const struct file_operations ctx_rq_list_fops = {
170*950cd7e9SOmar Sandoval 	.open		= ctx_rq_list_open,
171*950cd7e9SOmar Sandoval 	.read		= seq_read,
172*950cd7e9SOmar Sandoval 	.llseek		= seq_lseek,
173*950cd7e9SOmar Sandoval 	.release	= seq_release,
174*950cd7e9SOmar Sandoval };
175*950cd7e9SOmar Sandoval 
17607e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = {
1779abb2ad2SOmar Sandoval 	{"state", 0400, &hctx_state_fops},
1789abb2ad2SOmar Sandoval 	{"flags", 0400, &hctx_flags_fops},
179*950cd7e9SOmar Sandoval 	{"dispatch", 0400, &hctx_dispatch_fops},
18007e4feadSOmar Sandoval };
18107e4feadSOmar Sandoval 
18207e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = {
183*950cd7e9SOmar Sandoval 	{"rq_list", 0400, &ctx_rq_list_fops},
18407e4feadSOmar Sandoval };
18507e4feadSOmar Sandoval 
18607e4feadSOmar Sandoval int blk_mq_debugfs_register(struct request_queue *q, const char *name)
18707e4feadSOmar Sandoval {
18807e4feadSOmar Sandoval 	if (!block_debugfs_root)
18907e4feadSOmar Sandoval 		return -ENOENT;
19007e4feadSOmar Sandoval 
19107e4feadSOmar Sandoval 	q->debugfs_dir = debugfs_create_dir(name, block_debugfs_root);
19207e4feadSOmar Sandoval 	if (!q->debugfs_dir)
19307e4feadSOmar Sandoval 		goto err;
19407e4feadSOmar Sandoval 
19507e4feadSOmar Sandoval 	if (blk_mq_debugfs_register_hctxs(q))
19607e4feadSOmar Sandoval 		goto err;
19707e4feadSOmar Sandoval 
19807e4feadSOmar Sandoval 	return 0;
19907e4feadSOmar Sandoval 
20007e4feadSOmar Sandoval err:
20107e4feadSOmar Sandoval 	blk_mq_debugfs_unregister(q);
20207e4feadSOmar Sandoval 	return -ENOMEM;
20307e4feadSOmar Sandoval }
20407e4feadSOmar Sandoval 
20507e4feadSOmar Sandoval void blk_mq_debugfs_unregister(struct request_queue *q)
20607e4feadSOmar Sandoval {
20707e4feadSOmar Sandoval 	debugfs_remove_recursive(q->debugfs_dir);
20807e4feadSOmar Sandoval 	q->mq_debugfs_dir = NULL;
20907e4feadSOmar Sandoval 	q->debugfs_dir = NULL;
21007e4feadSOmar Sandoval }
21107e4feadSOmar Sandoval 
21207e4feadSOmar Sandoval static int blk_mq_debugfs_register_ctx(struct request_queue *q,
21307e4feadSOmar Sandoval 				       struct blk_mq_ctx *ctx,
21407e4feadSOmar Sandoval 				       struct dentry *hctx_dir)
21507e4feadSOmar Sandoval {
21607e4feadSOmar Sandoval 	struct dentry *ctx_dir;
21707e4feadSOmar Sandoval 	char name[20];
21807e4feadSOmar Sandoval 	int i;
21907e4feadSOmar Sandoval 
22007e4feadSOmar Sandoval 	snprintf(name, sizeof(name), "cpu%u", ctx->cpu);
22107e4feadSOmar Sandoval 	ctx_dir = debugfs_create_dir(name, hctx_dir);
22207e4feadSOmar Sandoval 	if (!ctx_dir)
22307e4feadSOmar Sandoval 		return -ENOMEM;
22407e4feadSOmar Sandoval 
22507e4feadSOmar Sandoval 	for (i = 0; i < ARRAY_SIZE(blk_mq_debugfs_ctx_attrs); i++) {
22607e4feadSOmar Sandoval 		const struct blk_mq_debugfs_attr *attr;
22707e4feadSOmar Sandoval 
22807e4feadSOmar Sandoval 		attr = &blk_mq_debugfs_ctx_attrs[i];
22907e4feadSOmar Sandoval 		if (!debugfs_create_file(attr->name, attr->mode, ctx_dir, ctx,
23007e4feadSOmar Sandoval 					 attr->fops))
23107e4feadSOmar Sandoval 			return -ENOMEM;
23207e4feadSOmar Sandoval 	}
23307e4feadSOmar Sandoval 
23407e4feadSOmar Sandoval 	return 0;
23507e4feadSOmar Sandoval }
23607e4feadSOmar Sandoval 
23707e4feadSOmar Sandoval static int blk_mq_debugfs_register_hctx(struct request_queue *q,
23807e4feadSOmar Sandoval 					struct blk_mq_hw_ctx *hctx)
23907e4feadSOmar Sandoval {
24007e4feadSOmar Sandoval 	struct blk_mq_ctx *ctx;
24107e4feadSOmar Sandoval 	struct dentry *hctx_dir;
24207e4feadSOmar Sandoval 	char name[20];
24307e4feadSOmar Sandoval 	int i;
24407e4feadSOmar Sandoval 
24507e4feadSOmar Sandoval 	snprintf(name, sizeof(name), "%u", hctx->queue_num);
24607e4feadSOmar Sandoval 	hctx_dir = debugfs_create_dir(name, q->mq_debugfs_dir);
24707e4feadSOmar Sandoval 	if (!hctx_dir)
24807e4feadSOmar Sandoval 		return -ENOMEM;
24907e4feadSOmar Sandoval 
25007e4feadSOmar Sandoval 	for (i = 0; i < ARRAY_SIZE(blk_mq_debugfs_hctx_attrs); i++) {
25107e4feadSOmar Sandoval 		const struct blk_mq_debugfs_attr *attr;
25207e4feadSOmar Sandoval 
25307e4feadSOmar Sandoval 		attr = &blk_mq_debugfs_hctx_attrs[i];
25407e4feadSOmar Sandoval 		if (!debugfs_create_file(attr->name, attr->mode, hctx_dir, hctx,
25507e4feadSOmar Sandoval 					 attr->fops))
25607e4feadSOmar Sandoval 			return -ENOMEM;
25707e4feadSOmar Sandoval 	}
25807e4feadSOmar Sandoval 
25907e4feadSOmar Sandoval 	hctx_for_each_ctx(hctx, ctx, i) {
26007e4feadSOmar Sandoval 		if (blk_mq_debugfs_register_ctx(q, ctx, hctx_dir))
26107e4feadSOmar Sandoval 			return -ENOMEM;
26207e4feadSOmar Sandoval 	}
26307e4feadSOmar Sandoval 
26407e4feadSOmar Sandoval 	return 0;
26507e4feadSOmar Sandoval }
26607e4feadSOmar Sandoval 
26707e4feadSOmar Sandoval int blk_mq_debugfs_register_hctxs(struct request_queue *q)
26807e4feadSOmar Sandoval {
26907e4feadSOmar Sandoval 	struct blk_mq_hw_ctx *hctx;
27007e4feadSOmar Sandoval 	int i;
27107e4feadSOmar Sandoval 
27207e4feadSOmar Sandoval 	if (!q->debugfs_dir)
27307e4feadSOmar Sandoval 		return -ENOENT;
27407e4feadSOmar Sandoval 
27507e4feadSOmar Sandoval 	q->mq_debugfs_dir = debugfs_create_dir("mq", q->debugfs_dir);
27607e4feadSOmar Sandoval 	if (!q->mq_debugfs_dir)
27707e4feadSOmar Sandoval 		goto err;
27807e4feadSOmar Sandoval 
27907e4feadSOmar Sandoval 	queue_for_each_hw_ctx(q, hctx, i) {
28007e4feadSOmar Sandoval 		if (blk_mq_debugfs_register_hctx(q, hctx))
28107e4feadSOmar Sandoval 			goto err;
28207e4feadSOmar Sandoval 	}
28307e4feadSOmar Sandoval 
28407e4feadSOmar Sandoval 	return 0;
28507e4feadSOmar Sandoval 
28607e4feadSOmar Sandoval err:
28707e4feadSOmar Sandoval 	blk_mq_debugfs_unregister_hctxs(q);
28807e4feadSOmar Sandoval 	return -ENOMEM;
28907e4feadSOmar Sandoval }
29007e4feadSOmar Sandoval 
29107e4feadSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
29207e4feadSOmar Sandoval {
29307e4feadSOmar Sandoval 	debugfs_remove_recursive(q->mq_debugfs_dir);
29407e4feadSOmar Sandoval 	q->mq_debugfs_dir = NULL;
29507e4feadSOmar Sandoval }
29607e4feadSOmar Sandoval 
29707e4feadSOmar Sandoval void blk_mq_debugfs_init(void)
29807e4feadSOmar Sandoval {
29907e4feadSOmar Sandoval 	block_debugfs_root = debugfs_create_dir("block", NULL);
30007e4feadSOmar Sandoval }
301