xref: /linux/block/blk-mq-debugfs.c (revision be21547318b2c7d9988237b106cc63767b86eae4)
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"
23d96b37c0SOmar Sandoval #include "blk-mq-tag.h"
2407e4feadSOmar Sandoval 
2507e4feadSOmar Sandoval struct blk_mq_debugfs_attr {
2607e4feadSOmar Sandoval 	const char *name;
2707e4feadSOmar Sandoval 	umode_t mode;
2807e4feadSOmar Sandoval 	const struct file_operations *fops;
2907e4feadSOmar Sandoval };
3007e4feadSOmar Sandoval 
3107e4feadSOmar Sandoval static struct dentry *block_debugfs_root;
3207e4feadSOmar Sandoval 
33950cd7e9SOmar Sandoval static int blk_mq_debugfs_seq_open(struct inode *inode, struct file *file,
34950cd7e9SOmar Sandoval 				   const struct seq_operations *ops)
35950cd7e9SOmar Sandoval {
36950cd7e9SOmar Sandoval 	struct seq_file *m;
37950cd7e9SOmar Sandoval 	int ret;
38950cd7e9SOmar Sandoval 
39950cd7e9SOmar Sandoval 	ret = seq_open(file, ops);
40950cd7e9SOmar Sandoval 	if (!ret) {
41950cd7e9SOmar Sandoval 		m = file->private_data;
42950cd7e9SOmar Sandoval 		m->private = inode->i_private;
43950cd7e9SOmar Sandoval 	}
44950cd7e9SOmar Sandoval 	return ret;
45950cd7e9SOmar Sandoval }
46950cd7e9SOmar Sandoval 
479abb2ad2SOmar Sandoval static int hctx_state_show(struct seq_file *m, void *v)
489abb2ad2SOmar Sandoval {
499abb2ad2SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
509abb2ad2SOmar Sandoval 
519abb2ad2SOmar Sandoval 	seq_printf(m, "0x%lx\n", hctx->state);
529abb2ad2SOmar Sandoval 	return 0;
539abb2ad2SOmar Sandoval }
549abb2ad2SOmar Sandoval 
559abb2ad2SOmar Sandoval static int hctx_state_open(struct inode *inode, struct file *file)
569abb2ad2SOmar Sandoval {
579abb2ad2SOmar Sandoval 	return single_open(file, hctx_state_show, inode->i_private);
589abb2ad2SOmar Sandoval }
599abb2ad2SOmar Sandoval 
609abb2ad2SOmar Sandoval static const struct file_operations hctx_state_fops = {
619abb2ad2SOmar Sandoval 	.open		= hctx_state_open,
629abb2ad2SOmar Sandoval 	.read		= seq_read,
639abb2ad2SOmar Sandoval 	.llseek		= seq_lseek,
649abb2ad2SOmar Sandoval 	.release	= single_release,
659abb2ad2SOmar Sandoval };
669abb2ad2SOmar Sandoval 
679abb2ad2SOmar Sandoval static int hctx_flags_show(struct seq_file *m, void *v)
689abb2ad2SOmar Sandoval {
699abb2ad2SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
709abb2ad2SOmar Sandoval 
719abb2ad2SOmar Sandoval 	seq_printf(m, "0x%lx\n", hctx->flags);
729abb2ad2SOmar Sandoval 	return 0;
739abb2ad2SOmar Sandoval }
749abb2ad2SOmar Sandoval 
759abb2ad2SOmar Sandoval static int hctx_flags_open(struct inode *inode, struct file *file)
769abb2ad2SOmar Sandoval {
779abb2ad2SOmar Sandoval 	return single_open(file, hctx_flags_show, inode->i_private);
789abb2ad2SOmar Sandoval }
799abb2ad2SOmar Sandoval 
809abb2ad2SOmar Sandoval static const struct file_operations hctx_flags_fops = {
819abb2ad2SOmar Sandoval 	.open		= hctx_flags_open,
829abb2ad2SOmar Sandoval 	.read		= seq_read,
839abb2ad2SOmar Sandoval 	.llseek		= seq_lseek,
849abb2ad2SOmar Sandoval 	.release	= single_release,
859abb2ad2SOmar Sandoval };
869abb2ad2SOmar Sandoval 
87950cd7e9SOmar Sandoval static int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
88950cd7e9SOmar Sandoval {
89950cd7e9SOmar Sandoval 	struct request *rq = list_entry_rq(v);
90950cd7e9SOmar Sandoval 
917b393852SOmar Sandoval 	seq_printf(m, "%p {.cmd_type=%u, .cmd_flags=0x%x, .rq_flags=0x%x, .tag=%d, .internal_tag=%d}\n",
927b393852SOmar Sandoval 		   rq, rq->cmd_type, rq->cmd_flags, (unsigned int)rq->rq_flags,
937b393852SOmar Sandoval 		   rq->tag, rq->internal_tag);
94950cd7e9SOmar Sandoval 	return 0;
95950cd7e9SOmar Sandoval }
96950cd7e9SOmar Sandoval 
97950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos)
98950cd7e9SOmar Sandoval {
99950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
100950cd7e9SOmar Sandoval 
101950cd7e9SOmar Sandoval 	spin_lock(&hctx->lock);
102950cd7e9SOmar Sandoval 	return seq_list_start(&hctx->dispatch, *pos);
103950cd7e9SOmar Sandoval }
104950cd7e9SOmar Sandoval 
105950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos)
106950cd7e9SOmar Sandoval {
107950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
108950cd7e9SOmar Sandoval 
109950cd7e9SOmar Sandoval 	return seq_list_next(v, &hctx->dispatch, pos);
110950cd7e9SOmar Sandoval }
111950cd7e9SOmar Sandoval 
112950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v)
113950cd7e9SOmar Sandoval {
114950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
115950cd7e9SOmar Sandoval 
116950cd7e9SOmar Sandoval 	spin_unlock(&hctx->lock);
117950cd7e9SOmar Sandoval }
118950cd7e9SOmar Sandoval 
119950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = {
120950cd7e9SOmar Sandoval 	.start	= hctx_dispatch_start,
121950cd7e9SOmar Sandoval 	.next	= hctx_dispatch_next,
122950cd7e9SOmar Sandoval 	.stop	= hctx_dispatch_stop,
123950cd7e9SOmar Sandoval 	.show	= blk_mq_debugfs_rq_show,
124950cd7e9SOmar Sandoval };
125950cd7e9SOmar Sandoval 
126950cd7e9SOmar Sandoval static int hctx_dispatch_open(struct inode *inode, struct file *file)
127950cd7e9SOmar Sandoval {
128950cd7e9SOmar Sandoval 	return blk_mq_debugfs_seq_open(inode, file, &hctx_dispatch_seq_ops);
129950cd7e9SOmar Sandoval }
130950cd7e9SOmar Sandoval 
131950cd7e9SOmar Sandoval static const struct file_operations hctx_dispatch_fops = {
132950cd7e9SOmar Sandoval 	.open		= hctx_dispatch_open,
133950cd7e9SOmar Sandoval 	.read		= seq_read,
134950cd7e9SOmar Sandoval 	.llseek		= seq_lseek,
135950cd7e9SOmar Sandoval 	.release	= seq_release,
136950cd7e9SOmar Sandoval };
137950cd7e9SOmar Sandoval 
1380bfa5288SOmar Sandoval static int hctx_ctx_map_show(struct seq_file *m, void *v)
1390bfa5288SOmar Sandoval {
1400bfa5288SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
1410bfa5288SOmar Sandoval 
1420bfa5288SOmar Sandoval 	sbitmap_bitmap_show(&hctx->ctx_map, m);
1430bfa5288SOmar Sandoval 	return 0;
1440bfa5288SOmar Sandoval }
1450bfa5288SOmar Sandoval 
1460bfa5288SOmar Sandoval static int hctx_ctx_map_open(struct inode *inode, struct file *file)
1470bfa5288SOmar Sandoval {
1480bfa5288SOmar Sandoval 	return single_open(file, hctx_ctx_map_show, inode->i_private);
1490bfa5288SOmar Sandoval }
1500bfa5288SOmar Sandoval 
1510bfa5288SOmar Sandoval static const struct file_operations hctx_ctx_map_fops = {
1520bfa5288SOmar Sandoval 	.open		= hctx_ctx_map_open,
1530bfa5288SOmar Sandoval 	.read		= seq_read,
1540bfa5288SOmar Sandoval 	.llseek		= seq_lseek,
1550bfa5288SOmar Sandoval 	.release	= single_release,
1560bfa5288SOmar Sandoval };
1570bfa5288SOmar Sandoval 
158d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m,
159d96b37c0SOmar Sandoval 				     struct blk_mq_tags *tags)
160d96b37c0SOmar Sandoval {
161d96b37c0SOmar Sandoval 	seq_printf(m, "nr_tags=%u\n", tags->nr_tags);
162d96b37c0SOmar Sandoval 	seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags);
163d96b37c0SOmar Sandoval 	seq_printf(m, "active_queues=%d\n",
164d96b37c0SOmar Sandoval 		   atomic_read(&tags->active_queues));
165d96b37c0SOmar Sandoval 
166d96b37c0SOmar Sandoval 	seq_puts(m, "\nbitmap_tags:\n");
167d96b37c0SOmar Sandoval 	sbitmap_queue_show(&tags->bitmap_tags, m);
168d96b37c0SOmar Sandoval 
169d96b37c0SOmar Sandoval 	if (tags->nr_reserved_tags) {
170d96b37c0SOmar Sandoval 		seq_puts(m, "\nbreserved_tags:\n");
171d96b37c0SOmar Sandoval 		sbitmap_queue_show(&tags->breserved_tags, m);
172d96b37c0SOmar Sandoval 	}
173d96b37c0SOmar Sandoval }
174d96b37c0SOmar Sandoval 
175d96b37c0SOmar Sandoval static int hctx_tags_show(struct seq_file *m, void *v)
176d96b37c0SOmar Sandoval {
177d96b37c0SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
178d96b37c0SOmar Sandoval 	struct request_queue *q = hctx->queue;
179d96b37c0SOmar Sandoval 
180d96b37c0SOmar Sandoval 	mutex_lock(&q->sysfs_lock);
181d96b37c0SOmar Sandoval 	if (hctx->tags)
182d96b37c0SOmar Sandoval 		blk_mq_debugfs_tags_show(m, hctx->tags);
183d96b37c0SOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
184d96b37c0SOmar Sandoval 
185d96b37c0SOmar Sandoval 	return 0;
186d96b37c0SOmar Sandoval }
187d96b37c0SOmar Sandoval 
188d96b37c0SOmar Sandoval static int hctx_tags_open(struct inode *inode, struct file *file)
189d96b37c0SOmar Sandoval {
190d96b37c0SOmar Sandoval 	return single_open(file, hctx_tags_show, inode->i_private);
191d96b37c0SOmar Sandoval }
192d96b37c0SOmar Sandoval 
193d96b37c0SOmar Sandoval static const struct file_operations hctx_tags_fops = {
194d96b37c0SOmar Sandoval 	.open		= hctx_tags_open,
195d96b37c0SOmar Sandoval 	.read		= seq_read,
196d96b37c0SOmar Sandoval 	.llseek		= seq_lseek,
197d96b37c0SOmar Sandoval 	.release	= single_release,
198d96b37c0SOmar Sandoval };
199d96b37c0SOmar Sandoval 
200d7e3621aSOmar Sandoval static int hctx_tags_bitmap_show(struct seq_file *m, void *v)
201d7e3621aSOmar Sandoval {
202d7e3621aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
203d7e3621aSOmar Sandoval 	struct request_queue *q = hctx->queue;
204d7e3621aSOmar Sandoval 
205d7e3621aSOmar Sandoval 	mutex_lock(&q->sysfs_lock);
206d7e3621aSOmar Sandoval 	if (hctx->tags)
207d7e3621aSOmar Sandoval 		sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m);
208d7e3621aSOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
209d7e3621aSOmar Sandoval 	return 0;
210d7e3621aSOmar Sandoval }
211d7e3621aSOmar Sandoval 
212d7e3621aSOmar Sandoval static int hctx_tags_bitmap_open(struct inode *inode, struct file *file)
213d7e3621aSOmar Sandoval {
214d7e3621aSOmar Sandoval 	return single_open(file, hctx_tags_bitmap_show, inode->i_private);
215d7e3621aSOmar Sandoval }
216d7e3621aSOmar Sandoval 
217d7e3621aSOmar Sandoval static const struct file_operations hctx_tags_bitmap_fops = {
218d7e3621aSOmar Sandoval 	.open		= hctx_tags_bitmap_open,
219d7e3621aSOmar Sandoval 	.read		= seq_read,
220d7e3621aSOmar Sandoval 	.llseek		= seq_lseek,
221d7e3621aSOmar Sandoval 	.release	= single_release,
222d7e3621aSOmar Sandoval };
223d7e3621aSOmar Sandoval 
224d96b37c0SOmar Sandoval static int hctx_sched_tags_show(struct seq_file *m, void *v)
225d96b37c0SOmar Sandoval {
226d96b37c0SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
227d96b37c0SOmar Sandoval 	struct request_queue *q = hctx->queue;
228d96b37c0SOmar Sandoval 
229d96b37c0SOmar Sandoval 	mutex_lock(&q->sysfs_lock);
230d96b37c0SOmar Sandoval 	if (hctx->sched_tags)
231d96b37c0SOmar Sandoval 		blk_mq_debugfs_tags_show(m, hctx->sched_tags);
232d96b37c0SOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
233d96b37c0SOmar Sandoval 
234d96b37c0SOmar Sandoval 	return 0;
235d96b37c0SOmar Sandoval }
236d96b37c0SOmar Sandoval 
237d96b37c0SOmar Sandoval static int hctx_sched_tags_open(struct inode *inode, struct file *file)
238d96b37c0SOmar Sandoval {
239d96b37c0SOmar Sandoval 	return single_open(file, hctx_sched_tags_show, inode->i_private);
240d96b37c0SOmar Sandoval }
241d96b37c0SOmar Sandoval 
242d96b37c0SOmar Sandoval static const struct file_operations hctx_sched_tags_fops = {
243d96b37c0SOmar Sandoval 	.open		= hctx_sched_tags_open,
244d96b37c0SOmar Sandoval 	.read		= seq_read,
245d96b37c0SOmar Sandoval 	.llseek		= seq_lseek,
246d96b37c0SOmar Sandoval 	.release	= single_release,
247d96b37c0SOmar Sandoval };
248d96b37c0SOmar Sandoval 
249d7e3621aSOmar Sandoval static int hctx_sched_tags_bitmap_show(struct seq_file *m, void *v)
250d7e3621aSOmar Sandoval {
251d7e3621aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
252d7e3621aSOmar Sandoval 	struct request_queue *q = hctx->queue;
253d7e3621aSOmar Sandoval 
254d7e3621aSOmar Sandoval 	mutex_lock(&q->sysfs_lock);
255d7e3621aSOmar Sandoval 	if (hctx->sched_tags)
256d7e3621aSOmar Sandoval 		sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m);
257d7e3621aSOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
258d7e3621aSOmar Sandoval 	return 0;
259d7e3621aSOmar Sandoval }
260d7e3621aSOmar Sandoval 
261d7e3621aSOmar Sandoval static int hctx_sched_tags_bitmap_open(struct inode *inode, struct file *file)
262d7e3621aSOmar Sandoval {
263d7e3621aSOmar Sandoval 	return single_open(file, hctx_sched_tags_bitmap_show, inode->i_private);
264d7e3621aSOmar Sandoval }
265d7e3621aSOmar Sandoval 
266d7e3621aSOmar Sandoval static const struct file_operations hctx_sched_tags_bitmap_fops = {
267d7e3621aSOmar Sandoval 	.open		= hctx_sched_tags_bitmap_open,
268d7e3621aSOmar Sandoval 	.read		= seq_read,
269d7e3621aSOmar Sandoval 	.llseek		= seq_lseek,
270d7e3621aSOmar Sandoval 	.release	= single_release,
271d7e3621aSOmar Sandoval };
272d7e3621aSOmar Sandoval 
273*be215473SOmar Sandoval static int hctx_io_poll_show(struct seq_file *m, void *v)
274*be215473SOmar Sandoval {
275*be215473SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
276*be215473SOmar Sandoval 
277*be215473SOmar Sandoval 	seq_printf(m, "considered=%lu\n", hctx->poll_considered);
278*be215473SOmar Sandoval 	seq_printf(m, "invoked=%lu\n", hctx->poll_invoked);
279*be215473SOmar Sandoval 	seq_printf(m, "success=%lu\n", hctx->poll_success);
280*be215473SOmar Sandoval 	return 0;
281*be215473SOmar Sandoval }
282*be215473SOmar Sandoval 
283*be215473SOmar Sandoval static int hctx_io_poll_open(struct inode *inode, struct file *file)
284*be215473SOmar Sandoval {
285*be215473SOmar Sandoval 	return single_open(file, hctx_io_poll_show, inode->i_private);
286*be215473SOmar Sandoval }
287*be215473SOmar Sandoval 
288*be215473SOmar Sandoval static ssize_t hctx_io_poll_write(struct file *file, const char __user *buf,
289*be215473SOmar Sandoval 				  size_t count, loff_t *ppos)
290*be215473SOmar Sandoval {
291*be215473SOmar Sandoval 	struct seq_file *m = file->private_data;
292*be215473SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
293*be215473SOmar Sandoval 
294*be215473SOmar Sandoval 	hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0;
295*be215473SOmar Sandoval 	return count;
296*be215473SOmar Sandoval }
297*be215473SOmar Sandoval 
298*be215473SOmar Sandoval static const struct file_operations hctx_io_poll_fops = {
299*be215473SOmar Sandoval 	.open		= hctx_io_poll_open,
300*be215473SOmar Sandoval 	.read		= seq_read,
301*be215473SOmar Sandoval 	.write		= hctx_io_poll_write,
302*be215473SOmar Sandoval 	.llseek		= seq_lseek,
303*be215473SOmar Sandoval 	.release	= single_release,
304*be215473SOmar Sandoval };
305*be215473SOmar Sandoval 
306*be215473SOmar Sandoval static void print_stat(struct seq_file *m, struct blk_rq_stat *stat)
307*be215473SOmar Sandoval {
308*be215473SOmar Sandoval 	seq_printf(m, "samples=%d, mean=%lld, min=%llu, max=%llu",
309*be215473SOmar Sandoval 		   stat->nr_samples, stat->mean, stat->min, stat->max);
310*be215473SOmar Sandoval }
311*be215473SOmar Sandoval 
312*be215473SOmar Sandoval static int hctx_stats_show(struct seq_file *m, void *v)
313*be215473SOmar Sandoval {
314*be215473SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
315*be215473SOmar Sandoval 	struct blk_rq_stat stat[2];
316*be215473SOmar Sandoval 
317*be215473SOmar Sandoval 	blk_stat_init(&stat[BLK_STAT_READ]);
318*be215473SOmar Sandoval 	blk_stat_init(&stat[BLK_STAT_WRITE]);
319*be215473SOmar Sandoval 
320*be215473SOmar Sandoval 	blk_hctx_stat_get(hctx, stat);
321*be215473SOmar Sandoval 
322*be215473SOmar Sandoval 	seq_puts(m, "read: ");
323*be215473SOmar Sandoval 	print_stat(m, &stat[BLK_STAT_READ]);
324*be215473SOmar Sandoval 	seq_puts(m, "\n");
325*be215473SOmar Sandoval 
326*be215473SOmar Sandoval 	seq_puts(m, "write: ");
327*be215473SOmar Sandoval 	print_stat(m, &stat[BLK_STAT_WRITE]);
328*be215473SOmar Sandoval 	seq_puts(m, "\n");
329*be215473SOmar Sandoval 	return 0;
330*be215473SOmar Sandoval }
331*be215473SOmar Sandoval 
332*be215473SOmar Sandoval static int hctx_stats_open(struct inode *inode, struct file *file)
333*be215473SOmar Sandoval {
334*be215473SOmar Sandoval 	return single_open(file, hctx_stats_show, inode->i_private);
335*be215473SOmar Sandoval }
336*be215473SOmar Sandoval 
337*be215473SOmar Sandoval static ssize_t hctx_stats_write(struct file *file, const char __user *buf,
338*be215473SOmar Sandoval 				size_t count, loff_t *ppos)
339*be215473SOmar Sandoval {
340*be215473SOmar Sandoval 	struct seq_file *m = file->private_data;
341*be215473SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
342*be215473SOmar Sandoval 	struct blk_mq_ctx *ctx;
343*be215473SOmar Sandoval 	int i;
344*be215473SOmar Sandoval 
345*be215473SOmar Sandoval 	hctx_for_each_ctx(hctx, ctx, i) {
346*be215473SOmar Sandoval 		blk_stat_init(&ctx->stat[BLK_STAT_READ]);
347*be215473SOmar Sandoval 		blk_stat_init(&ctx->stat[BLK_STAT_WRITE]);
348*be215473SOmar Sandoval 	}
349*be215473SOmar Sandoval 	return count;
350*be215473SOmar Sandoval }
351*be215473SOmar Sandoval 
352*be215473SOmar Sandoval static const struct file_operations hctx_stats_fops = {
353*be215473SOmar Sandoval 	.open		= hctx_stats_open,
354*be215473SOmar Sandoval 	.read		= seq_read,
355*be215473SOmar Sandoval 	.write		= hctx_stats_write,
356*be215473SOmar Sandoval 	.llseek		= seq_lseek,
357*be215473SOmar Sandoval 	.release	= single_release,
358*be215473SOmar Sandoval };
359*be215473SOmar Sandoval 
360*be215473SOmar Sandoval static int hctx_dispatched_show(struct seq_file *m, void *v)
361*be215473SOmar Sandoval {
362*be215473SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
363*be215473SOmar Sandoval 	int i;
364*be215473SOmar Sandoval 
365*be215473SOmar Sandoval 	seq_printf(m, "%8u\t%lu\n", 0U, hctx->dispatched[0]);
366*be215473SOmar Sandoval 
367*be215473SOmar Sandoval 	for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) {
368*be215473SOmar Sandoval 		unsigned int d = 1U << (i - 1);
369*be215473SOmar Sandoval 
370*be215473SOmar Sandoval 		seq_printf(m, "%8u\t%lu\n", d, hctx->dispatched[i]);
371*be215473SOmar Sandoval 	}
372*be215473SOmar Sandoval 
373*be215473SOmar Sandoval 	seq_printf(m, "%8u+\t%lu\n", 1U << (i - 1), hctx->dispatched[i]);
374*be215473SOmar Sandoval 	return 0;
375*be215473SOmar Sandoval }
376*be215473SOmar Sandoval 
377*be215473SOmar Sandoval static int hctx_dispatched_open(struct inode *inode, struct file *file)
378*be215473SOmar Sandoval {
379*be215473SOmar Sandoval 	return single_open(file, hctx_dispatched_show, inode->i_private);
380*be215473SOmar Sandoval }
381*be215473SOmar Sandoval 
382*be215473SOmar Sandoval static ssize_t hctx_dispatched_write(struct file *file, const char __user *buf,
383*be215473SOmar Sandoval 				     size_t count, loff_t *ppos)
384*be215473SOmar Sandoval {
385*be215473SOmar Sandoval 	struct seq_file *m = file->private_data;
386*be215473SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
387*be215473SOmar Sandoval 	int i;
388*be215473SOmar Sandoval 
389*be215473SOmar Sandoval 	for (i = 0; i < BLK_MQ_MAX_DISPATCH_ORDER; i++)
390*be215473SOmar Sandoval 		hctx->dispatched[i] = 0;
391*be215473SOmar Sandoval 	return count;
392*be215473SOmar Sandoval }
393*be215473SOmar Sandoval 
394*be215473SOmar Sandoval static const struct file_operations hctx_dispatched_fops = {
395*be215473SOmar Sandoval 	.open		= hctx_dispatched_open,
396*be215473SOmar Sandoval 	.read		= seq_read,
397*be215473SOmar Sandoval 	.write		= hctx_dispatched_write,
398*be215473SOmar Sandoval 	.llseek		= seq_lseek,
399*be215473SOmar Sandoval 	.release	= single_release,
400*be215473SOmar Sandoval };
401*be215473SOmar Sandoval 
402950cd7e9SOmar Sandoval static void *ctx_rq_list_start(struct seq_file *m, loff_t *pos)
403950cd7e9SOmar Sandoval {
404950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
405950cd7e9SOmar Sandoval 
406950cd7e9SOmar Sandoval 	spin_lock(&ctx->lock);
407950cd7e9SOmar Sandoval 	return seq_list_start(&ctx->rq_list, *pos);
408950cd7e9SOmar Sandoval }
409950cd7e9SOmar Sandoval 
410950cd7e9SOmar Sandoval static void *ctx_rq_list_next(struct seq_file *m, void *v, loff_t *pos)
411950cd7e9SOmar Sandoval {
412950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
413950cd7e9SOmar Sandoval 
414950cd7e9SOmar Sandoval 	return seq_list_next(v, &ctx->rq_list, pos);
415950cd7e9SOmar Sandoval }
416950cd7e9SOmar Sandoval 
417950cd7e9SOmar Sandoval static void ctx_rq_list_stop(struct seq_file *m, void *v)
418950cd7e9SOmar Sandoval {
419950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
420950cd7e9SOmar Sandoval 
421950cd7e9SOmar Sandoval 	spin_unlock(&ctx->lock);
422950cd7e9SOmar Sandoval }
423950cd7e9SOmar Sandoval 
424950cd7e9SOmar Sandoval static const struct seq_operations ctx_rq_list_seq_ops = {
425950cd7e9SOmar Sandoval 	.start	= ctx_rq_list_start,
426950cd7e9SOmar Sandoval 	.next	= ctx_rq_list_next,
427950cd7e9SOmar Sandoval 	.stop	= ctx_rq_list_stop,
428950cd7e9SOmar Sandoval 	.show	= blk_mq_debugfs_rq_show,
429950cd7e9SOmar Sandoval };
430950cd7e9SOmar Sandoval 
431950cd7e9SOmar Sandoval static int ctx_rq_list_open(struct inode *inode, struct file *file)
432950cd7e9SOmar Sandoval {
433950cd7e9SOmar Sandoval 	return blk_mq_debugfs_seq_open(inode, file, &ctx_rq_list_seq_ops);
434950cd7e9SOmar Sandoval }
435950cd7e9SOmar Sandoval 
436950cd7e9SOmar Sandoval static const struct file_operations ctx_rq_list_fops = {
437950cd7e9SOmar Sandoval 	.open		= ctx_rq_list_open,
438950cd7e9SOmar Sandoval 	.read		= seq_read,
439950cd7e9SOmar Sandoval 	.llseek		= seq_lseek,
440950cd7e9SOmar Sandoval 	.release	= seq_release,
441950cd7e9SOmar Sandoval };
442950cd7e9SOmar Sandoval 
44307e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = {
4449abb2ad2SOmar Sandoval 	{"state", 0400, &hctx_state_fops},
4459abb2ad2SOmar Sandoval 	{"flags", 0400, &hctx_flags_fops},
446950cd7e9SOmar Sandoval 	{"dispatch", 0400, &hctx_dispatch_fops},
4470bfa5288SOmar Sandoval 	{"ctx_map", 0400, &hctx_ctx_map_fops},
448d96b37c0SOmar Sandoval 	{"tags", 0400, &hctx_tags_fops},
449d7e3621aSOmar Sandoval 	{"tags_bitmap", 0400, &hctx_tags_bitmap_fops},
450d96b37c0SOmar Sandoval 	{"sched_tags", 0400, &hctx_sched_tags_fops},
451d7e3621aSOmar Sandoval 	{"sched_tags_bitmap", 0400, &hctx_sched_tags_bitmap_fops},
452*be215473SOmar Sandoval 	{"io_poll", 0600, &hctx_io_poll_fops},
453*be215473SOmar Sandoval 	{"stats", 0600, &hctx_stats_fops},
454*be215473SOmar Sandoval 	{"dispatched", 0600, &hctx_dispatched_fops},
45507e4feadSOmar Sandoval };
45607e4feadSOmar Sandoval 
45707e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = {
458950cd7e9SOmar Sandoval 	{"rq_list", 0400, &ctx_rq_list_fops},
45907e4feadSOmar Sandoval };
46007e4feadSOmar Sandoval 
46107e4feadSOmar Sandoval int blk_mq_debugfs_register(struct request_queue *q, const char *name)
46207e4feadSOmar Sandoval {
46307e4feadSOmar Sandoval 	if (!block_debugfs_root)
46407e4feadSOmar Sandoval 		return -ENOENT;
46507e4feadSOmar Sandoval 
46607e4feadSOmar Sandoval 	q->debugfs_dir = debugfs_create_dir(name, block_debugfs_root);
46707e4feadSOmar Sandoval 	if (!q->debugfs_dir)
46807e4feadSOmar Sandoval 		goto err;
46907e4feadSOmar Sandoval 
47007e4feadSOmar Sandoval 	if (blk_mq_debugfs_register_hctxs(q))
47107e4feadSOmar Sandoval 		goto err;
47207e4feadSOmar Sandoval 
47307e4feadSOmar Sandoval 	return 0;
47407e4feadSOmar Sandoval 
47507e4feadSOmar Sandoval err:
47607e4feadSOmar Sandoval 	blk_mq_debugfs_unregister(q);
47707e4feadSOmar Sandoval 	return -ENOMEM;
47807e4feadSOmar Sandoval }
47907e4feadSOmar Sandoval 
48007e4feadSOmar Sandoval void blk_mq_debugfs_unregister(struct request_queue *q)
48107e4feadSOmar Sandoval {
48207e4feadSOmar Sandoval 	debugfs_remove_recursive(q->debugfs_dir);
48307e4feadSOmar Sandoval 	q->mq_debugfs_dir = NULL;
48407e4feadSOmar Sandoval 	q->debugfs_dir = NULL;
48507e4feadSOmar Sandoval }
48607e4feadSOmar Sandoval 
48707e4feadSOmar Sandoval static int blk_mq_debugfs_register_ctx(struct request_queue *q,
48807e4feadSOmar Sandoval 				       struct blk_mq_ctx *ctx,
48907e4feadSOmar Sandoval 				       struct dentry *hctx_dir)
49007e4feadSOmar Sandoval {
49107e4feadSOmar Sandoval 	struct dentry *ctx_dir;
49207e4feadSOmar Sandoval 	char name[20];
49307e4feadSOmar Sandoval 	int i;
49407e4feadSOmar Sandoval 
49507e4feadSOmar Sandoval 	snprintf(name, sizeof(name), "cpu%u", ctx->cpu);
49607e4feadSOmar Sandoval 	ctx_dir = debugfs_create_dir(name, hctx_dir);
49707e4feadSOmar Sandoval 	if (!ctx_dir)
49807e4feadSOmar Sandoval 		return -ENOMEM;
49907e4feadSOmar Sandoval 
50007e4feadSOmar Sandoval 	for (i = 0; i < ARRAY_SIZE(blk_mq_debugfs_ctx_attrs); i++) {
50107e4feadSOmar Sandoval 		const struct blk_mq_debugfs_attr *attr;
50207e4feadSOmar Sandoval 
50307e4feadSOmar Sandoval 		attr = &blk_mq_debugfs_ctx_attrs[i];
50407e4feadSOmar Sandoval 		if (!debugfs_create_file(attr->name, attr->mode, ctx_dir, ctx,
50507e4feadSOmar Sandoval 					 attr->fops))
50607e4feadSOmar Sandoval 			return -ENOMEM;
50707e4feadSOmar Sandoval 	}
50807e4feadSOmar Sandoval 
50907e4feadSOmar Sandoval 	return 0;
51007e4feadSOmar Sandoval }
51107e4feadSOmar Sandoval 
51207e4feadSOmar Sandoval static int blk_mq_debugfs_register_hctx(struct request_queue *q,
51307e4feadSOmar Sandoval 					struct blk_mq_hw_ctx *hctx)
51407e4feadSOmar Sandoval {
51507e4feadSOmar Sandoval 	struct blk_mq_ctx *ctx;
51607e4feadSOmar Sandoval 	struct dentry *hctx_dir;
51707e4feadSOmar Sandoval 	char name[20];
51807e4feadSOmar Sandoval 	int i;
51907e4feadSOmar Sandoval 
52007e4feadSOmar Sandoval 	snprintf(name, sizeof(name), "%u", hctx->queue_num);
52107e4feadSOmar Sandoval 	hctx_dir = debugfs_create_dir(name, q->mq_debugfs_dir);
52207e4feadSOmar Sandoval 	if (!hctx_dir)
52307e4feadSOmar Sandoval 		return -ENOMEM;
52407e4feadSOmar Sandoval 
52507e4feadSOmar Sandoval 	for (i = 0; i < ARRAY_SIZE(blk_mq_debugfs_hctx_attrs); i++) {
52607e4feadSOmar Sandoval 		const struct blk_mq_debugfs_attr *attr;
52707e4feadSOmar Sandoval 
52807e4feadSOmar Sandoval 		attr = &blk_mq_debugfs_hctx_attrs[i];
52907e4feadSOmar Sandoval 		if (!debugfs_create_file(attr->name, attr->mode, hctx_dir, hctx,
53007e4feadSOmar Sandoval 					 attr->fops))
53107e4feadSOmar Sandoval 			return -ENOMEM;
53207e4feadSOmar Sandoval 	}
53307e4feadSOmar Sandoval 
53407e4feadSOmar Sandoval 	hctx_for_each_ctx(hctx, ctx, i) {
53507e4feadSOmar Sandoval 		if (blk_mq_debugfs_register_ctx(q, ctx, hctx_dir))
53607e4feadSOmar Sandoval 			return -ENOMEM;
53707e4feadSOmar Sandoval 	}
53807e4feadSOmar Sandoval 
53907e4feadSOmar Sandoval 	return 0;
54007e4feadSOmar Sandoval }
54107e4feadSOmar Sandoval 
54207e4feadSOmar Sandoval int blk_mq_debugfs_register_hctxs(struct request_queue *q)
54307e4feadSOmar Sandoval {
54407e4feadSOmar Sandoval 	struct blk_mq_hw_ctx *hctx;
54507e4feadSOmar Sandoval 	int i;
54607e4feadSOmar Sandoval 
54707e4feadSOmar Sandoval 	if (!q->debugfs_dir)
54807e4feadSOmar Sandoval 		return -ENOENT;
54907e4feadSOmar Sandoval 
55007e4feadSOmar Sandoval 	q->mq_debugfs_dir = debugfs_create_dir("mq", q->debugfs_dir);
55107e4feadSOmar Sandoval 	if (!q->mq_debugfs_dir)
55207e4feadSOmar Sandoval 		goto err;
55307e4feadSOmar Sandoval 
55407e4feadSOmar Sandoval 	queue_for_each_hw_ctx(q, hctx, i) {
55507e4feadSOmar Sandoval 		if (blk_mq_debugfs_register_hctx(q, hctx))
55607e4feadSOmar Sandoval 			goto err;
55707e4feadSOmar Sandoval 	}
55807e4feadSOmar Sandoval 
55907e4feadSOmar Sandoval 	return 0;
56007e4feadSOmar Sandoval 
56107e4feadSOmar Sandoval err:
56207e4feadSOmar Sandoval 	blk_mq_debugfs_unregister_hctxs(q);
56307e4feadSOmar Sandoval 	return -ENOMEM;
56407e4feadSOmar Sandoval }
56507e4feadSOmar Sandoval 
56607e4feadSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
56707e4feadSOmar Sandoval {
56807e4feadSOmar Sandoval 	debugfs_remove_recursive(q->mq_debugfs_dir);
56907e4feadSOmar Sandoval 	q->mq_debugfs_dir = NULL;
57007e4feadSOmar Sandoval }
57107e4feadSOmar Sandoval 
57207e4feadSOmar Sandoval void blk_mq_debugfs_init(void)
57307e4feadSOmar Sandoval {
57407e4feadSOmar Sandoval 	block_debugfs_root = debugfs_create_dir("block", NULL);
57507e4feadSOmar Sandoval }
576