18c16567dSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
207e4feadSOmar Sandoval /*
307e4feadSOmar Sandoval * Copyright (C) 2017 Facebook
407e4feadSOmar Sandoval */
507e4feadSOmar Sandoval
607e4feadSOmar Sandoval #include <linux/kernel.h>
707e4feadSOmar Sandoval #include <linux/blkdev.h>
807e4feadSOmar Sandoval #include <linux/debugfs.h>
907e4feadSOmar Sandoval
1018fbda91SOmar Sandoval #include "blk.h"
1107e4feadSOmar Sandoval #include "blk-mq.h"
12d173a251SOmar Sandoval #include "blk-mq-debugfs.h"
132aa7745bSChristoph Hellwig #include "blk-mq-sched.h"
14cc56694fSMing Lei #include "blk-rq-qos.h"
1507e4feadSOmar Sandoval
queue_poll_stat_show(void * data,struct seq_file * m)161209cb7fSBart Van Assche static int queue_poll_stat_show(void *data, struct seq_file *m)
171209cb7fSBart Van Assche {
181209cb7fSBart Van Assche return 0;
191209cb7fSBart Van Assche }
201209cb7fSBart Van Assche
queue_requeue_list_start(struct seq_file * m,loff_t * pos)211209cb7fSBart Van Assche static void *queue_requeue_list_start(struct seq_file *m, loff_t *pos)
221209cb7fSBart Van Assche __acquires(&q->requeue_lock)
231209cb7fSBart Van Assche {
241209cb7fSBart Van Assche struct request_queue *q = m->private;
251209cb7fSBart Van Assche
261209cb7fSBart Van Assche spin_lock_irq(&q->requeue_lock);
271209cb7fSBart Van Assche return seq_list_start(&q->requeue_list, *pos);
281209cb7fSBart Van Assche }
291209cb7fSBart Van Assche
queue_requeue_list_next(struct seq_file * m,void * v,loff_t * pos)301209cb7fSBart Van Assche static void *queue_requeue_list_next(struct seq_file *m, void *v, loff_t *pos)
311209cb7fSBart Van Assche {
321209cb7fSBart Van Assche struct request_queue *q = m->private;
331209cb7fSBart Van Assche
341209cb7fSBart Van Assche return seq_list_next(v, &q->requeue_list, pos);
351209cb7fSBart Van Assche }
361209cb7fSBart Van Assche
queue_requeue_list_stop(struct seq_file * m,void * v)371209cb7fSBart Van Assche static void queue_requeue_list_stop(struct seq_file *m, void *v)
381209cb7fSBart Van Assche __releases(&q->requeue_lock)
391209cb7fSBart Van Assche {
401209cb7fSBart Van Assche struct request_queue *q = m->private;
411209cb7fSBart Van Assche
421209cb7fSBart Van Assche spin_unlock_irq(&q->requeue_lock);
431209cb7fSBart Van Assche }
441209cb7fSBart Van Assche
451209cb7fSBart Van Assche static const struct seq_operations queue_requeue_list_seq_ops = {
461209cb7fSBart Van Assche .start = queue_requeue_list_start,
471209cb7fSBart Van Assche .next = queue_requeue_list_next,
481209cb7fSBart Van Assche .stop = queue_requeue_list_stop,
491209cb7fSBart Van Assche .show = blk_mq_debugfs_rq_show,
501209cb7fSBart Van Assche };
511209cb7fSBart Van Assche
blk_flags_show(struct seq_file * m,const unsigned long flags,const char * const * flag_name,int flag_name_count)5291d68905SBart Van Assche static int blk_flags_show(struct seq_file *m, const unsigned long flags,
5391d68905SBart Van Assche const char *const *flag_name, int flag_name_count)
5491d68905SBart Van Assche {
5591d68905SBart Van Assche bool sep = false;
5691d68905SBart Van Assche int i;
5791d68905SBart Van Assche
5891d68905SBart Van Assche for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) {
5991d68905SBart Van Assche if (!(flags & BIT(i)))
6091d68905SBart Van Assche continue;
6191d68905SBart Van Assche if (sep)
62bec03d6bSOmar Sandoval seq_puts(m, "|");
6391d68905SBart Van Assche sep = true;
6491d68905SBart Van Assche if (i < flag_name_count && flag_name[i])
6591d68905SBart Van Assche seq_puts(m, flag_name[i]);
6691d68905SBart Van Assche else
6791d68905SBart Van Assche seq_printf(m, "%d", i);
6891d68905SBart Van Assche }
6991d68905SBart Van Assche return 0;
7091d68905SBart Van Assche }
7191d68905SBart Van Assche
queue_pm_only_show(void * data,struct seq_file * m)72cd84a62eSBart Van Assche static int queue_pm_only_show(void *data, struct seq_file *m)
73cd84a62eSBart Van Assche {
74cd84a62eSBart Van Assche struct request_queue *q = data;
75cd84a62eSBart Van Assche
76cd84a62eSBart Van Assche seq_printf(m, "%d\n", atomic_read(&q->pm_only));
77cd84a62eSBart Van Assche return 0;
78cd84a62eSBart Van Assche }
79cd84a62eSBart Van Assche
801a435111SOmar Sandoval #define QUEUE_FLAG_NAME(name) [QUEUE_FLAG_##name] = #name
8191d68905SBart Van Assche static const char *const blk_queue_flag_name[] = {
821a435111SOmar Sandoval QUEUE_FLAG_NAME(STOPPED),
831a435111SOmar Sandoval QUEUE_FLAG_NAME(DYING),
841a435111SOmar Sandoval QUEUE_FLAG_NAME(NOMERGES),
851a435111SOmar Sandoval QUEUE_FLAG_NAME(SAME_COMP),
861a435111SOmar Sandoval QUEUE_FLAG_NAME(FAIL_IO),
871a435111SOmar Sandoval QUEUE_FLAG_NAME(NONROT),
881a435111SOmar Sandoval QUEUE_FLAG_NAME(IO_STAT),
891a435111SOmar Sandoval QUEUE_FLAG_NAME(NOXMERGES),
901a435111SOmar Sandoval QUEUE_FLAG_NAME(ADD_RANDOM),
911a435111SOmar Sandoval QUEUE_FLAG_NAME(SYNCHRONOUS),
921a435111SOmar Sandoval QUEUE_FLAG_NAME(SAME_FORCE),
931cb039f3SChristoph Hellwig QUEUE_FLAG_NAME(INIT_DONE),
941a435111SOmar Sandoval QUEUE_FLAG_NAME(STABLE_WRITES),
951a435111SOmar Sandoval QUEUE_FLAG_NAME(POLL),
961a435111SOmar Sandoval QUEUE_FLAG_NAME(WC),
971a435111SOmar Sandoval QUEUE_FLAG_NAME(FUA),
981a435111SOmar Sandoval QUEUE_FLAG_NAME(DAX),
991a435111SOmar Sandoval QUEUE_FLAG_NAME(STATS),
10022d53821SBart Van Assche QUEUE_FLAG_NAME(REGISTERED),
101bfe373f6SHou Tao QUEUE_FLAG_NAME(QUIESCED),
102bfe373f6SHou Tao QUEUE_FLAG_NAME(PCI_P2PDMA),
103bfe373f6SHou Tao QUEUE_FLAG_NAME(ZONE_RESETALL),
1041dbdd99bSJohannes Thumshirn QUEUE_FLAG_NAME(RQ_ALLOC_TIME),
105dc304326SAndres Freund QUEUE_FLAG_NAME(HCTX_ACTIVE),
10691d68905SBart Van Assche QUEUE_FLAG_NAME(NOWAIT),
1071a435111SOmar Sandoval QUEUE_FLAG_NAME(SQ_SCHED),
10891d68905SBart Van Assche QUEUE_FLAG_NAME(SKIP_TAGSET_QUIESCE),
109f57de23aSOmar Sandoval };
11091d68905SBart Van Assche #undef QUEUE_FLAG_NAME
111f57de23aSOmar Sandoval
queue_state_show(void * data,struct seq_file * m)11291d68905SBart Van Assche static int queue_state_show(void *data, struct seq_file *m)
11391d68905SBart Van Assche {
11491d68905SBart Van Assche struct request_queue *q = data;
115fd07dc81SBart Van Assche
11691d68905SBart Van Assche blk_flags_show(m, q->queue_flags, blk_queue_flag_name,
11791d68905SBart Van Assche ARRAY_SIZE(blk_queue_flag_name));
11891d68905SBart Van Assche seq_puts(m, "\n");
119f57de23aSOmar Sandoval return 0;
120c7e4145aSOmar Sandoval }
12191d68905SBart Van Assche
queue_state_write(void * data,const char __user * buf,size_t count,loff_t * ppos)122f57de23aSOmar Sandoval static ssize_t queue_state_write(void *data, const char __user *buf,
12371b90511SOmar Sandoval size_t count, loff_t *ppos)
12491d68905SBart Van Assche {
12518d4d7d0SBart Van Assche struct request_queue *q = data;
1261f90307eSChristoph Hellwig char opbuf[16] = { }, *op;
1271f90307eSChristoph Hellwig
12818d4d7d0SBart Van Assche /*
1291f90307eSChristoph Hellwig * The "state" attribute is removed when the queue is removed. Don't
13018d4d7d0SBart Van Assche * allow setting the state on a dying queue to avoid a use-after-free.
13118d4d7d0SBart Van Assche */
13271b90511SOmar Sandoval if (blk_queue_dying(q))
133c7e4145aSOmar Sandoval return -ENOENT;
134c7e4145aSOmar Sandoval
135c7e4145aSOmar Sandoval if (count >= sizeof(opbuf)) {
136c7e4145aSOmar Sandoval pr_err("%s: operation too long\n", __func__);
13771b90511SOmar Sandoval goto inval;
13891d68905SBart Van Assche }
13971b90511SOmar Sandoval
14091d68905SBart Van Assche if (copy_from_user(opbuf, buf, count))
14191d68905SBart Van Assche return -EFAULT;
14291d68905SBart Van Assche op = strstrip(opbuf);
14391d68905SBart Van Assche if (strcmp(op, "run") == 0) {
144edea55abSBart Van Assche blk_mq_run_hw_queues(q, true);
145edea55abSBart Van Assche } else if (strcmp(op, "start") == 0) {
14691d68905SBart Van Assche blk_mq_start_stopped_hw_queues(q, true);
147c7e4145aSOmar Sandoval } else if (strcmp(op, "kick") == 0) {
148c7e4145aSOmar Sandoval blk_mq_kick_requeue_list(q);
149edea55abSBart Van Assche } else {
15091d68905SBart Van Assche pr_err("%s: unsupported operation '%s'\n", __func__, op);
15191d68905SBart Van Assche inval:
152c7e4145aSOmar Sandoval pr_err("%s: use 'run', 'start' or 'kick'\n", __func__);
15391d68905SBart Van Assche return -EINVAL;
15491d68905SBart Van Assche }
1551209cb7fSBart Van Assche return count;
1561209cb7fSBart Van Assche }
1571209cb7fSBart Van Assche
158cd84a62eSBart Van Assche static const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = {
1591209cb7fSBart Van Assche { "poll_stat", 0400, queue_poll_stat_show },
16018bc4230SBart Van Assche { "requeue_list", 0400, .seq_ops = &queue_requeue_list_seq_ops },
1611209cb7fSBart Van Assche { "pm_only", 0600, queue_pm_only_show, NULL },
1621209cb7fSBart Van Assche { "state", 0600, queue_state_show, queue_state_write },
16334dbad5dSOmar Sandoval { "zone_wlock", 0400, queue_zone_wlock_show, NULL },
1641a435111SOmar Sandoval { },
165f5c0b091SBart Van Assche };
1661a435111SOmar Sandoval
1671a435111SOmar Sandoval #define HCTX_STATE_NAME(name) [BLK_MQ_S_##name] = #name
1681a435111SOmar Sandoval static const char *const hctx_state_name[] = {
169bf0beec0SMing Lei HCTX_STATE_NAME(STOPPED),
170f5c0b091SBart Van Assche HCTX_STATE_NAME(TAG_ACTIVE),
1711a435111SOmar Sandoval HCTX_STATE_NAME(SCHED_RESTART),
1721a435111SOmar Sandoval HCTX_STATE_NAME(INACTIVE),
173f57de23aSOmar Sandoval };
1749abb2ad2SOmar Sandoval #undef HCTX_STATE_NAME
175f57de23aSOmar Sandoval
hctx_state_show(void * data,struct seq_file * m)1769abb2ad2SOmar Sandoval static int hctx_state_show(void *data, struct seq_file *m)
177f5c0b091SBart Van Assche {
178f5c0b091SBart Van Assche struct blk_mq_hw_ctx *hctx = data;
179fd07dc81SBart Van Assche
1809abb2ad2SOmar Sandoval blk_flags_show(m, hctx->state, hctx_state_name,
1819abb2ad2SOmar Sandoval ARRAY_SIZE(hctx_state_name));
1829abb2ad2SOmar Sandoval seq_puts(m, "\n");
1831a435111SOmar Sandoval return 0;
184f5c0b091SBart Van Assche }
1851a435111SOmar Sandoval
1861a435111SOmar Sandoval #define BLK_TAG_ALLOC_NAME(name) [BLK_TAG_ALLOC_##name] = #name
187f5c0b091SBart Van Assche static const char *const alloc_policy_name[] = {
1881a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(FIFO),
189f5c0b091SBart Van Assche BLK_TAG_ALLOC_NAME(RR),
1901a435111SOmar Sandoval };
191f5c0b091SBart Van Assche #undef BLK_TAG_ALLOC_NAME
1921a435111SOmar Sandoval
19351db1c37SMing Lei #define HCTX_FLAG_NAME(name) [ilog2(BLK_MQ_F_##name)] = #name
1941a435111SOmar Sandoval static const char *const hctx_flag_name[] = {
1951a435111SOmar Sandoval HCTX_FLAG_NAME(SHOULD_MERGE),
196bf0beec0SMing Lei HCTX_FLAG_NAME(TAG_QUEUE_SHARED),
19702f938e9SJohn Garry HCTX_FLAG_NAME(BLOCKING),
198f5c0b091SBart Van Assche HCTX_FLAG_NAME(NO_SCHED),
1991a435111SOmar Sandoval HCTX_FLAG_NAME(STACKING),
200f5c0b091SBart Van Assche HCTX_FLAG_NAME(TAG_HCTX_SHARED),
201f57de23aSOmar Sandoval };
2029abb2ad2SOmar Sandoval #undef HCTX_FLAG_NAME
203f57de23aSOmar Sandoval
hctx_flags_show(void * data,struct seq_file * m)204f5c0b091SBart Van Assche static int hctx_flags_show(void *data, struct seq_file *m)
2059abb2ad2SOmar Sandoval {
206f5c0b091SBart Van Assche struct blk_mq_hw_ctx *hctx = data;
207f5c0b091SBart Van Assche const int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(hctx->flags);
208f5c0b091SBart Van Assche
209f5c0b091SBart Van Assche seq_puts(m, "alloc_policy=");
210f5c0b091SBart Van Assche if (alloc_policy < ARRAY_SIZE(alloc_policy_name) &&
211f5c0b091SBart Van Assche alloc_policy_name[alloc_policy])
212f5c0b091SBart Van Assche seq_puts(m, alloc_policy_name[alloc_policy]);
213f5c0b091SBart Van Assche else
214f5c0b091SBart Van Assche seq_printf(m, "%d", alloc_policy);
215f5c0b091SBart Van Assche seq_puts(m, " ");
216fd07dc81SBart Van Assche blk_flags_show(m,
2179abb2ad2SOmar Sandoval hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy),
2189abb2ad2SOmar Sandoval hctx_flag_name, ARRAY_SIZE(hctx_flag_name));
2199abb2ad2SOmar Sandoval seq_puts(m, "\n");
2201a435111SOmar Sandoval return 0;
2218658dca8SBart Van Assche }
2221a435111SOmar Sandoval
2231a435111SOmar Sandoval #define CMD_FLAG_NAME(name) [__REQ_##name] = #name
2241a435111SOmar Sandoval static const char *const cmd_flag_name[] = {
2251a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DEV),
2261a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_TRANSPORT),
2271a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DRIVER),
2281a435111SOmar Sandoval CMD_FLAG_NAME(SYNC),
2291a435111SOmar Sandoval CMD_FLAG_NAME(META),
2301a435111SOmar Sandoval CMD_FLAG_NAME(PRIO),
2311a435111SOmar Sandoval CMD_FLAG_NAME(NOMERGE),
2321a435111SOmar Sandoval CMD_FLAG_NAME(IDLE),
2331a435111SOmar Sandoval CMD_FLAG_NAME(INTEGRITY),
2341a435111SOmar Sandoval CMD_FLAG_NAME(FUA),
23522d53821SBart Van Assche CMD_FLAG_NAME(PREFLUSH),
2361c26010cSJianchao Wang CMD_FLAG_NAME(RAHEAD),
2376ce913feSChristoph Hellwig CMD_FLAG_NAME(BACKGROUND),
2388658dca8SBart Van Assche CMD_FLAG_NAME(NOWAIT),
2391a435111SOmar Sandoval CMD_FLAG_NAME(NOUNMAP),
2408658dca8SBart Van Assche CMD_FLAG_NAME(POLLED),
2411a435111SOmar Sandoval };
2428658dca8SBart Van Assche #undef CMD_FLAG_NAME
24385ba3effSJens Axboe
2441a435111SOmar Sandoval #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name
2451a435111SOmar Sandoval static const char *const rqf_name[] = {
2461a435111SOmar Sandoval RQF_NAME(STARTED),
2471a435111SOmar Sandoval RQF_NAME(FLUSH_SEQ),
2481a435111SOmar Sandoval RQF_NAME(MIXED_MERGE),
2491a435111SOmar Sandoval RQF_NAME(MQ_INFLIGHT),
2501a435111SOmar Sandoval RQF_NAME(DONTPREP),
2511a435111SOmar Sandoval RQF_NAME(SCHED_TAGS),
2521a435111SOmar Sandoval RQF_NAME(USE_SCHED),
2531a435111SOmar Sandoval RQF_NAME(FAILED),
2541a435111SOmar Sandoval RQF_NAME(QUIET),
2551a435111SOmar Sandoval RQF_NAME(IO_STAT),
2561a435111SOmar Sandoval RQF_NAME(PM),
2575d75d3f2SJens Axboe RQF_NAME(HASHED),
258745ed372SJens Axboe RQF_NAME(STATS),
25962ba0c00SMing Lei RQF_NAME(SPECIAL_PAYLOAD),
260745ed372SJens Axboe RQF_NAME(ZONE_WRITE_LOCKED),
2618658dca8SBart Van Assche RQF_NAME(TIMED_OUT),
2621a435111SOmar Sandoval RQF_NAME(RESV),
2638658dca8SBart Van Assche };
264ec6dcf63SBart Van Assche #undef RQF_NAME
265ec6dcf63SBart Van Assche
266ec6dcf63SBart Van Assche static const char *const blk_mq_rq_state_name_array[] = {
267ec6dcf63SBart Van Assche [MQ_RQ_IDLE] = "idle",
268ec6dcf63SBart Van Assche [MQ_RQ_IN_FLIGHT] = "in_flight",
269ec6dcf63SBart Van Assche [MQ_RQ_COMPLETE] = "complete",
270ec6dcf63SBart Van Assche };
271ec6dcf63SBart Van Assche
blk_mq_rq_state_name(enum mq_rq_state rq_state)272a1e79188SDan Carpenter static const char *blk_mq_rq_state_name(enum mq_rq_state rq_state)
273ec6dcf63SBart Van Assche {
274ec6dcf63SBart Van Assche if (WARN_ON_ONCE((unsigned int)rq_state >=
275ec6dcf63SBart Van Assche ARRAY_SIZE(blk_mq_rq_state_name_array)))
276ec6dcf63SBart Van Assche return "(?)";
277ec6dcf63SBart Van Assche return blk_mq_rq_state_name_array[rq_state];
278daaadb3eSOmar Sandoval }
279950cd7e9SOmar Sandoval
__blk_mq_debugfs_rq_show(struct seq_file * m,struct request * rq)2802836ee4bSBart Van Assche int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq)
28177e7ffd7SBart Van Assche {
282874c893bSChaitanya Kulkarni const struct blk_mq_ops *const mq_ops = rq->q->mq_ops;
283950cd7e9SOmar Sandoval const enum req_op op = req_op(rq);
2848658dca8SBart Van Assche const char *op_str = blk_op_str(op);
285874c893bSChaitanya Kulkarni
2863f6d385fSChaitanya Kulkarni seq_printf(m, "%p {.op=", rq);
2878658dca8SBart Van Assche if (strcmp(op_str, "UNKNOWN") == 0)
288874c893bSChaitanya Kulkarni seq_printf(m, "%u", op);
2898658dca8SBart Van Assche else
29016458cf3SBart Van Assche seq_printf(m, "%s", op_str);
29116458cf3SBart Van Assche seq_puts(m, ", .cmd_flags=");
2928658dca8SBart Van Assche blk_flags_show(m, (__force unsigned int)(rq->cmd_flags & ~REQ_OP_MASK),
2938658dca8SBart Van Assche cmd_flag_name, ARRAY_SIZE(cmd_flag_name));
2948658dca8SBart Van Assche seq_puts(m, ", .rq_flags=");
295ec6dcf63SBart Van Assche blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name,
2962836ee4bSBart Van Assche ARRAY_SIZE(rqf_name));
2978658dca8SBart Van Assche seq_printf(m, ", .state=%s", blk_mq_rq_state_name(blk_mq_rq_state(rq)));
2982836ee4bSBart Van Assche seq_printf(m, ", .tag=%d, .internal_tag=%d", rq->tag,
2992836ee4bSBart Van Assche rq->internal_tag);
3002836ee4bSBart Van Assche if (mq_ops->show_rq)
301950cd7e9SOmar Sandoval mq_ops->show_rq(m, rq);
302950cd7e9SOmar Sandoval seq_puts(m, "}\n");
303daaadb3eSOmar Sandoval return 0;
304daaadb3eSOmar Sandoval }
305daaadb3eSOmar Sandoval EXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show);
306daaadb3eSOmar Sandoval
blk_mq_debugfs_rq_show(struct seq_file * m,void * v)307daaadb3eSOmar Sandoval int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
308daaadb3eSOmar Sandoval {
30916b738f6SOmar Sandoval return __blk_mq_debugfs_rq_show(m, list_entry_rq(v));
310950cd7e9SOmar Sandoval }
311950cd7e9SOmar Sandoval EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show);
312f3bcb0e6SBart Van Assche
hctx_dispatch_start(struct seq_file * m,loff_t * pos)313950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos)
314950cd7e9SOmar Sandoval __acquires(&hctx->lock)
315950cd7e9SOmar Sandoval {
316950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private;
317950cd7e9SOmar Sandoval
318950cd7e9SOmar Sandoval spin_lock(&hctx->lock);
319950cd7e9SOmar Sandoval return seq_list_start(&hctx->dispatch, *pos);
320950cd7e9SOmar Sandoval }
321950cd7e9SOmar Sandoval
hctx_dispatch_next(struct seq_file * m,void * v,loff_t * pos)322950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos)
323950cd7e9SOmar Sandoval {
324950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private;
325950cd7e9SOmar Sandoval
326950cd7e9SOmar Sandoval return seq_list_next(v, &hctx->dispatch, pos);
327950cd7e9SOmar Sandoval }
328f3bcb0e6SBart Van Assche
hctx_dispatch_stop(struct seq_file * m,void * v)329950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v)
330950cd7e9SOmar Sandoval __releases(&hctx->lock)
331950cd7e9SOmar Sandoval {
332950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private;
333950cd7e9SOmar Sandoval
334950cd7e9SOmar Sandoval spin_unlock(&hctx->lock);
335950cd7e9SOmar Sandoval }
336950cd7e9SOmar Sandoval
337950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = {
338950cd7e9SOmar Sandoval .start = hctx_dispatch_start,
339950cd7e9SOmar Sandoval .next = hctx_dispatch_next,
340950cd7e9SOmar Sandoval .stop = hctx_dispatch_stop,
341950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show,
3422720bab5SBart Van Assche };
3432720bab5SBart Van Assche
3442720bab5SBart Van Assche struct show_busy_params {
3452720bab5SBart Van Assche struct seq_file *m;
3462720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx;
3472720bab5SBart Van Assche };
3482720bab5SBart Van Assche
3497baa8572SJens Axboe /*
3507baa8572SJens Axboe * Note: the state of a request may change while this function is in progress,
3512720bab5SBart Van Assche * e.g. due to a concurrent blk_mq_finish_request() call. Returns true to
3522dd6532eSJohn Garry * keep iterating requests.
3532720bab5SBart Van Assche */
hctx_show_busy_rq(struct request * rq,void * data)3542720bab5SBart Van Assche static bool hctx_show_busy_rq(struct request *rq, void *data)
3552720bab5SBart Van Assche {
356ea4f995eSJens Axboe const struct show_busy_params *params = data;
357b5fc1e8bSHou Tao
3587baa8572SJens Axboe if (rq->mq_hctx == params->hctx)
3597baa8572SJens Axboe __blk_mq_debugfs_rq_show(params->m, rq);
3602720bab5SBart Van Assche
3612720bab5SBart Van Assche return true;
3622720bab5SBart Van Assche }
3632720bab5SBart Van Assche
hctx_busy_show(void * data,struct seq_file * m)3642720bab5SBart Van Assche static int hctx_busy_show(void *data, struct seq_file *m)
3652720bab5SBart Van Assche {
3662720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx = data;
3672720bab5SBart Van Assche struct show_busy_params params = { .m = m, .hctx = hctx };
3682720bab5SBart Van Assche
3692720bab5SBart Van Assche blk_mq_tagset_busy_iter(hctx->queue->tag_set, hctx_show_busy_rq,
3702720bab5SBart Van Assche ¶ms);
3712720bab5SBart Van Assche
3722720bab5SBart Van Assche return 0;
373346fc108SMing Lei }
374346fc108SMing Lei
375346fc108SMing Lei static const char *const hctx_types[] = {
376346fc108SMing Lei [HCTX_TYPE_DEFAULT] = "default",
377346fc108SMing Lei [HCTX_TYPE_READ] = "read",
378346fc108SMing Lei [HCTX_TYPE_POLL] = "poll",
379346fc108SMing Lei };
380346fc108SMing Lei
hctx_type_show(void * data,struct seq_file * m)381346fc108SMing Lei static int hctx_type_show(void *data, struct seq_file *m)
382346fc108SMing Lei {
383346fc108SMing Lei struct blk_mq_hw_ctx *hctx = data;
384346fc108SMing Lei
385346fc108SMing Lei BUILD_BUG_ON(ARRAY_SIZE(hctx_types) != HCTX_MAX_TYPES);
386346fc108SMing Lei seq_printf(m, "%s\n", hctx_types[hctx->type]);
387346fc108SMing Lei return 0;
388f57de23aSOmar Sandoval }
389950cd7e9SOmar Sandoval
hctx_ctx_map_show(void * data,struct seq_file * m)390f57de23aSOmar Sandoval static int hctx_ctx_map_show(void *data, struct seq_file *m)
3910bfa5288SOmar Sandoval {
3920bfa5288SOmar Sandoval struct blk_mq_hw_ctx *hctx = data;
3930bfa5288SOmar Sandoval
3940bfa5288SOmar Sandoval sbitmap_bitmap_show(&hctx->ctx_map, m);
3950bfa5288SOmar Sandoval return 0;
396d96b37c0SOmar Sandoval }
397d96b37c0SOmar Sandoval
blk_mq_debugfs_tags_show(struct seq_file * m,struct blk_mq_tags * tags)398d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m,
399d96b37c0SOmar Sandoval struct blk_mq_tags *tags)
400d96b37c0SOmar Sandoval {
401d96b37c0SOmar Sandoval seq_printf(m, "nr_tags=%u\n", tags->nr_tags);
402d96b37c0SOmar Sandoval seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags);
403d96b37c0SOmar Sandoval seq_printf(m, "active_queues=%d\n",
404d96b37c0SOmar Sandoval READ_ONCE(tags->active_queues));
405ae0f1a73SJohn Garry
406d96b37c0SOmar Sandoval seq_puts(m, "\nbitmap_tags:\n");
407d96b37c0SOmar Sandoval sbitmap_queue_show(&tags->bitmap_tags, m);
408d96b37c0SOmar Sandoval
409ae0f1a73SJohn Garry if (tags->nr_reserved_tags) {
410d96b37c0SOmar Sandoval seq_puts(m, "\nbreserved_tags:\n");
411d96b37c0SOmar Sandoval sbitmap_queue_show(&tags->breserved_tags, m);
412d96b37c0SOmar Sandoval }
413f57de23aSOmar Sandoval }
414d96b37c0SOmar Sandoval
hctx_tags_show(void * data,struct seq_file * m)415f57de23aSOmar Sandoval static int hctx_tags_show(void *data, struct seq_file *m)
416d96b37c0SOmar Sandoval {
4178c0f14eaSBart Van Assche struct blk_mq_hw_ctx *hctx = data;
418d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue;
4198c0f14eaSBart Van Assche int res;
4208c0f14eaSBart Van Assche
4218c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock);
422d96b37c0SOmar Sandoval if (res)
423d96b37c0SOmar Sandoval goto out;
424d96b37c0SOmar Sandoval if (hctx->tags)
425d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->tags);
4268c0f14eaSBart Van Assche mutex_unlock(&q->sysfs_lock);
4278c0f14eaSBart Van Assche
428d96b37c0SOmar Sandoval out:
429d96b37c0SOmar Sandoval return res;
430f57de23aSOmar Sandoval }
431d96b37c0SOmar Sandoval
hctx_tags_bitmap_show(void * data,struct seq_file * m)432f57de23aSOmar Sandoval static int hctx_tags_bitmap_show(void *data, struct seq_file *m)
433d7e3621aSOmar Sandoval {
4348c0f14eaSBart Van Assche struct blk_mq_hw_ctx *hctx = data;
435d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue;
4368c0f14eaSBart Van Assche int res;
4378c0f14eaSBart Van Assche
4388c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock);
439d7e3621aSOmar Sandoval if (res)
440ae0f1a73SJohn Garry goto out;
441d7e3621aSOmar Sandoval if (hctx->tags)
4428c0f14eaSBart Van Assche sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m);
4438c0f14eaSBart Van Assche mutex_unlock(&q->sysfs_lock);
4448c0f14eaSBart Van Assche
445d7e3621aSOmar Sandoval out:
446d7e3621aSOmar Sandoval return res;
447f57de23aSOmar Sandoval }
448d7e3621aSOmar Sandoval
hctx_sched_tags_show(void * data,struct seq_file * m)449f57de23aSOmar Sandoval static int hctx_sched_tags_show(void *data, struct seq_file *m)
450d96b37c0SOmar Sandoval {
4518c0f14eaSBart Van Assche struct blk_mq_hw_ctx *hctx = data;
452d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue;
4538c0f14eaSBart Van Assche int res;
4548c0f14eaSBart Van Assche
4558c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock);
456d96b37c0SOmar Sandoval if (res)
457d96b37c0SOmar Sandoval goto out;
458d96b37c0SOmar Sandoval if (hctx->sched_tags)
459d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->sched_tags);
4608c0f14eaSBart Van Assche mutex_unlock(&q->sysfs_lock);
4618c0f14eaSBart Van Assche
462d96b37c0SOmar Sandoval out:
463d96b37c0SOmar Sandoval return res;
464f57de23aSOmar Sandoval }
465d96b37c0SOmar Sandoval
hctx_sched_tags_bitmap_show(void * data,struct seq_file * m)466f57de23aSOmar Sandoval static int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m)
467d7e3621aSOmar Sandoval {
4688c0f14eaSBart Van Assche struct blk_mq_hw_ctx *hctx = data;
469d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue;
4708c0f14eaSBart Van Assche int res;
4718c0f14eaSBart Van Assche
4728c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock);
473d7e3621aSOmar Sandoval if (res)
474ae0f1a73SJohn Garry goto out;
475d7e3621aSOmar Sandoval if (hctx->sched_tags)
4768c0f14eaSBart Van Assche sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m);
4778c0f14eaSBart Van Assche mutex_unlock(&q->sysfs_lock);
4788c0f14eaSBart Van Assche
479d7e3621aSOmar Sandoval out:
480d7e3621aSOmar Sandoval return res;
481f57de23aSOmar Sandoval }
4824a46f05eSOmar Sandoval
hctx_run_show(void * data,struct seq_file * m)483f57de23aSOmar Sandoval static int hctx_run_show(void *data, struct seq_file *m)
4844a46f05eSOmar Sandoval {
4854a46f05eSOmar Sandoval struct blk_mq_hw_ctx *hctx = data;
4864a46f05eSOmar Sandoval
4874a46f05eSOmar Sandoval seq_printf(m, "%lu\n", hctx->run);
4884a46f05eSOmar Sandoval return 0;
489f57de23aSOmar Sandoval }
490f57de23aSOmar Sandoval
hctx_run_write(void * data,const char __user * buf,size_t count,loff_t * ppos)4914a46f05eSOmar Sandoval static ssize_t hctx_run_write(void *data, const char __user *buf, size_t count,
492f57de23aSOmar Sandoval loff_t *ppos)
4934a46f05eSOmar Sandoval {
4944a46f05eSOmar Sandoval struct blk_mq_hw_ctx *hctx = data;
4954a46f05eSOmar Sandoval
4964a46f05eSOmar Sandoval hctx->run = 0;
4974a46f05eSOmar Sandoval return count;
498f57de23aSOmar Sandoval }
4994a46f05eSOmar Sandoval
hctx_active_show(void * data,struct seq_file * m)500f57de23aSOmar Sandoval static int hctx_active_show(void *data, struct seq_file *m)
5014a46f05eSOmar Sandoval {
5029b84c629SJohn Garry struct blk_mq_hw_ctx *hctx = data;
5034a46f05eSOmar Sandoval
5044a46f05eSOmar Sandoval seq_printf(m, "%d\n", __blk_mq_active_requests(hctx));
5054a46f05eSOmar Sandoval return 0;
5066e768717SMing Lei }
5076e768717SMing Lei
hctx_dispatch_busy_show(void * data,struct seq_file * m)5086e768717SMing Lei static int hctx_dispatch_busy_show(void *data, struct seq_file *m)
5096e768717SMing Lei {
5106e768717SMing Lei struct blk_mq_hw_ctx *hctx = data;
5116e768717SMing Lei
5126e768717SMing Lei seq_printf(m, "%u\n", hctx->dispatch_busy);
5136e768717SMing Lei return 0;
514c16d6b5aSMing Lei }
515c16d6b5aSMing Lei
516c16d6b5aSMing Lei #define CTX_RQ_SEQ_OPS(name, type) \
517c16d6b5aSMing Lei static void *ctx_##name##_rq_list_start(struct seq_file *m, loff_t *pos) \
518c16d6b5aSMing Lei __acquires(&ctx->lock) \
519c16d6b5aSMing Lei { \
520c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \
521c16d6b5aSMing Lei \
522c16d6b5aSMing Lei spin_lock(&ctx->lock); \
523c16d6b5aSMing Lei return seq_list_start(&ctx->rq_lists[type], *pos); \
524c16d6b5aSMing Lei } \
525c16d6b5aSMing Lei \
526c16d6b5aSMing Lei static void *ctx_##name##_rq_list_next(struct seq_file *m, void *v, \
527c16d6b5aSMing Lei loff_t *pos) \
528c16d6b5aSMing Lei { \
529c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \
530c16d6b5aSMing Lei \
531c16d6b5aSMing Lei return seq_list_next(v, &ctx->rq_lists[type], pos); \
532c16d6b5aSMing Lei } \
533c16d6b5aSMing Lei \
534c16d6b5aSMing Lei static void ctx_##name##_rq_list_stop(struct seq_file *m, void *v) \
535c16d6b5aSMing Lei __releases(&ctx->lock) \
536c16d6b5aSMing Lei { \
537c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \
538c16d6b5aSMing Lei \
539c16d6b5aSMing Lei spin_unlock(&ctx->lock); \
540c16d6b5aSMing Lei } \
541c16d6b5aSMing Lei \
542c16d6b5aSMing Lei static const struct seq_operations ctx_##name##_rq_list_seq_ops = { \
543c16d6b5aSMing Lei .start = ctx_##name##_rq_list_start, \
544c16d6b5aSMing Lei .next = ctx_##name##_rq_list_next, \
545950cd7e9SOmar Sandoval .stop = ctx_##name##_rq_list_stop, \
546950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, \
547c16d6b5aSMing Lei }
548c16d6b5aSMing Lei
549c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(default, HCTX_TYPE_DEFAULT);
550950cd7e9SOmar Sandoval CTX_RQ_SEQ_OPS(read, HCTX_TYPE_READ);
551f57de23aSOmar Sandoval CTX_RQ_SEQ_OPS(poll, HCTX_TYPE_POLL);
552f57de23aSOmar Sandoval
blk_mq_debugfs_show(struct seq_file * m,void * v)553f57de23aSOmar Sandoval static int blk_mq_debugfs_show(struct seq_file *m, void *v)
554f57de23aSOmar Sandoval {
555f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private;
556f57de23aSOmar Sandoval void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private;
557f57de23aSOmar Sandoval
558f57de23aSOmar Sandoval return attr->show(data, m);
559f57de23aSOmar Sandoval }
560f57de23aSOmar Sandoval
blk_mq_debugfs_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)561f57de23aSOmar Sandoval static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf,
562f57de23aSOmar Sandoval size_t count, loff_t *ppos)
563f57de23aSOmar Sandoval {
564f57de23aSOmar Sandoval struct seq_file *m = file->private_data;
565f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private;
5666b136a24SEryu Guan void *data = d_inode(file->f_path.dentry->d_parent)->i_private;
5676b136a24SEryu Guan
5686b136a24SEryu Guan /*
5696b136a24SEryu Guan * Attributes that only implement .seq_ops are read-only and 'attr' is
5706b136a24SEryu Guan * the same with 'data' in this case.
571f57de23aSOmar Sandoval */
572f57de23aSOmar Sandoval if (attr == data || !attr->write)
573f57de23aSOmar Sandoval return -EPERM;
574f57de23aSOmar Sandoval
575f57de23aSOmar Sandoval return attr->write(data, buf, count, ppos);
576f57de23aSOmar Sandoval }
577f57de23aSOmar Sandoval
blk_mq_debugfs_open(struct inode * inode,struct file * file)578f57de23aSOmar Sandoval static int blk_mq_debugfs_open(struct inode *inode, struct file *file)
579f57de23aSOmar Sandoval {
580f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private;
581f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private;
582f57de23aSOmar Sandoval struct seq_file *m;
583f57de23aSOmar Sandoval int ret;
584f57de23aSOmar Sandoval
585f57de23aSOmar Sandoval if (attr->seq_ops) {
586f57de23aSOmar Sandoval ret = seq_open(file, attr->seq_ops);
587f57de23aSOmar Sandoval if (!ret) {
588f57de23aSOmar Sandoval m = file->private_data;
589f57de23aSOmar Sandoval m->private = data;
590f57de23aSOmar Sandoval }
591f57de23aSOmar Sandoval return ret;
592f57de23aSOmar Sandoval }
593f57de23aSOmar Sandoval
594f57de23aSOmar Sandoval if (WARN_ON_ONCE(!attr->show))
595f57de23aSOmar Sandoval return -EPERM;
596f57de23aSOmar Sandoval
597f57de23aSOmar Sandoval return single_open(file, blk_mq_debugfs_show, inode->i_private);
598f57de23aSOmar Sandoval }
599f57de23aSOmar Sandoval
blk_mq_debugfs_release(struct inode * inode,struct file * file)600f57de23aSOmar Sandoval static int blk_mq_debugfs_release(struct inode *inode, struct file *file)
601f57de23aSOmar Sandoval {
602f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private;
603f57de23aSOmar Sandoval
604ee1e0359SChaitanya Kulkarni if (attr->show)
605f57de23aSOmar Sandoval return single_release(inode, file);
606f57de23aSOmar Sandoval
607f57de23aSOmar Sandoval return seq_release(inode, file);
608f8465933SBart Van Assche }
609f57de23aSOmar Sandoval
6104a46f05eSOmar Sandoval static const struct file_operations blk_mq_debugfs_fops = {
611f57de23aSOmar Sandoval .open = blk_mq_debugfs_open,
6124a46f05eSOmar Sandoval .read = seq_read,
613f57de23aSOmar Sandoval .write = blk_mq_debugfs_write,
6144a46f05eSOmar Sandoval .llseek = seq_lseek,
6154a46f05eSOmar Sandoval .release = blk_mq_debugfs_release,
61607e4feadSOmar Sandoval };
617f57de23aSOmar Sandoval
618f57de23aSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = {
619f57de23aSOmar Sandoval {"state", 0400, hctx_state_show},
6202720bab5SBart Van Assche {"flags", 0400, hctx_flags_show},
621f57de23aSOmar Sandoval {"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops},
622f57de23aSOmar Sandoval {"busy", 0400, hctx_busy_show},
623f57de23aSOmar Sandoval {"ctx_map", 0400, hctx_ctx_map_show},
624f57de23aSOmar Sandoval {"tags", 0400, hctx_tags_show},
625f57de23aSOmar Sandoval {"tags_bitmap", 0400, hctx_tags_bitmap_show},
626f57de23aSOmar Sandoval {"sched_tags", 0400, hctx_sched_tags_show},
627f57de23aSOmar Sandoval {"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show},
6286e768717SMing Lei {"run", 0600, hctx_run_show, hctx_run_write},
629346fc108SMing Lei {"active", 0400, hctx_active_show},
63072f2f8f6SBart Van Assche {"dispatch_busy", 0400, hctx_dispatch_busy_show},
63107e4feadSOmar Sandoval {"type", 0400, hctx_type_show},
63207e4feadSOmar Sandoval {},
63307e4feadSOmar Sandoval };
634c16d6b5aSMing Lei
635c16d6b5aSMing Lei static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = {
636c16d6b5aSMing Lei {"default_rq_list", 0400, .seq_ops = &ctx_default_rq_list_seq_ops},
63772f2f8f6SBart Van Assche {"read_rq_list", 0400, .seq_ops = &ctx_read_rq_list_seq_ops},
63807e4feadSOmar Sandoval {"poll_rq_list", 0400, .seq_ops = &ctx_poll_rq_list_seq_ops},
63907e4feadSOmar Sandoval {},
6406cfc0081SGreg Kroah-Hartman };
64172f2f8f6SBart Van Assche
debugfs_create_files(struct dentry * parent,void * data,const struct blk_mq_debugfs_attr * attr)64272f2f8f6SBart Van Assche static void debugfs_create_files(struct dentry *parent, void *data,
64336991ca6SGreg Kroah-Hartman const struct blk_mq_debugfs_attr *attr)
6446cfc0081SGreg Kroah-Hartman {
64536991ca6SGreg Kroah-Hartman if (IS_ERR_OR_NULL(parent))
646f57de23aSOmar Sandoval return;
647f57de23aSOmar Sandoval
6486cfc0081SGreg Kroah-Hartman d_inode(parent)->i_private = data;
6496cfc0081SGreg Kroah-Hartman
6506cfc0081SGreg Kroah-Hartman for (; attr->name; attr++)
65172f2f8f6SBart Van Assche debugfs_create_file(attr->name, attr->mode, parent,
65272f2f8f6SBart Van Assche (void *)attr, &blk_mq_debugfs_fops);
6536cfc0081SGreg Kroah-Hartman }
6549c1051aaSOmar Sandoval
blk_mq_debugfs_register(struct request_queue * q)6559c1051aaSOmar Sandoval void blk_mq_debugfs_register(struct request_queue *q)
6564f481208SMing Lei {
6579c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx;
6586cfc0081SGreg Kroah-Hartman unsigned long i;
6599c1051aaSOmar Sandoval
6609c1051aaSOmar Sandoval debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs);
66170e62f4bSOmar Sandoval
6629c1051aaSOmar Sandoval /*
6639c1051aaSOmar Sandoval * blk_mq_init_sched() attempted to do this already, but q->debugfs_dir
6649c1051aaSOmar Sandoval * didn't exist yet (because we don't know what to name the directory
66570e62f4bSOmar Sandoval * until the queue is registered to a gendisk).
66670e62f4bSOmar Sandoval */
66770e62f4bSOmar Sandoval if (q->elevator && !q->sched_debugfs_dir)
66870e62f4bSOmar Sandoval blk_mq_debugfs_register_sched(q);
6699c1051aaSOmar Sandoval
6706cfc0081SGreg Kroah-Hartman /* Similarly, blk_mq_init_hctx() couldn't do this previously. */
6716cfc0081SGreg Kroah-Hartman queue_for_each_hw_ctx(q, hctx, i) {
6726cfc0081SGreg Kroah-Hartman if (!hctx->debugfs_dir)
6736cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_hctx(q, hctx);
6749c1051aaSOmar Sandoval if (q->elevator && !hctx->sched_debugfs_dir)
6759c1051aaSOmar Sandoval blk_mq_debugfs_register_sched_hctx(q, hctx);
676cc56694fSMing Lei }
677cc56694fSMing Lei
678cc56694fSMing Lei if (q->rq_qos) {
679cc56694fSMing Lei struct rq_qos *rqos = q->rq_qos;
680cc56694fSMing Lei
681cc56694fSMing Lei while (rqos) {
682cc56694fSMing Lei blk_mq_debugfs_register_rqos(rqos);
683cc56694fSMing Lei rqos = rqos->next;
6849c1051aaSOmar Sandoval }
6859c1051aaSOmar Sandoval }
6866cfc0081SGreg Kroah-Hartman }
6879c1051aaSOmar Sandoval
blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx * hctx,struct blk_mq_ctx * ctx)68807e4feadSOmar Sandoval static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
68907e4feadSOmar Sandoval struct blk_mq_ctx *ctx)
69007e4feadSOmar Sandoval {
69107e4feadSOmar Sandoval struct dentry *ctx_dir;
69207e4feadSOmar Sandoval char name[20];
6939c1051aaSOmar Sandoval
69407e4feadSOmar Sandoval snprintf(name, sizeof(name), "cpu%u", ctx->cpu);
6956cfc0081SGreg Kroah-Hartman ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir);
69607e4feadSOmar Sandoval
69707e4feadSOmar Sandoval debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs);
6986cfc0081SGreg Kroah-Hartman }
69907e4feadSOmar Sandoval
blk_mq_debugfs_register_hctx(struct request_queue * q,struct blk_mq_hw_ctx * hctx)70007e4feadSOmar Sandoval void blk_mq_debugfs_register_hctx(struct request_queue *q,
70107e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx)
70207e4feadSOmar Sandoval {
70307e4feadSOmar Sandoval struct blk_mq_ctx *ctx;
70407e4feadSOmar Sandoval char name[20];
705f3ec5d11SMing Lei int i;
706f3ec5d11SMing Lei
707f3ec5d11SMing Lei if (!q->debugfs_dir)
7089c1051aaSOmar Sandoval return;
7099c1051aaSOmar Sandoval
7109c1051aaSOmar Sandoval snprintf(name, sizeof(name), "hctx%u", hctx->queue_num);
7116cfc0081SGreg Kroah-Hartman hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir);
71207e4feadSOmar Sandoval
7136cfc0081SGreg Kroah-Hartman debugfs_create_files(hctx->debugfs_dir, hctx, blk_mq_debugfs_hctx_attrs);
7146cfc0081SGreg Kroah-Hartman
71507e4feadSOmar Sandoval hctx_for_each_ctx(hctx, ctx, i)
71607e4feadSOmar Sandoval blk_mq_debugfs_register_ctx(hctx, ctx);
7179c1051aaSOmar Sandoval }
71807e4feadSOmar Sandoval
blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx * hctx)7195cf9c91bSChristoph Hellwig void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx)
7205cf9c91bSChristoph Hellwig {
7219c1051aaSOmar Sandoval if (!hctx->queue->debugfs_dir)
722d332ce09SOmar Sandoval return;
7239c1051aaSOmar Sandoval debugfs_remove_recursive(hctx->debugfs_dir);
7249c1051aaSOmar Sandoval hctx->sched_debugfs_dir = NULL;
7259c1051aaSOmar Sandoval hctx->debugfs_dir = NULL;
7266cfc0081SGreg Kroah-Hartman }
7279c1051aaSOmar Sandoval
blk_mq_debugfs_register_hctxs(struct request_queue * q)7289c1051aaSOmar Sandoval void blk_mq_debugfs_register_hctxs(struct request_queue *q)
7294f481208SMing Lei {
7309c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx;
7316cfc0081SGreg Kroah-Hartman unsigned long i;
7326cfc0081SGreg Kroah-Hartman
7339c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i)
7349c1051aaSOmar Sandoval blk_mq_debugfs_register_hctx(q, hctx);
7359c1051aaSOmar Sandoval }
7369c1051aaSOmar Sandoval
blk_mq_debugfs_unregister_hctxs(struct request_queue * q)7379c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
7384f481208SMing Lei {
7399c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx;
7409c1051aaSOmar Sandoval unsigned long i;
7419c1051aaSOmar Sandoval
74207e4feadSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i)
743d332ce09SOmar Sandoval blk_mq_debugfs_unregister_hctx(hctx);
7446cfc0081SGreg Kroah-Hartman }
745d332ce09SOmar Sandoval
blk_mq_debugfs_register_sched(struct request_queue * q)746d332ce09SOmar Sandoval void blk_mq_debugfs_register_sched(struct request_queue *q)
747d332ce09SOmar Sandoval {
7485cf9c91bSChristoph Hellwig struct elevator_type *e = q->elevator->type;
7495cf9c91bSChristoph Hellwig
7507e41c3c9SGreg Kroah-Hartman lockdep_assert_held(&q->debugfs_mutex);
7517e41c3c9SGreg Kroah-Hartman
7527e41c3c9SGreg Kroah-Hartman /*
7537e41c3c9SGreg Kroah-Hartman * If the parent directory has not been created yet, return, we will be
7547e41c3c9SGreg Kroah-Hartman * called again later on and the directory/files will be created then.
7557e41c3c9SGreg Kroah-Hartman */
7567e41c3c9SGreg Kroah-Hartman if (!q->debugfs_dir)
757d332ce09SOmar Sandoval return;
7586cfc0081SGreg Kroah-Hartman
759d332ce09SOmar Sandoval if (!e->queue_debugfs_attrs)
760d332ce09SOmar Sandoval return;
761d332ce09SOmar Sandoval
7626cfc0081SGreg Kroah-Hartman q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir);
763d332ce09SOmar Sandoval
764d332ce09SOmar Sandoval debugfs_create_files(q->sched_debugfs_dir, q, e->queue_debugfs_attrs);
765d332ce09SOmar Sandoval }
766d332ce09SOmar Sandoval
blk_mq_debugfs_unregister_sched(struct request_queue * q)7675cf9c91bSChristoph Hellwig void blk_mq_debugfs_unregister_sched(struct request_queue *q)
7685cf9c91bSChristoph Hellwig {
769d332ce09SOmar Sandoval lockdep_assert_held(&q->debugfs_mutex);
770d332ce09SOmar Sandoval
771d332ce09SOmar Sandoval debugfs_remove_recursive(q->sched_debugfs_dir);
772d332ce09SOmar Sandoval q->sched_debugfs_dir = NULL;
773fb44023eSBart Van Assche }
774fb44023eSBart Van Assche
rq_qos_id_to_name(enum rq_qos_id id)775fb44023eSBart Van Assche static const char *rq_qos_id_to_name(enum rq_qos_id id)
776fb44023eSBart Van Assche {
777fb44023eSBart Van Assche switch (id) {
778fb44023eSBart Van Assche case RQ_QOS_WBT:
779fb44023eSBart Van Assche return "wbt";
780fb44023eSBart Van Assche case RQ_QOS_LATENCY:
781fb44023eSBart Van Assche return "latency";
782fb44023eSBart Van Assche case RQ_QOS_COST:
783fb44023eSBart Van Assche return "cost";
784fb44023eSBart Van Assche }
785fb44023eSBart Van Assche return "unknown";
786cc56694fSMing Lei }
787cc56694fSMing Lei
blk_mq_debugfs_unregister_rqos(struct rq_qos * rqos)788*ba91c849SChristoph Hellwig void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos)
7895cf9c91bSChristoph Hellwig {
790*ba91c849SChristoph Hellwig lockdep_assert_held(&rqos->disk->queue->debugfs_mutex);
7915cf9c91bSChristoph Hellwig
792cc56694fSMing Lei if (!rqos->disk->queue->debugfs_dir)
793cc56694fSMing Lei return;
794cc56694fSMing Lei debugfs_remove_recursive(rqos->debugfs_dir);
795cc56694fSMing Lei rqos->debugfs_dir = NULL;
7966cfc0081SGreg Kroah-Hartman }
797cc56694fSMing Lei
blk_mq_debugfs_register_rqos(struct rq_qos * rqos)798*ba91c849SChristoph Hellwig void blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
799cc56694fSMing Lei {
800cc56694fSMing Lei struct request_queue *q = rqos->disk->queue;
8015cf9c91bSChristoph Hellwig const char *dir_name = rq_qos_id_to_name(rqos->id);
8025cf9c91bSChristoph Hellwig
803cc56694fSMing Lei lockdep_assert_held(&q->debugfs_mutex);
8046cfc0081SGreg Kroah-Hartman
805cc56694fSMing Lei if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs)
8066cfc0081SGreg Kroah-Hartman return;
807cc56694fSMing Lei
808cc56694fSMing Lei if (!q->rqos_debugfs_dir)
809cc56694fSMing Lei q->rqos_debugfs_dir = debugfs_create_dir("rqos",
810*ba91c849SChristoph Hellwig q->debugfs_dir);
8116cfc0081SGreg Kroah-Hartman
812cc56694fSMing Lei rqos->debugfs_dir = debugfs_create_dir(dir_name, q->rqos_debugfs_dir);
813cc56694fSMing Lei debugfs_create_files(rqos->debugfs_dir, rqos, rqos->ops->debugfs_attrs);
8146cfc0081SGreg Kroah-Hartman }
815d332ce09SOmar Sandoval
blk_mq_debugfs_register_sched_hctx(struct request_queue * q,struct blk_mq_hw_ctx * hctx)816d332ce09SOmar Sandoval void blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
817d332ce09SOmar Sandoval struct blk_mq_hw_ctx *hctx)
818d332ce09SOmar Sandoval {
8195cf9c91bSChristoph Hellwig struct elevator_type *e = q->elevator->type;
8205cf9c91bSChristoph Hellwig
8211e91e28eSSaravanan D lockdep_assert_held(&q->debugfs_mutex);
8221e91e28eSSaravanan D
8231e91e28eSSaravanan D /*
8241e91e28eSSaravanan D * If the parent debugfs directory has not been created yet, return;
8251e91e28eSSaravanan D * We will be called again later on with appropriate parent debugfs
8261e91e28eSSaravanan D * directory from blk_register_queue()
8271e91e28eSSaravanan D */
8281e91e28eSSaravanan D if (!hctx->debugfs_dir)
829d332ce09SOmar Sandoval return;
8306cfc0081SGreg Kroah-Hartman
831d332ce09SOmar Sandoval if (!e->hctx_debugfs_attrs)
832d332ce09SOmar Sandoval return;
833d332ce09SOmar Sandoval
8346cfc0081SGreg Kroah-Hartman hctx->sched_debugfs_dir = debugfs_create_dir("sched",
8356cfc0081SGreg Kroah-Hartman hctx->debugfs_dir);
836d332ce09SOmar Sandoval debugfs_create_files(hctx->sched_debugfs_dir, hctx,
837d332ce09SOmar Sandoval e->hctx_debugfs_attrs);
838d332ce09SOmar Sandoval }
839d332ce09SOmar Sandoval
blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx * hctx)8405cf9c91bSChristoph Hellwig void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx)
8415cf9c91bSChristoph Hellwig {
8425cf9c91bSChristoph Hellwig lockdep_assert_held(&hctx->queue->debugfs_mutex);
8435cf9c91bSChristoph Hellwig
844d332ce09SOmar Sandoval if (!hctx->queue->debugfs_dir)
845d332ce09SOmar Sandoval return;
846d332ce09SOmar Sandoval debugfs_remove_recursive(hctx->sched_debugfs_dir);
847 hctx->sched_debugfs_dir = NULL;
848 }
849