Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Copyright (C) 2017 Facebook
4 : : */
5 : :
6 : : #include <linux/kernel.h>
7 : : #include <linux/blkdev.h>
8 : : #include <linux/debugfs.h>
9 : :
10 : : #include <linux/blk-mq.h>
11 : : #include "blk.h"
12 : : #include "blk-mq.h"
13 : : #include "blk-mq-debugfs.h"
14 : : #include "blk-mq-tag.h"
15 : : #include "blk-rq-qos.h"
16 : :
17 : 0 : static void print_stat(struct seq_file *m, struct blk_rq_stat *stat)
18 : : {
19 [ # # ]: 0 : if (stat->nr_samples) {
20 : 0 : seq_printf(m, "samples=%d, mean=%llu, min=%llu, max=%llu",
21 : : stat->nr_samples, stat->mean, stat->min, stat->max);
22 : : } else {
23 : 0 : seq_puts(m, "samples=0");
24 : : }
25 : 0 : }
26 : :
27 : 0 : static int queue_poll_stat_show(void *data, struct seq_file *m)
28 : : {
29 : : struct request_queue *q = data;
30 : : int bucket;
31 : :
32 [ # # ]: 0 : for (bucket = 0; bucket < (BLK_MQ_POLL_STATS_BKTS / 2); bucket++) {
33 : 0 : seq_printf(m, "read (%d Bytes): ", 1 << (9 + bucket));
34 : 0 : print_stat(m, &q->poll_stat[2 * bucket]);
35 : 0 : seq_puts(m, "\n");
36 : :
37 : 0 : seq_printf(m, "write (%d Bytes): ", 1 << (9 + bucket));
38 : 0 : print_stat(m, &q->poll_stat[2 * bucket + 1]);
39 : 0 : seq_puts(m, "\n");
40 : : }
41 : 0 : return 0;
42 : : }
43 : :
44 : 0 : static void *queue_requeue_list_start(struct seq_file *m, loff_t *pos)
45 : : __acquires(&q->requeue_lock)
46 : : {
47 : 0 : struct request_queue *q = m->private;
48 : :
49 : : spin_lock_irq(&q->requeue_lock);
50 : 0 : return seq_list_start(&q->requeue_list, *pos);
51 : : }
52 : :
53 : 0 : static void *queue_requeue_list_next(struct seq_file *m, void *v, loff_t *pos)
54 : : {
55 : 0 : struct request_queue *q = m->private;
56 : :
57 : 0 : return seq_list_next(v, &q->requeue_list, pos);
58 : : }
59 : :
60 : 0 : static void queue_requeue_list_stop(struct seq_file *m, void *v)
61 : : __releases(&q->requeue_lock)
62 : : {
63 : 0 : struct request_queue *q = m->private;
64 : :
65 : : spin_unlock_irq(&q->requeue_lock);
66 : 0 : }
67 : :
68 : : static const struct seq_operations queue_requeue_list_seq_ops = {
69 : : .start = queue_requeue_list_start,
70 : : .next = queue_requeue_list_next,
71 : : .stop = queue_requeue_list_stop,
72 : : .show = blk_mq_debugfs_rq_show,
73 : : };
74 : :
75 : 0 : static int blk_flags_show(struct seq_file *m, const unsigned long flags,
76 : : const char *const *flag_name, int flag_name_count)
77 : : {
78 : : bool sep = false;
79 : : int i;
80 : :
81 [ # # ]: 0 : for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) {
82 [ # # ]: 0 : if (!(flags & BIT(i)))
83 : 0 : continue;
84 [ # # ]: 0 : if (sep)
85 : 0 : seq_puts(m, "|");
86 : : sep = true;
87 [ # # # # ]: 0 : if (i < flag_name_count && flag_name[i])
88 : 0 : seq_puts(m, flag_name[i]);
89 : : else
90 : 0 : seq_printf(m, "%d", i);
91 : : }
92 : 0 : return 0;
93 : : }
94 : :
95 : 0 : static int queue_pm_only_show(void *data, struct seq_file *m)
96 : : {
97 : : struct request_queue *q = data;
98 : :
99 : 0 : seq_printf(m, "%d\n", atomic_read(&q->pm_only));
100 : 0 : return 0;
101 : : }
102 : :
103 : : #define QUEUE_FLAG_NAME(name) [QUEUE_FLAG_##name] = #name
104 : : static const char *const blk_queue_flag_name[] = {
105 : : QUEUE_FLAG_NAME(STOPPED),
106 : : QUEUE_FLAG_NAME(DYING),
107 : : QUEUE_FLAG_NAME(NOMERGES),
108 : : QUEUE_FLAG_NAME(SAME_COMP),
109 : : QUEUE_FLAG_NAME(FAIL_IO),
110 : : QUEUE_FLAG_NAME(NONROT),
111 : : QUEUE_FLAG_NAME(IO_STAT),
112 : : QUEUE_FLAG_NAME(DISCARD),
113 : : QUEUE_FLAG_NAME(NOXMERGES),
114 : : QUEUE_FLAG_NAME(ADD_RANDOM),
115 : : QUEUE_FLAG_NAME(SECERASE),
116 : : QUEUE_FLAG_NAME(SAME_FORCE),
117 : : QUEUE_FLAG_NAME(DEAD),
118 : : QUEUE_FLAG_NAME(INIT_DONE),
119 : : QUEUE_FLAG_NAME(POLL),
120 : : QUEUE_FLAG_NAME(WC),
121 : : QUEUE_FLAG_NAME(FUA),
122 : : QUEUE_FLAG_NAME(DAX),
123 : : QUEUE_FLAG_NAME(STATS),
124 : : QUEUE_FLAG_NAME(POLL_STATS),
125 : : QUEUE_FLAG_NAME(REGISTERED),
126 : : QUEUE_FLAG_NAME(SCSI_PASSTHROUGH),
127 : : QUEUE_FLAG_NAME(QUIESCED),
128 : : QUEUE_FLAG_NAME(PCI_P2PDMA),
129 : : QUEUE_FLAG_NAME(ZONE_RESETALL),
130 : : QUEUE_FLAG_NAME(RQ_ALLOC_TIME),
131 : : };
132 : : #undef QUEUE_FLAG_NAME
133 : :
134 : 0 : static int queue_state_show(void *data, struct seq_file *m)
135 : : {
136 : : struct request_queue *q = data;
137 : :
138 : 0 : blk_flags_show(m, q->queue_flags, blk_queue_flag_name,
139 : : ARRAY_SIZE(blk_queue_flag_name));
140 : 0 : seq_puts(m, "\n");
141 : 0 : return 0;
142 : : }
143 : :
144 : 0 : static ssize_t queue_state_write(void *data, const char __user *buf,
145 : : size_t count, loff_t *ppos)
146 : : {
147 : : struct request_queue *q = data;
148 : 0 : char opbuf[16] = { }, *op;
149 : :
150 : : /*
151 : : * The "state" attribute is removed after blk_cleanup_queue() has called
152 : : * blk_mq_free_queue(). Return if QUEUE_FLAG_DEAD has been set to avoid
153 : : * triggering a use-after-free.
154 : : */
155 [ # # ]: 0 : if (blk_queue_dead(q))
156 : : return -ENOENT;
157 : :
158 [ # # ]: 0 : if (count >= sizeof(opbuf)) {
159 : 0 : pr_err("%s: operation too long\n", __func__);
160 : 0 : goto inval;
161 : : }
162 : :
163 [ # # ]: 0 : if (copy_from_user(opbuf, buf, count))
164 : : return -EFAULT;
165 : : op = strstrip(opbuf);
166 [ # # ]: 0 : if (strcmp(op, "run") == 0) {
167 : 0 : blk_mq_run_hw_queues(q, true);
168 [ # # ]: 0 : } else if (strcmp(op, "start") == 0) {
169 : 0 : blk_mq_start_stopped_hw_queues(q, true);
170 [ # # ]: 0 : } else if (strcmp(op, "kick") == 0) {
171 : 0 : blk_mq_kick_requeue_list(q);
172 : : } else {
173 : 0 : pr_err("%s: unsupported operation '%s'\n", __func__, op);
174 : : inval:
175 : 0 : pr_err("%s: use 'run', 'start' or 'kick'\n", __func__);
176 : 0 : return -EINVAL;
177 : : }
178 : 0 : return count;
179 : : }
180 : :
181 : 0 : static int queue_write_hint_show(void *data, struct seq_file *m)
182 : : {
183 : : struct request_queue *q = data;
184 : : int i;
185 : :
186 [ # # ]: 0 : for (i = 0; i < BLK_MAX_WRITE_HINTS; i++)
187 : 0 : seq_printf(m, "hint%d: %llu\n", i, q->write_hints[i]);
188 : :
189 : 0 : return 0;
190 : : }
191 : :
192 : 0 : static ssize_t queue_write_hint_store(void *data, const char __user *buf,
193 : : size_t count, loff_t *ppos)
194 : : {
195 : : struct request_queue *q = data;
196 : : int i;
197 : :
198 [ # # ]: 0 : for (i = 0; i < BLK_MAX_WRITE_HINTS; i++)
199 : 0 : q->write_hints[i] = 0;
200 : :
201 : 0 : return count;
202 : : }
203 : :
204 : : static const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = {
205 : : { "poll_stat", 0400, queue_poll_stat_show },
206 : : { "requeue_list", 0400, .seq_ops = &queue_requeue_list_seq_ops },
207 : : { "pm_only", 0600, queue_pm_only_show, NULL },
208 : : { "state", 0600, queue_state_show, queue_state_write },
209 : : { "write_hints", 0600, queue_write_hint_show, queue_write_hint_store },
210 : : { "zone_wlock", 0400, queue_zone_wlock_show, NULL },
211 : : { },
212 : : };
213 : :
214 : : #define HCTX_STATE_NAME(name) [BLK_MQ_S_##name] = #name
215 : : static const char *const hctx_state_name[] = {
216 : : HCTX_STATE_NAME(STOPPED),
217 : : HCTX_STATE_NAME(TAG_ACTIVE),
218 : : HCTX_STATE_NAME(SCHED_RESTART),
219 : : };
220 : : #undef HCTX_STATE_NAME
221 : :
222 : 0 : static int hctx_state_show(void *data, struct seq_file *m)
223 : : {
224 : : struct blk_mq_hw_ctx *hctx = data;
225 : :
226 : 0 : blk_flags_show(m, hctx->state, hctx_state_name,
227 : : ARRAY_SIZE(hctx_state_name));
228 : 0 : seq_puts(m, "\n");
229 : 0 : return 0;
230 : : }
231 : :
232 : : #define BLK_TAG_ALLOC_NAME(name) [BLK_TAG_ALLOC_##name] = #name
233 : : static const char *const alloc_policy_name[] = {
234 : : BLK_TAG_ALLOC_NAME(FIFO),
235 : : BLK_TAG_ALLOC_NAME(RR),
236 : : };
237 : : #undef BLK_TAG_ALLOC_NAME
238 : :
239 : : #define HCTX_FLAG_NAME(name) [ilog2(BLK_MQ_F_##name)] = #name
240 : : static const char *const hctx_flag_name[] = {
241 : : HCTX_FLAG_NAME(SHOULD_MERGE),
242 : : HCTX_FLAG_NAME(TAG_SHARED),
243 : : HCTX_FLAG_NAME(BLOCKING),
244 : : HCTX_FLAG_NAME(NO_SCHED),
245 : : };
246 : : #undef HCTX_FLAG_NAME
247 : :
248 : 0 : static int hctx_flags_show(void *data, struct seq_file *m)
249 : : {
250 : : struct blk_mq_hw_ctx *hctx = data;
251 : 0 : const int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(hctx->flags);
252 : :
253 : 0 : seq_puts(m, "alloc_policy=");
254 [ # # # # ]: 0 : if (alloc_policy < ARRAY_SIZE(alloc_policy_name) &&
255 : 0 : alloc_policy_name[alloc_policy])
256 : 0 : seq_puts(m, alloc_policy_name[alloc_policy]);
257 : : else
258 : 0 : seq_printf(m, "%d", alloc_policy);
259 : 0 : seq_puts(m, " ");
260 : 0 : blk_flags_show(m,
261 : 0 : hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy),
262 : : hctx_flag_name, ARRAY_SIZE(hctx_flag_name));
263 : 0 : seq_puts(m, "\n");
264 : 0 : return 0;
265 : : }
266 : :
267 : : #define CMD_FLAG_NAME(name) [__REQ_##name] = #name
268 : : static const char *const cmd_flag_name[] = {
269 : : CMD_FLAG_NAME(FAILFAST_DEV),
270 : : CMD_FLAG_NAME(FAILFAST_TRANSPORT),
271 : : CMD_FLAG_NAME(FAILFAST_DRIVER),
272 : : CMD_FLAG_NAME(SYNC),
273 : : CMD_FLAG_NAME(META),
274 : : CMD_FLAG_NAME(PRIO),
275 : : CMD_FLAG_NAME(NOMERGE),
276 : : CMD_FLAG_NAME(IDLE),
277 : : CMD_FLAG_NAME(INTEGRITY),
278 : : CMD_FLAG_NAME(FUA),
279 : : CMD_FLAG_NAME(PREFLUSH),
280 : : CMD_FLAG_NAME(RAHEAD),
281 : : CMD_FLAG_NAME(BACKGROUND),
282 : : CMD_FLAG_NAME(NOWAIT),
283 : : CMD_FLAG_NAME(NOUNMAP),
284 : : CMD_FLAG_NAME(HIPRI),
285 : : };
286 : : #undef CMD_FLAG_NAME
287 : :
288 : : #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name
289 : : static const char *const rqf_name[] = {
290 : : RQF_NAME(SORTED),
291 : : RQF_NAME(STARTED),
292 : : RQF_NAME(SOFTBARRIER),
293 : : RQF_NAME(FLUSH_SEQ),
294 : : RQF_NAME(MIXED_MERGE),
295 : : RQF_NAME(MQ_INFLIGHT),
296 : : RQF_NAME(DONTPREP),
297 : : RQF_NAME(PREEMPT),
298 : : RQF_NAME(COPY_USER),
299 : : RQF_NAME(FAILED),
300 : : RQF_NAME(QUIET),
301 : : RQF_NAME(ELVPRIV),
302 : : RQF_NAME(IO_STAT),
303 : : RQF_NAME(ALLOCED),
304 : : RQF_NAME(PM),
305 : : RQF_NAME(HASHED),
306 : : RQF_NAME(STATS),
307 : : RQF_NAME(SPECIAL_PAYLOAD),
308 : : RQF_NAME(ZONE_WRITE_LOCKED),
309 : : RQF_NAME(MQ_POLL_SLEPT),
310 : : };
311 : : #undef RQF_NAME
312 : :
313 : : static const char *const blk_mq_rq_state_name_array[] = {
314 : : [MQ_RQ_IDLE] = "idle",
315 : : [MQ_RQ_IN_FLIGHT] = "in_flight",
316 : : [MQ_RQ_COMPLETE] = "complete",
317 : : };
318 : :
319 : 0 : static const char *blk_mq_rq_state_name(enum mq_rq_state rq_state)
320 : : {
321 [ # # # # : 0 : if (WARN_ON_ONCE((unsigned int)rq_state >=
# # ]
322 : : ARRAY_SIZE(blk_mq_rq_state_name_array)))
323 : : return "(?)";
324 : 0 : return blk_mq_rq_state_name_array[rq_state];
325 : : }
326 : :
327 : 0 : int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq)
328 : : {
329 : 0 : const struct blk_mq_ops *const mq_ops = rq->q->mq_ops;
330 : 0 : const unsigned int op = req_op(rq);
331 : 0 : const char *op_str = blk_op_str(op);
332 : :
333 : 0 : seq_printf(m, "%p {.op=", rq);
334 [ # # ]: 0 : if (strcmp(op_str, "UNKNOWN") == 0)
335 : 0 : seq_printf(m, "%u", op);
336 : : else
337 : 0 : seq_printf(m, "%s", op_str);
338 : 0 : seq_puts(m, ", .cmd_flags=");
339 : 0 : blk_flags_show(m, rq->cmd_flags & ~REQ_OP_MASK, cmd_flag_name,
340 : : ARRAY_SIZE(cmd_flag_name));
341 : 0 : seq_puts(m, ", .rq_flags=");
342 : 0 : blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name,
343 : : ARRAY_SIZE(rqf_name));
344 : 0 : seq_printf(m, ", .state=%s", blk_mq_rq_state_name(blk_mq_rq_state(rq)));
345 : 0 : seq_printf(m, ", .tag=%d, .internal_tag=%d", rq->tag,
346 : : rq->internal_tag);
347 [ # # ]: 0 : if (mq_ops->show_rq)
348 : 0 : mq_ops->show_rq(m, rq);
349 : 0 : seq_puts(m, "}\n");
350 : 0 : return 0;
351 : : }
352 : : EXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show);
353 : :
354 : 0 : int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
355 : : {
356 : 0 : return __blk_mq_debugfs_rq_show(m, list_entry_rq(v));
357 : : }
358 : : EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show);
359 : :
360 : 0 : static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos)
361 : : __acquires(&hctx->lock)
362 : : {
363 : 0 : struct blk_mq_hw_ctx *hctx = m->private;
364 : :
365 : : spin_lock(&hctx->lock);
366 : 0 : return seq_list_start(&hctx->dispatch, *pos);
367 : : }
368 : :
369 : 0 : static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos)
370 : : {
371 : 0 : struct blk_mq_hw_ctx *hctx = m->private;
372 : :
373 : 0 : return seq_list_next(v, &hctx->dispatch, pos);
374 : : }
375 : :
376 : 0 : static void hctx_dispatch_stop(struct seq_file *m, void *v)
377 : : __releases(&hctx->lock)
378 : : {
379 : 0 : struct blk_mq_hw_ctx *hctx = m->private;
380 : :
381 : : spin_unlock(&hctx->lock);
382 : 0 : }
383 : :
384 : : static const struct seq_operations hctx_dispatch_seq_ops = {
385 : : .start = hctx_dispatch_start,
386 : : .next = hctx_dispatch_next,
387 : : .stop = hctx_dispatch_stop,
388 : : .show = blk_mq_debugfs_rq_show,
389 : : };
390 : :
391 : : struct show_busy_params {
392 : : struct seq_file *m;
393 : : struct blk_mq_hw_ctx *hctx;
394 : : };
395 : :
396 : : /*
397 : : * Note: the state of a request may change while this function is in progress,
398 : : * e.g. due to a concurrent blk_mq_finish_request() call. Returns true to
399 : : * keep iterating requests.
400 : : */
401 : 0 : static bool hctx_show_busy_rq(struct request *rq, void *data, bool reserved)
402 : : {
403 : : const struct show_busy_params *params = data;
404 : :
405 [ # # ]: 0 : if (rq->mq_hctx == params->hctx)
406 : 0 : __blk_mq_debugfs_rq_show(params->m,
407 : : list_entry_rq(&rq->queuelist));
408 : :
409 : 0 : return true;
410 : : }
411 : :
412 : 0 : static int hctx_busy_show(void *data, struct seq_file *m)
413 : : {
414 : : struct blk_mq_hw_ctx *hctx = data;
415 : 0 : struct show_busy_params params = { .m = m, .hctx = hctx };
416 : :
417 : 0 : blk_mq_tagset_busy_iter(hctx->queue->tag_set, hctx_show_busy_rq,
418 : : ¶ms);
419 : :
420 : 0 : return 0;
421 : : }
422 : :
423 : : static const char *const hctx_types[] = {
424 : : [HCTX_TYPE_DEFAULT] = "default",
425 : : [HCTX_TYPE_READ] = "read",
426 : : [HCTX_TYPE_POLL] = "poll",
427 : : };
428 : :
429 : 0 : static int hctx_type_show(void *data, struct seq_file *m)
430 : : {
431 : : struct blk_mq_hw_ctx *hctx = data;
432 : :
433 : : BUILD_BUG_ON(ARRAY_SIZE(hctx_types) != HCTX_MAX_TYPES);
434 : 0 : seq_printf(m, "%s\n", hctx_types[hctx->type]);
435 : 0 : return 0;
436 : : }
437 : :
438 : 0 : static int hctx_ctx_map_show(void *data, struct seq_file *m)
439 : : {
440 : : struct blk_mq_hw_ctx *hctx = data;
441 : :
442 : 0 : sbitmap_bitmap_show(&hctx->ctx_map, m);
443 : 0 : return 0;
444 : : }
445 : :
446 : 0 : static void blk_mq_debugfs_tags_show(struct seq_file *m,
447 : : struct blk_mq_tags *tags)
448 : : {
449 : 0 : seq_printf(m, "nr_tags=%u\n", tags->nr_tags);
450 : 0 : seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags);
451 : 0 : seq_printf(m, "active_queues=%d\n",
452 : 0 : atomic_read(&tags->active_queues));
453 : :
454 : 0 : seq_puts(m, "\nbitmap_tags:\n");
455 : 0 : sbitmap_queue_show(&tags->bitmap_tags, m);
456 : :
457 [ # # ]: 0 : if (tags->nr_reserved_tags) {
458 : 0 : seq_puts(m, "\nbreserved_tags:\n");
459 : 0 : sbitmap_queue_show(&tags->breserved_tags, m);
460 : : }
461 : 0 : }
462 : :
463 : 0 : static int hctx_tags_show(void *data, struct seq_file *m)
464 : : {
465 : : struct blk_mq_hw_ctx *hctx = data;
466 : 0 : struct request_queue *q = hctx->queue;
467 : : int res;
468 : :
469 : 0 : res = mutex_lock_interruptible(&q->sysfs_lock);
470 [ # # ]: 0 : if (res)
471 : : goto out;
472 [ # # ]: 0 : if (hctx->tags)
473 : 0 : blk_mq_debugfs_tags_show(m, hctx->tags);
474 : 0 : mutex_unlock(&q->sysfs_lock);
475 : :
476 : : out:
477 : 0 : return res;
478 : : }
479 : :
480 : 0 : static int hctx_tags_bitmap_show(void *data, struct seq_file *m)
481 : : {
482 : : struct blk_mq_hw_ctx *hctx = data;
483 : 0 : struct request_queue *q = hctx->queue;
484 : : int res;
485 : :
486 : 0 : res = mutex_lock_interruptible(&q->sysfs_lock);
487 [ # # ]: 0 : if (res)
488 : : goto out;
489 [ # # ]: 0 : if (hctx->tags)
490 : 0 : sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m);
491 : 0 : mutex_unlock(&q->sysfs_lock);
492 : :
493 : : out:
494 : 0 : return res;
495 : : }
496 : :
497 : 0 : static int hctx_sched_tags_show(void *data, struct seq_file *m)
498 : : {
499 : : struct blk_mq_hw_ctx *hctx = data;
500 : 0 : struct request_queue *q = hctx->queue;
501 : : int res;
502 : :
503 : 0 : res = mutex_lock_interruptible(&q->sysfs_lock);
504 [ # # ]: 0 : if (res)
505 : : goto out;
506 [ # # ]: 0 : if (hctx->sched_tags)
507 : 0 : blk_mq_debugfs_tags_show(m, hctx->sched_tags);
508 : 0 : mutex_unlock(&q->sysfs_lock);
509 : :
510 : : out:
511 : 0 : return res;
512 : : }
513 : :
514 : 0 : static int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m)
515 : : {
516 : : struct blk_mq_hw_ctx *hctx = data;
517 : 0 : struct request_queue *q = hctx->queue;
518 : : int res;
519 : :
520 : 0 : res = mutex_lock_interruptible(&q->sysfs_lock);
521 [ # # ]: 0 : if (res)
522 : : goto out;
523 [ # # ]: 0 : if (hctx->sched_tags)
524 : 0 : sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m);
525 : 0 : mutex_unlock(&q->sysfs_lock);
526 : :
527 : : out:
528 : 0 : return res;
529 : : }
530 : :
531 : 0 : static int hctx_io_poll_show(void *data, struct seq_file *m)
532 : : {
533 : : struct blk_mq_hw_ctx *hctx = data;
534 : :
535 : 0 : seq_printf(m, "considered=%lu\n", hctx->poll_considered);
536 : 0 : seq_printf(m, "invoked=%lu\n", hctx->poll_invoked);
537 : 0 : seq_printf(m, "success=%lu\n", hctx->poll_success);
538 : 0 : return 0;
539 : : }
540 : :
541 : 0 : static ssize_t hctx_io_poll_write(void *data, const char __user *buf,
542 : : size_t count, loff_t *ppos)
543 : : {
544 : : struct blk_mq_hw_ctx *hctx = data;
545 : :
546 : 0 : hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0;
547 : 0 : return count;
548 : : }
549 : :
550 : 0 : static int hctx_dispatched_show(void *data, struct seq_file *m)
551 : : {
552 : : struct blk_mq_hw_ctx *hctx = data;
553 : : int i;
554 : :
555 : 0 : seq_printf(m, "%8u\t%lu\n", 0U, hctx->dispatched[0]);
556 : :
557 [ # # ]: 0 : for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) {
558 : 0 : unsigned int d = 1U << (i - 1);
559 : :
560 : 0 : seq_printf(m, "%8u\t%lu\n", d, hctx->dispatched[i]);
561 : : }
562 : :
563 : 0 : seq_printf(m, "%8u+\t%lu\n", 1U << (i - 1), hctx->dispatched[i]);
564 : 0 : return 0;
565 : : }
566 : :
567 : 0 : static ssize_t hctx_dispatched_write(void *data, const char __user *buf,
568 : : size_t count, loff_t *ppos)
569 : : {
570 : : struct blk_mq_hw_ctx *hctx = data;
571 : : int i;
572 : :
573 [ # # ]: 0 : for (i = 0; i < BLK_MQ_MAX_DISPATCH_ORDER; i++)
574 : 0 : hctx->dispatched[i] = 0;
575 : 0 : return count;
576 : : }
577 : :
578 : 0 : static int hctx_queued_show(void *data, struct seq_file *m)
579 : : {
580 : : struct blk_mq_hw_ctx *hctx = data;
581 : :
582 : 0 : seq_printf(m, "%lu\n", hctx->queued);
583 : 0 : return 0;
584 : : }
585 : :
586 : 0 : static ssize_t hctx_queued_write(void *data, const char __user *buf,
587 : : size_t count, loff_t *ppos)
588 : : {
589 : : struct blk_mq_hw_ctx *hctx = data;
590 : :
591 : 0 : hctx->queued = 0;
592 : 0 : return count;
593 : : }
594 : :
595 : 0 : static int hctx_run_show(void *data, struct seq_file *m)
596 : : {
597 : : struct blk_mq_hw_ctx *hctx = data;
598 : :
599 : 0 : seq_printf(m, "%lu\n", hctx->run);
600 : 0 : return 0;
601 : : }
602 : :
603 : 0 : static ssize_t hctx_run_write(void *data, const char __user *buf, size_t count,
604 : : loff_t *ppos)
605 : : {
606 : : struct blk_mq_hw_ctx *hctx = data;
607 : :
608 : 0 : hctx->run = 0;
609 : 0 : return count;
610 : : }
611 : :
612 : 0 : static int hctx_active_show(void *data, struct seq_file *m)
613 : : {
614 : : struct blk_mq_hw_ctx *hctx = data;
615 : :
616 : 0 : seq_printf(m, "%d\n", atomic_read(&hctx->nr_active));
617 : 0 : return 0;
618 : : }
619 : :
620 : 0 : static int hctx_dispatch_busy_show(void *data, struct seq_file *m)
621 : : {
622 : : struct blk_mq_hw_ctx *hctx = data;
623 : :
624 : 0 : seq_printf(m, "%u\n", hctx->dispatch_busy);
625 : 0 : return 0;
626 : : }
627 : :
628 : : #define CTX_RQ_SEQ_OPS(name, type) \
629 : : static void *ctx_##name##_rq_list_start(struct seq_file *m, loff_t *pos) \
630 : : __acquires(&ctx->lock) \
631 : : { \
632 : : struct blk_mq_ctx *ctx = m->private; \
633 : : \
634 : : spin_lock(&ctx->lock); \
635 : : return seq_list_start(&ctx->rq_lists[type], *pos); \
636 : : } \
637 : : \
638 : : static void *ctx_##name##_rq_list_next(struct seq_file *m, void *v, \
639 : : loff_t *pos) \
640 : : { \
641 : : struct blk_mq_ctx *ctx = m->private; \
642 : : \
643 : : return seq_list_next(v, &ctx->rq_lists[type], pos); \
644 : : } \
645 : : \
646 : : static void ctx_##name##_rq_list_stop(struct seq_file *m, void *v) \
647 : : __releases(&ctx->lock) \
648 : : { \
649 : : struct blk_mq_ctx *ctx = m->private; \
650 : : \
651 : : spin_unlock(&ctx->lock); \
652 : : } \
653 : : \
654 : : static const struct seq_operations ctx_##name##_rq_list_seq_ops = { \
655 : : .start = ctx_##name##_rq_list_start, \
656 : : .next = ctx_##name##_rq_list_next, \
657 : : .stop = ctx_##name##_rq_list_stop, \
658 : : .show = blk_mq_debugfs_rq_show, \
659 : : }
660 : :
661 : 0 : CTX_RQ_SEQ_OPS(default, HCTX_TYPE_DEFAULT);
662 : 0 : CTX_RQ_SEQ_OPS(read, HCTX_TYPE_READ);
663 : 0 : CTX_RQ_SEQ_OPS(poll, HCTX_TYPE_POLL);
664 : :
665 : 0 : static int ctx_dispatched_show(void *data, struct seq_file *m)
666 : : {
667 : : struct blk_mq_ctx *ctx = data;
668 : :
669 : 0 : seq_printf(m, "%lu %lu\n", ctx->rq_dispatched[1], ctx->rq_dispatched[0]);
670 : 0 : return 0;
671 : : }
672 : :
673 : 0 : static ssize_t ctx_dispatched_write(void *data, const char __user *buf,
674 : : size_t count, loff_t *ppos)
675 : : {
676 : : struct blk_mq_ctx *ctx = data;
677 : :
678 : 0 : ctx->rq_dispatched[0] = ctx->rq_dispatched[1] = 0;
679 : 0 : return count;
680 : : }
681 : :
682 : 0 : static int ctx_merged_show(void *data, struct seq_file *m)
683 : : {
684 : : struct blk_mq_ctx *ctx = data;
685 : :
686 : 0 : seq_printf(m, "%lu\n", ctx->rq_merged);
687 : 0 : return 0;
688 : : }
689 : :
690 : 0 : static ssize_t ctx_merged_write(void *data, const char __user *buf,
691 : : size_t count, loff_t *ppos)
692 : : {
693 : : struct blk_mq_ctx *ctx = data;
694 : :
695 : 0 : ctx->rq_merged = 0;
696 : 0 : return count;
697 : : }
698 : :
699 : 0 : static int ctx_completed_show(void *data, struct seq_file *m)
700 : : {
701 : : struct blk_mq_ctx *ctx = data;
702 : :
703 : 0 : seq_printf(m, "%lu %lu\n", ctx->rq_completed[1], ctx->rq_completed[0]);
704 : 0 : return 0;
705 : : }
706 : :
707 : 0 : static ssize_t ctx_completed_write(void *data, const char __user *buf,
708 : : size_t count, loff_t *ppos)
709 : : {
710 : : struct blk_mq_ctx *ctx = data;
711 : :
712 : 0 : ctx->rq_completed[0] = ctx->rq_completed[1] = 0;
713 : 0 : return count;
714 : : }
715 : :
716 : 0 : static int blk_mq_debugfs_show(struct seq_file *m, void *v)
717 : : {
718 : 0 : const struct blk_mq_debugfs_attr *attr = m->private;
719 : 0 : void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private;
720 : :
721 : 0 : return attr->show(data, m);
722 : : }
723 : :
724 : 0 : static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf,
725 : : size_t count, loff_t *ppos)
726 : : {
727 : 0 : struct seq_file *m = file->private_data;
728 : 0 : const struct blk_mq_debugfs_attr *attr = m->private;
729 : 0 : void *data = d_inode(file->f_path.dentry->d_parent)->i_private;
730 : :
731 : : /*
732 : : * Attributes that only implement .seq_ops are read-only and 'attr' is
733 : : * the same with 'data' in this case.
734 : : */
735 [ # # # # ]: 0 : if (attr == data || !attr->write)
736 : : return -EPERM;
737 : :
738 : 0 : return attr->write(data, buf, count, ppos);
739 : : }
740 : :
741 : 0 : static int blk_mq_debugfs_open(struct inode *inode, struct file *file)
742 : : {
743 : 0 : const struct blk_mq_debugfs_attr *attr = inode->i_private;
744 : 0 : void *data = d_inode(file->f_path.dentry->d_parent)->i_private;
745 : : struct seq_file *m;
746 : : int ret;
747 : :
748 [ # # ]: 0 : if (attr->seq_ops) {
749 : 0 : ret = seq_open(file, attr->seq_ops);
750 [ # # ]: 0 : if (!ret) {
751 : 0 : m = file->private_data;
752 : 0 : m->private = data;
753 : : }
754 : 0 : return ret;
755 : : }
756 : :
757 [ # # # # : 0 : if (WARN_ON_ONCE(!attr->show))
# # ]
758 : : return -EPERM;
759 : :
760 : 0 : return single_open(file, blk_mq_debugfs_show, inode->i_private);
761 : : }
762 : :
763 : 0 : static int blk_mq_debugfs_release(struct inode *inode, struct file *file)
764 : : {
765 : 0 : const struct blk_mq_debugfs_attr *attr = inode->i_private;
766 : :
767 [ # # ]: 0 : if (attr->show)
768 : 0 : return single_release(inode, file);
769 : :
770 : 0 : return seq_release(inode, file);
771 : : }
772 : :
773 : : static const struct file_operations blk_mq_debugfs_fops = {
774 : : .open = blk_mq_debugfs_open,
775 : : .read = seq_read,
776 : : .write = blk_mq_debugfs_write,
777 : : .llseek = seq_lseek,
778 : : .release = blk_mq_debugfs_release,
779 : : };
780 : :
781 : : static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = {
782 : : {"state", 0400, hctx_state_show},
783 : : {"flags", 0400, hctx_flags_show},
784 : : {"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops},
785 : : {"busy", 0400, hctx_busy_show},
786 : : {"ctx_map", 0400, hctx_ctx_map_show},
787 : : {"tags", 0400, hctx_tags_show},
788 : : {"tags_bitmap", 0400, hctx_tags_bitmap_show},
789 : : {"sched_tags", 0400, hctx_sched_tags_show},
790 : : {"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show},
791 : : {"io_poll", 0600, hctx_io_poll_show, hctx_io_poll_write},
792 : : {"dispatched", 0600, hctx_dispatched_show, hctx_dispatched_write},
793 : : {"queued", 0600, hctx_queued_show, hctx_queued_write},
794 : : {"run", 0600, hctx_run_show, hctx_run_write},
795 : : {"active", 0400, hctx_active_show},
796 : : {"dispatch_busy", 0400, hctx_dispatch_busy_show},
797 : : {"type", 0400, hctx_type_show},
798 : : {},
799 : : };
800 : :
801 : : static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = {
802 : : {"default_rq_list", 0400, .seq_ops = &ctx_default_rq_list_seq_ops},
803 : : {"read_rq_list", 0400, .seq_ops = &ctx_read_rq_list_seq_ops},
804 : : {"poll_rq_list", 0400, .seq_ops = &ctx_poll_rq_list_seq_ops},
805 : : {"dispatched", 0600, ctx_dispatched_show, ctx_dispatched_write},
806 : : {"merged", 0600, ctx_merged_show, ctx_merged_write},
807 : : {"completed", 0600, ctx_completed_show, ctx_completed_write},
808 : : {},
809 : : };
810 : :
811 : 13041 : static void debugfs_create_files(struct dentry *parent, void *data,
812 : : const struct blk_mq_debugfs_attr *attr)
813 : : {
814 [ + - ]: 13041 : if (IS_ERR_OR_NULL(parent))
815 : 13041 : return;
816 : :
817 : 13041 : d_inode(parent)->i_private = data;
818 : :
819 [ + + ]: 111780 : for (; attr->name; attr++)
820 : 98739 : debugfs_create_file(attr->name, attr->mode, parent,
821 : : (void *)attr, &blk_mq_debugfs_fops);
822 : : }
823 : :
824 : 1863 : void blk_mq_debugfs_register(struct request_queue *q)
825 : : {
826 : : struct blk_mq_hw_ctx *hctx;
827 : : int i;
828 : :
829 : 3726 : q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent),
830 : : blk_debugfs_root);
831 : :
832 : 1863 : debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs);
833 : :
834 : : /*
835 : : * blk_mq_init_sched() attempted to do this already, but q->debugfs_dir
836 : : * didn't exist yet (because we don't know what to name the directory
837 : : * until the queue is registered to a gendisk).
838 : : */
839 [ + - + - ]: 1863 : if (q->elevator && !q->sched_debugfs_dir)
840 : 1863 : blk_mq_debugfs_register_sched(q);
841 : :
842 : : /* Similarly, blk_mq_init_hctx() couldn't do this previously. */
843 [ + + ]: 1863 : queue_for_each_hw_ctx(q, hctx, i) {
844 [ + - ]: 1863 : if (!hctx->debugfs_dir)
845 : 1863 : blk_mq_debugfs_register_hctx(q, hctx);
846 [ + - + - ]: 1863 : if (q->elevator && !hctx->sched_debugfs_dir)
847 : 1863 : blk_mq_debugfs_register_sched_hctx(q, hctx);
848 : : }
849 : :
850 [ - + ]: 1863 : if (q->rq_qos) {
851 : : struct rq_qos *rqos = q->rq_qos;
852 : :
853 [ # # ]: 0 : while (rqos) {
854 : 0 : blk_mq_debugfs_register_rqos(rqos);
855 : 0 : rqos = rqos->next;
856 : : }
857 : : }
858 : 1863 : }
859 : :
860 : 0 : void blk_mq_debugfs_unregister(struct request_queue *q)
861 : : {
862 : 0 : debugfs_remove_recursive(q->debugfs_dir);
863 : 0 : q->sched_debugfs_dir = NULL;
864 : 0 : q->debugfs_dir = NULL;
865 : 0 : }
866 : :
867 : 7452 : static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
868 : : struct blk_mq_ctx *ctx)
869 : : {
870 : : struct dentry *ctx_dir;
871 : : char name[20];
872 : :
873 : 7452 : snprintf(name, sizeof(name), "cpu%u", ctx->cpu);
874 : 7452 : ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir);
875 : :
876 : 7452 : debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs);
877 : 7452 : }
878 : :
879 : 1863 : void blk_mq_debugfs_register_hctx(struct request_queue *q,
880 : : struct blk_mq_hw_ctx *hctx)
881 : : {
882 : : struct blk_mq_ctx *ctx;
883 : : char name[20];
884 : : int i;
885 : :
886 : 1863 : snprintf(name, sizeof(name), "hctx%u", hctx->queue_num);
887 : 1863 : hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir);
888 : :
889 : 1863 : debugfs_create_files(hctx->debugfs_dir, hctx, blk_mq_debugfs_hctx_attrs);
890 : :
891 [ + + ]: 9315 : hctx_for_each_ctx(hctx, ctx, i)
892 : 7452 : blk_mq_debugfs_register_ctx(hctx, ctx);
893 : 1863 : }
894 : :
895 : 0 : void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx)
896 : : {
897 : 0 : debugfs_remove_recursive(hctx->debugfs_dir);
898 : 0 : hctx->sched_debugfs_dir = NULL;
899 : 0 : hctx->debugfs_dir = NULL;
900 : 0 : }
901 : :
902 : 0 : void blk_mq_debugfs_register_hctxs(struct request_queue *q)
903 : : {
904 : : struct blk_mq_hw_ctx *hctx;
905 : : int i;
906 : :
907 [ # # ]: 0 : queue_for_each_hw_ctx(q, hctx, i)
908 : 0 : blk_mq_debugfs_register_hctx(q, hctx);
909 : 0 : }
910 : :
911 : 0 : void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
912 : : {
913 : : struct blk_mq_hw_ctx *hctx;
914 : : int i;
915 : :
916 [ # # ]: 0 : queue_for_each_hw_ctx(q, hctx, i)
917 : : blk_mq_debugfs_unregister_hctx(hctx);
918 : 0 : }
919 : :
920 : 3726 : void blk_mq_debugfs_register_sched(struct request_queue *q)
921 : : {
922 : 3726 : struct elevator_type *e = q->elevator->type;
923 : :
924 : : /*
925 : : * If the parent directory has not been created yet, return, we will be
926 : : * called again later on and the directory/files will be created then.
927 : : */
928 [ + + ]: 3726 : if (!q->debugfs_dir)
929 : : return;
930 : :
931 [ + - ]: 1863 : if (!e->queue_debugfs_attrs)
932 : : return;
933 : :
934 : 1863 : q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir);
935 : :
936 : 1863 : debugfs_create_files(q->sched_debugfs_dir, q, e->queue_debugfs_attrs);
937 : : }
938 : :
939 : 0 : void blk_mq_debugfs_unregister_sched(struct request_queue *q)
940 : : {
941 : 0 : debugfs_remove_recursive(q->sched_debugfs_dir);
942 : 0 : q->sched_debugfs_dir = NULL;
943 : 0 : }
944 : :
945 : 0 : void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos)
946 : : {
947 : 0 : debugfs_remove_recursive(rqos->debugfs_dir);
948 : 0 : rqos->debugfs_dir = NULL;
949 : 0 : }
950 : :
951 : 0 : void blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
952 : : {
953 : 0 : struct request_queue *q = rqos->q;
954 [ # # ]: 0 : const char *dir_name = rq_qos_id_to_name(rqos->id);
955 : :
956 [ # # # # ]: 0 : if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs)
957 : 0 : return;
958 : :
959 [ # # ]: 0 : if (!q->rqos_debugfs_dir)
960 : 0 : q->rqos_debugfs_dir = debugfs_create_dir("rqos",
961 : : q->debugfs_dir);
962 : :
963 : 0 : rqos->debugfs_dir = debugfs_create_dir(dir_name,
964 : 0 : rqos->q->rqos_debugfs_dir);
965 : :
966 : 0 : debugfs_create_files(rqos->debugfs_dir, rqos, rqos->ops->debugfs_attrs);
967 : : }
968 : :
969 : 0 : void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q)
970 : : {
971 : 0 : debugfs_remove_recursive(q->rqos_debugfs_dir);
972 : 0 : q->rqos_debugfs_dir = NULL;
973 : 0 : }
974 : :
975 : 3726 : void blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
976 : : struct blk_mq_hw_ctx *hctx)
977 : : {
978 : 3726 : struct elevator_type *e = q->elevator->type;
979 : :
980 [ - + ]: 3726 : if (!e->hctx_debugfs_attrs)
981 : 3726 : return;
982 : :
983 : 0 : hctx->sched_debugfs_dir = debugfs_create_dir("sched",
984 : : hctx->debugfs_dir);
985 : 0 : debugfs_create_files(hctx->sched_debugfs_dir, hctx,
986 : : e->hctx_debugfs_attrs);
987 : : }
988 : :
989 : 0 : void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx)
990 : : {
991 : 0 : debugfs_remove_recursive(hctx->sched_debugfs_dir);
992 : 0 : hctx->sched_debugfs_dir = NULL;
993 : 0 : }
|