blob: 1077008690b29a2f9123b371e71b01fe1d02ae38 [file] [log] [blame]
Omar Sandoval07e4fea2017-01-25 08:06:40 -08001/*
2 * Copyright (C) 2017 Facebook
3 *
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.
7 *
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.
12 *
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/>.
15 */
16
17#include <linux/kernel.h>
18#include <linux/blkdev.h>
19#include <linux/debugfs.h>
20
21#include <linux/blk-mq.h>
22#include "blk-mq.h"
Omar Sandovald96b37c2017-01-25 08:06:46 -080023#include "blk-mq-tag.h"
Omar Sandoval07e4fea2017-01-25 08:06:40 -080024
25struct blk_mq_debugfs_attr {
26 const char *name;
27 umode_t mode;
28 const struct file_operations *fops;
29};
30
31static struct dentry *block_debugfs_root;
32
Omar Sandoval950cd7e2017-01-25 08:06:42 -080033static int blk_mq_debugfs_seq_open(struct inode *inode, struct file *file,
34 const struct seq_operations *ops)
35{
36 struct seq_file *m;
37 int ret;
38
39 ret = seq_open(file, ops);
40 if (!ret) {
41 m = file->private_data;
42 m->private = inode->i_private;
43 }
44 return ret;
45}
46
Omar Sandoval9abb2ad2017-01-25 08:06:41 -080047static int hctx_state_show(struct seq_file *m, void *v)
48{
49 struct blk_mq_hw_ctx *hctx = m->private;
50
51 seq_printf(m, "0x%lx\n", hctx->state);
52 return 0;
53}
54
55static int hctx_state_open(struct inode *inode, struct file *file)
56{
57 return single_open(file, hctx_state_show, inode->i_private);
58}
59
60static const struct file_operations hctx_state_fops = {
61 .open = hctx_state_open,
62 .read = seq_read,
63 .llseek = seq_lseek,
64 .release = single_release,
65};
66
67static int hctx_flags_show(struct seq_file *m, void *v)
68{
69 struct blk_mq_hw_ctx *hctx = m->private;
70
71 seq_printf(m, "0x%lx\n", hctx->flags);
72 return 0;
73}
74
75static int hctx_flags_open(struct inode *inode, struct file *file)
76{
77 return single_open(file, hctx_flags_show, inode->i_private);
78}
79
80static const struct file_operations hctx_flags_fops = {
81 .open = hctx_flags_open,
82 .read = seq_read,
83 .llseek = seq_lseek,
84 .release = single_release,
85};
86
Omar Sandoval950cd7e2017-01-25 08:06:42 -080087static int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
88{
89 struct request *rq = list_entry_rq(v);
90
Christoph Hellwigaebf5262017-01-31 16:57:31 +010091 seq_printf(m, "%p {.cmd_flags=0x%x, .rq_flags=0x%x, .tag=%d, .internal_tag=%d}\n",
Bart Van Asschea1ae0f72017-02-01 12:22:23 -070092 rq, rq->cmd_flags, (__force unsigned int)rq->rq_flags,
Omar Sandoval7b393852017-01-25 08:06:43 -080093 rq->tag, rq->internal_tag);
Omar Sandoval950cd7e2017-01-25 08:06:42 -080094 return 0;
95}
96
97static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos)
Bart Van Asschef3bcb0e2017-02-01 10:20:56 -080098 __acquires(&hctx->lock)
Omar Sandoval950cd7e2017-01-25 08:06:42 -080099{
100 struct blk_mq_hw_ctx *hctx = m->private;
101
102 spin_lock(&hctx->lock);
103 return seq_list_start(&hctx->dispatch, *pos);
104}
105
106static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos)
107{
108 struct blk_mq_hw_ctx *hctx = m->private;
109
110 return seq_list_next(v, &hctx->dispatch, pos);
111}
112
113static void hctx_dispatch_stop(struct seq_file *m, void *v)
Bart Van Asschef3bcb0e2017-02-01 10:20:56 -0800114 __releases(&hctx->lock)
Omar Sandoval950cd7e2017-01-25 08:06:42 -0800115{
116 struct blk_mq_hw_ctx *hctx = m->private;
117
118 spin_unlock(&hctx->lock);
119}
120
121static const struct seq_operations hctx_dispatch_seq_ops = {
122 .start = hctx_dispatch_start,
123 .next = hctx_dispatch_next,
124 .stop = hctx_dispatch_stop,
125 .show = blk_mq_debugfs_rq_show,
126};
127
128static int hctx_dispatch_open(struct inode *inode, struct file *file)
129{
130 return blk_mq_debugfs_seq_open(inode, file, &hctx_dispatch_seq_ops);
131}
132
133static const struct file_operations hctx_dispatch_fops = {
134 .open = hctx_dispatch_open,
135 .read = seq_read,
136 .llseek = seq_lseek,
137 .release = seq_release,
138};
139
Omar Sandoval0bfa5282017-01-25 08:06:45 -0800140static int hctx_ctx_map_show(struct seq_file *m, void *v)
141{
142 struct blk_mq_hw_ctx *hctx = m->private;
143
144 sbitmap_bitmap_show(&hctx->ctx_map, m);
145 return 0;
146}
147
148static int hctx_ctx_map_open(struct inode *inode, struct file *file)
149{
150 return single_open(file, hctx_ctx_map_show, inode->i_private);
151}
152
153static const struct file_operations hctx_ctx_map_fops = {
154 .open = hctx_ctx_map_open,
155 .read = seq_read,
156 .llseek = seq_lseek,
157 .release = single_release,
158};
159
Omar Sandovald96b37c2017-01-25 08:06:46 -0800160static void blk_mq_debugfs_tags_show(struct seq_file *m,
161 struct blk_mq_tags *tags)
162{
163 seq_printf(m, "nr_tags=%u\n", tags->nr_tags);
164 seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags);
165 seq_printf(m, "active_queues=%d\n",
166 atomic_read(&tags->active_queues));
167
168 seq_puts(m, "\nbitmap_tags:\n");
169 sbitmap_queue_show(&tags->bitmap_tags, m);
170
171 if (tags->nr_reserved_tags) {
172 seq_puts(m, "\nbreserved_tags:\n");
173 sbitmap_queue_show(&tags->breserved_tags, m);
174 }
175}
176
177static int hctx_tags_show(struct seq_file *m, void *v)
178{
179 struct blk_mq_hw_ctx *hctx = m->private;
180 struct request_queue *q = hctx->queue;
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800181 int res;
Omar Sandovald96b37c2017-01-25 08:06:46 -0800182
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800183 res = mutex_lock_interruptible(&q->sysfs_lock);
184 if (res)
185 goto out;
Omar Sandovald96b37c2017-01-25 08:06:46 -0800186 if (hctx->tags)
187 blk_mq_debugfs_tags_show(m, hctx->tags);
188 mutex_unlock(&q->sysfs_lock);
189
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800190out:
191 return res;
Omar Sandovald96b37c2017-01-25 08:06:46 -0800192}
193
194static int hctx_tags_open(struct inode *inode, struct file *file)
195{
196 return single_open(file, hctx_tags_show, inode->i_private);
197}
198
199static const struct file_operations hctx_tags_fops = {
200 .open = hctx_tags_open,
201 .read = seq_read,
202 .llseek = seq_lseek,
203 .release = single_release,
204};
205
Omar Sandovald7e36212017-01-25 08:06:47 -0800206static int hctx_tags_bitmap_show(struct seq_file *m, void *v)
207{
208 struct blk_mq_hw_ctx *hctx = m->private;
209 struct request_queue *q = hctx->queue;
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800210 int res;
Omar Sandovald7e36212017-01-25 08:06:47 -0800211
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800212 res = mutex_lock_interruptible(&q->sysfs_lock);
213 if (res)
214 goto out;
Omar Sandovald7e36212017-01-25 08:06:47 -0800215 if (hctx->tags)
216 sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m);
217 mutex_unlock(&q->sysfs_lock);
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800218
219out:
220 return res;
Omar Sandovald7e36212017-01-25 08:06:47 -0800221}
222
223static int hctx_tags_bitmap_open(struct inode *inode, struct file *file)
224{
225 return single_open(file, hctx_tags_bitmap_show, inode->i_private);
226}
227
228static const struct file_operations hctx_tags_bitmap_fops = {
229 .open = hctx_tags_bitmap_open,
230 .read = seq_read,
231 .llseek = seq_lseek,
232 .release = single_release,
233};
234
Omar Sandovald96b37c2017-01-25 08:06:46 -0800235static int hctx_sched_tags_show(struct seq_file *m, void *v)
236{
237 struct blk_mq_hw_ctx *hctx = m->private;
238 struct request_queue *q = hctx->queue;
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800239 int res;
Omar Sandovald96b37c2017-01-25 08:06:46 -0800240
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800241 res = mutex_lock_interruptible(&q->sysfs_lock);
242 if (res)
243 goto out;
Omar Sandovald96b37c2017-01-25 08:06:46 -0800244 if (hctx->sched_tags)
245 blk_mq_debugfs_tags_show(m, hctx->sched_tags);
246 mutex_unlock(&q->sysfs_lock);
247
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800248out:
249 return res;
Omar Sandovald96b37c2017-01-25 08:06:46 -0800250}
251
252static int hctx_sched_tags_open(struct inode *inode, struct file *file)
253{
254 return single_open(file, hctx_sched_tags_show, inode->i_private);
255}
256
257static const struct file_operations hctx_sched_tags_fops = {
258 .open = hctx_sched_tags_open,
259 .read = seq_read,
260 .llseek = seq_lseek,
261 .release = single_release,
262};
263
Omar Sandovald7e36212017-01-25 08:06:47 -0800264static int hctx_sched_tags_bitmap_show(struct seq_file *m, void *v)
265{
266 struct blk_mq_hw_ctx *hctx = m->private;
267 struct request_queue *q = hctx->queue;
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800268 int res;
Omar Sandovald7e36212017-01-25 08:06:47 -0800269
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800270 res = mutex_lock_interruptible(&q->sysfs_lock);
271 if (res)
272 goto out;
Omar Sandovald7e36212017-01-25 08:06:47 -0800273 if (hctx->sched_tags)
274 sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m);
275 mutex_unlock(&q->sysfs_lock);
Bart Van Assche8c0f14e2017-02-01 10:20:58 -0800276
277out:
278 return res;
Omar Sandovald7e36212017-01-25 08:06:47 -0800279}
280
281static int hctx_sched_tags_bitmap_open(struct inode *inode, struct file *file)
282{
283 return single_open(file, hctx_sched_tags_bitmap_show, inode->i_private);
284}
285
286static const struct file_operations hctx_sched_tags_bitmap_fops = {
287 .open = hctx_sched_tags_bitmap_open,
288 .read = seq_read,
289 .llseek = seq_lseek,
290 .release = single_release,
291};
292
Omar Sandovalbe215472017-01-25 08:06:48 -0800293static int hctx_io_poll_show(struct seq_file *m, void *v)
294{
295 struct blk_mq_hw_ctx *hctx = m->private;
296
297 seq_printf(m, "considered=%lu\n", hctx->poll_considered);
298 seq_printf(m, "invoked=%lu\n", hctx->poll_invoked);
299 seq_printf(m, "success=%lu\n", hctx->poll_success);
300 return 0;
301}
302
303static int hctx_io_poll_open(struct inode *inode, struct file *file)
304{
305 return single_open(file, hctx_io_poll_show, inode->i_private);
306}
307
308static ssize_t hctx_io_poll_write(struct file *file, const char __user *buf,
309 size_t count, loff_t *ppos)
310{
311 struct seq_file *m = file->private_data;
312 struct blk_mq_hw_ctx *hctx = m->private;
313
314 hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0;
315 return count;
316}
317
318static const struct file_operations hctx_io_poll_fops = {
319 .open = hctx_io_poll_open,
320 .read = seq_read,
321 .write = hctx_io_poll_write,
322 .llseek = seq_lseek,
323 .release = single_release,
324};
325
326static void print_stat(struct seq_file *m, struct blk_rq_stat *stat)
327{
328 seq_printf(m, "samples=%d, mean=%lld, min=%llu, max=%llu",
329 stat->nr_samples, stat->mean, stat->min, stat->max);
330}
331
332static int hctx_stats_show(struct seq_file *m, void *v)
333{
334 struct blk_mq_hw_ctx *hctx = m->private;
335 struct blk_rq_stat stat[2];
336
337 blk_stat_init(&stat[BLK_STAT_READ]);
338 blk_stat_init(&stat[BLK_STAT_WRITE]);
339
340 blk_hctx_stat_get(hctx, stat);
341
342 seq_puts(m, "read: ");
343 print_stat(m, &stat[BLK_STAT_READ]);
344 seq_puts(m, "\n");
345
346 seq_puts(m, "write: ");
347 print_stat(m, &stat[BLK_STAT_WRITE]);
348 seq_puts(m, "\n");
349 return 0;
350}
351
352static int hctx_stats_open(struct inode *inode, struct file *file)
353{
354 return single_open(file, hctx_stats_show, inode->i_private);
355}
356
357static ssize_t hctx_stats_write(struct file *file, const char __user *buf,
358 size_t count, loff_t *ppos)
359{
360 struct seq_file *m = file->private_data;
361 struct blk_mq_hw_ctx *hctx = m->private;
362 struct blk_mq_ctx *ctx;
363 int i;
364
365 hctx_for_each_ctx(hctx, ctx, i) {
366 blk_stat_init(&ctx->stat[BLK_STAT_READ]);
367 blk_stat_init(&ctx->stat[BLK_STAT_WRITE]);
368 }
369 return count;
370}
371
372static const struct file_operations hctx_stats_fops = {
373 .open = hctx_stats_open,
374 .read = seq_read,
375 .write = hctx_stats_write,
376 .llseek = seq_lseek,
377 .release = single_release,
378};
379
380static int hctx_dispatched_show(struct seq_file *m, void *v)
381{
382 struct blk_mq_hw_ctx *hctx = m->private;
383 int i;
384
385 seq_printf(m, "%8u\t%lu\n", 0U, hctx->dispatched[0]);
386
387 for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) {
388 unsigned int d = 1U << (i - 1);
389
390 seq_printf(m, "%8u\t%lu\n", d, hctx->dispatched[i]);
391 }
392
393 seq_printf(m, "%8u+\t%lu\n", 1U << (i - 1), hctx->dispatched[i]);
394 return 0;
395}
396
397static int hctx_dispatched_open(struct inode *inode, struct file *file)
398{
399 return single_open(file, hctx_dispatched_show, inode->i_private);
400}
401
402static ssize_t hctx_dispatched_write(struct file *file, const char __user *buf,
403 size_t count, loff_t *ppos)
404{
405 struct seq_file *m = file->private_data;
406 struct blk_mq_hw_ctx *hctx = m->private;
407 int i;
408
409 for (i = 0; i < BLK_MQ_MAX_DISPATCH_ORDER; i++)
410 hctx->dispatched[i] = 0;
411 return count;
412}
413
414static const struct file_operations hctx_dispatched_fops = {
415 .open = hctx_dispatched_open,
416 .read = seq_read,
417 .write = hctx_dispatched_write,
418 .llseek = seq_lseek,
419 .release = single_release,
420};
421
Omar Sandoval4a46f052017-01-25 08:06:49 -0800422static int hctx_queued_show(struct seq_file *m, void *v)
423{
424 struct blk_mq_hw_ctx *hctx = m->private;
425
426 seq_printf(m, "%lu\n", hctx->queued);
427 return 0;
428}
429
430static int hctx_queued_open(struct inode *inode, struct file *file)
431{
432 return single_open(file, hctx_queued_show, inode->i_private);
433}
434
435static ssize_t hctx_queued_write(struct file *file, const char __user *buf,
436 size_t count, loff_t *ppos)
437{
438 struct seq_file *m = file->private_data;
439 struct blk_mq_hw_ctx *hctx = m->private;
440
441 hctx->queued = 0;
442 return count;
443}
444
445static const struct file_operations hctx_queued_fops = {
446 .open = hctx_queued_open,
447 .read = seq_read,
448 .write = hctx_queued_write,
449 .llseek = seq_lseek,
450 .release = single_release,
451};
452
453static int hctx_run_show(struct seq_file *m, void *v)
454{
455 struct blk_mq_hw_ctx *hctx = m->private;
456
457 seq_printf(m, "%lu\n", hctx->run);
458 return 0;
459}
460
461static int hctx_run_open(struct inode *inode, struct file *file)
462{
463 return single_open(file, hctx_run_show, inode->i_private);
464}
465
466static ssize_t hctx_run_write(struct file *file, const char __user *buf,
467 size_t count, loff_t *ppos)
468{
469 struct seq_file *m = file->private_data;
470 struct blk_mq_hw_ctx *hctx = m->private;
471
472 hctx->run = 0;
473 return count;
474}
475
476static const struct file_operations hctx_run_fops = {
477 .open = hctx_run_open,
478 .read = seq_read,
479 .write = hctx_run_write,
480 .llseek = seq_lseek,
481 .release = single_release,
482};
483
484static int hctx_active_show(struct seq_file *m, void *v)
485{
486 struct blk_mq_hw_ctx *hctx = m->private;
487
488 seq_printf(m, "%d\n", atomic_read(&hctx->nr_active));
489 return 0;
490}
491
492static int hctx_active_open(struct inode *inode, struct file *file)
493{
494 return single_open(file, hctx_active_show, inode->i_private);
495}
496
497static const struct file_operations hctx_active_fops = {
498 .open = hctx_active_open,
499 .read = seq_read,
500 .llseek = seq_lseek,
501 .release = single_release,
502};
503
Omar Sandoval950cd7e2017-01-25 08:06:42 -0800504static void *ctx_rq_list_start(struct seq_file *m, loff_t *pos)
Bart Van Asschef3bcb0e2017-02-01 10:20:56 -0800505 __acquires(&ctx->lock)
Omar Sandoval950cd7e2017-01-25 08:06:42 -0800506{
507 struct blk_mq_ctx *ctx = m->private;
508
509 spin_lock(&ctx->lock);
510 return seq_list_start(&ctx->rq_list, *pos);
511}
512
513static void *ctx_rq_list_next(struct seq_file *m, void *v, loff_t *pos)
514{
515 struct blk_mq_ctx *ctx = m->private;
516
517 return seq_list_next(v, &ctx->rq_list, pos);
518}
519
520static void ctx_rq_list_stop(struct seq_file *m, void *v)
Bart Van Asschef3bcb0e2017-02-01 10:20:56 -0800521 __releases(&ctx->lock)
Omar Sandoval950cd7e2017-01-25 08:06:42 -0800522{
523 struct blk_mq_ctx *ctx = m->private;
524
525 spin_unlock(&ctx->lock);
526}
527
528static const struct seq_operations ctx_rq_list_seq_ops = {
529 .start = ctx_rq_list_start,
530 .next = ctx_rq_list_next,
531 .stop = ctx_rq_list_stop,
532 .show = blk_mq_debugfs_rq_show,
533};
534
535static int ctx_rq_list_open(struct inode *inode, struct file *file)
536{
537 return blk_mq_debugfs_seq_open(inode, file, &ctx_rq_list_seq_ops);
538}
539
540static const struct file_operations ctx_rq_list_fops = {
541 .open = ctx_rq_list_open,
542 .read = seq_read,
543 .llseek = seq_lseek,
544 .release = seq_release,
545};
546
Omar Sandoval4a46f052017-01-25 08:06:49 -0800547static int ctx_dispatched_show(struct seq_file *m, void *v)
548{
549 struct blk_mq_ctx *ctx = m->private;
550
551 seq_printf(m, "%lu %lu\n", ctx->rq_dispatched[1], ctx->rq_dispatched[0]);
552 return 0;
553}
554
555static int ctx_dispatched_open(struct inode *inode, struct file *file)
556{
557 return single_open(file, ctx_dispatched_show, inode->i_private);
558}
559
560static ssize_t ctx_dispatched_write(struct file *file, const char __user *buf,
561 size_t count, loff_t *ppos)
562{
563 struct seq_file *m = file->private_data;
564 struct blk_mq_ctx *ctx = m->private;
565
566 ctx->rq_dispatched[0] = ctx->rq_dispatched[1] = 0;
567 return count;
568}
569
570static const struct file_operations ctx_dispatched_fops = {
571 .open = ctx_dispatched_open,
572 .read = seq_read,
573 .write = ctx_dispatched_write,
574 .llseek = seq_lseek,
575 .release = single_release,
576};
577
578static int ctx_merged_show(struct seq_file *m, void *v)
579{
580 struct blk_mq_ctx *ctx = m->private;
581
582 seq_printf(m, "%lu\n", ctx->rq_merged);
583 return 0;
584}
585
586static int ctx_merged_open(struct inode *inode, struct file *file)
587{
588 return single_open(file, ctx_merged_show, inode->i_private);
589}
590
591static ssize_t ctx_merged_write(struct file *file, const char __user *buf,
592 size_t count, loff_t *ppos)
593{
594 struct seq_file *m = file->private_data;
595 struct blk_mq_ctx *ctx = m->private;
596
597 ctx->rq_merged = 0;
598 return count;
599}
600
601static const struct file_operations ctx_merged_fops = {
602 .open = ctx_merged_open,
603 .read = seq_read,
604 .write = ctx_merged_write,
605 .llseek = seq_lseek,
606 .release = single_release,
607};
608
609static int ctx_completed_show(struct seq_file *m, void *v)
610{
611 struct blk_mq_ctx *ctx = m->private;
612
613 seq_printf(m, "%lu %lu\n", ctx->rq_completed[1], ctx->rq_completed[0]);
614 return 0;
615}
616
617static int ctx_completed_open(struct inode *inode, struct file *file)
618{
619 return single_open(file, ctx_completed_show, inode->i_private);
620}
621
622static ssize_t ctx_completed_write(struct file *file, const char __user *buf,
623 size_t count, loff_t *ppos)
624{
625 struct seq_file *m = file->private_data;
626 struct blk_mq_ctx *ctx = m->private;
627
628 ctx->rq_completed[0] = ctx->rq_completed[1] = 0;
629 return count;
630}
631
632static const struct file_operations ctx_completed_fops = {
633 .open = ctx_completed_open,
634 .read = seq_read,
635 .write = ctx_completed_write,
636 .llseek = seq_lseek,
637 .release = single_release,
638};
639
Omar Sandoval07e4fea2017-01-25 08:06:40 -0800640static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = {
Omar Sandoval9abb2ad2017-01-25 08:06:41 -0800641 {"state", 0400, &hctx_state_fops},
642 {"flags", 0400, &hctx_flags_fops},
Omar Sandoval950cd7e2017-01-25 08:06:42 -0800643 {"dispatch", 0400, &hctx_dispatch_fops},
Omar Sandoval0bfa5282017-01-25 08:06:45 -0800644 {"ctx_map", 0400, &hctx_ctx_map_fops},
Omar Sandovald96b37c2017-01-25 08:06:46 -0800645 {"tags", 0400, &hctx_tags_fops},
Omar Sandovald7e36212017-01-25 08:06:47 -0800646 {"tags_bitmap", 0400, &hctx_tags_bitmap_fops},
Omar Sandovald96b37c2017-01-25 08:06:46 -0800647 {"sched_tags", 0400, &hctx_sched_tags_fops},
Omar Sandovald7e36212017-01-25 08:06:47 -0800648 {"sched_tags_bitmap", 0400, &hctx_sched_tags_bitmap_fops},
Omar Sandovalbe215472017-01-25 08:06:48 -0800649 {"io_poll", 0600, &hctx_io_poll_fops},
650 {"stats", 0600, &hctx_stats_fops},
651 {"dispatched", 0600, &hctx_dispatched_fops},
Omar Sandoval4a46f052017-01-25 08:06:49 -0800652 {"queued", 0600, &hctx_queued_fops},
653 {"run", 0600, &hctx_run_fops},
654 {"active", 0400, &hctx_active_fops},
Bart Van Assche72f2f8f2017-02-01 10:20:59 -0800655 {},
Omar Sandoval07e4fea2017-01-25 08:06:40 -0800656};
657
658static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = {
Omar Sandoval950cd7e2017-01-25 08:06:42 -0800659 {"rq_list", 0400, &ctx_rq_list_fops},
Omar Sandoval4a46f052017-01-25 08:06:49 -0800660 {"dispatched", 0600, &ctx_dispatched_fops},
661 {"merged", 0600, &ctx_merged_fops},
662 {"completed", 0600, &ctx_completed_fops},
Bart Van Assche72f2f8f2017-02-01 10:20:59 -0800663 {},
Omar Sandoval07e4fea2017-01-25 08:06:40 -0800664};
665
666int blk_mq_debugfs_register(struct request_queue *q, const char *name)
667{
668 if (!block_debugfs_root)
669 return -ENOENT;
670
671 q->debugfs_dir = debugfs_create_dir(name, block_debugfs_root);
672 if (!q->debugfs_dir)
673 goto err;
674
675 if (blk_mq_debugfs_register_hctxs(q))
676 goto err;
677
678 return 0;
679
680err:
681 blk_mq_debugfs_unregister(q);
682 return -ENOMEM;
683}
684
685void blk_mq_debugfs_unregister(struct request_queue *q)
686{
687 debugfs_remove_recursive(q->debugfs_dir);
688 q->mq_debugfs_dir = NULL;
689 q->debugfs_dir = NULL;
690}
691
Bart Van Assche72f2f8f2017-02-01 10:20:59 -0800692static bool debugfs_create_files(struct dentry *parent, void *data,
693 const struct blk_mq_debugfs_attr *attr)
694{
695 for (; attr->name; attr++) {
696 if (!debugfs_create_file(attr->name, attr->mode, parent,
697 data, attr->fops))
698 return false;
699 }
700 return true;
701}
702
Omar Sandoval07e4fea2017-01-25 08:06:40 -0800703static int blk_mq_debugfs_register_ctx(struct request_queue *q,
704 struct blk_mq_ctx *ctx,
705 struct dentry *hctx_dir)
706{
707 struct dentry *ctx_dir;
708 char name[20];
Omar Sandoval07e4fea2017-01-25 08:06:40 -0800709
710 snprintf(name, sizeof(name), "cpu%u", ctx->cpu);
711 ctx_dir = debugfs_create_dir(name, hctx_dir);
712 if (!ctx_dir)
713 return -ENOMEM;
714
Bart Van Assche72f2f8f2017-02-01 10:20:59 -0800715 if (!debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs))
716 return -ENOMEM;
Omar Sandoval07e4fea2017-01-25 08:06:40 -0800717
718 return 0;
719}
720
721static int blk_mq_debugfs_register_hctx(struct request_queue *q,
722 struct blk_mq_hw_ctx *hctx)
723{
724 struct blk_mq_ctx *ctx;
725 struct dentry *hctx_dir;
726 char name[20];
727 int i;
728
729 snprintf(name, sizeof(name), "%u", hctx->queue_num);
730 hctx_dir = debugfs_create_dir(name, q->mq_debugfs_dir);
731 if (!hctx_dir)
732 return -ENOMEM;
733
Bart Van Assche72f2f8f2017-02-01 10:20:59 -0800734 if (!debugfs_create_files(hctx_dir, hctx, blk_mq_debugfs_hctx_attrs))
735 return -ENOMEM;
Omar Sandoval07e4fea2017-01-25 08:06:40 -0800736
737 hctx_for_each_ctx(hctx, ctx, i) {
738 if (blk_mq_debugfs_register_ctx(q, ctx, hctx_dir))
739 return -ENOMEM;
740 }
741
742 return 0;
743}
744
745int blk_mq_debugfs_register_hctxs(struct request_queue *q)
746{
747 struct blk_mq_hw_ctx *hctx;
748 int i;
749
750 if (!q->debugfs_dir)
751 return -ENOENT;
752
753 q->mq_debugfs_dir = debugfs_create_dir("mq", q->debugfs_dir);
754 if (!q->mq_debugfs_dir)
755 goto err;
756
757 queue_for_each_hw_ctx(q, hctx, i) {
758 if (blk_mq_debugfs_register_hctx(q, hctx))
759 goto err;
760 }
761
762 return 0;
763
764err:
765 blk_mq_debugfs_unregister_hctxs(q);
766 return -ENOMEM;
767}
768
769void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
770{
771 debugfs_remove_recursive(q->mq_debugfs_dir);
772 q->mq_debugfs_dir = NULL;
773}
774
775void blk_mq_debugfs_init(void)
776{
777 block_debugfs_root = debugfs_create_dir("block", NULL);
778}