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