xref: /linux/block/blk-mq-debugfs.c (revision c0cb1c6d39060ce04470b10347b7b6f1df77bef5)
107e4feadSOmar Sandoval /*
207e4feadSOmar Sandoval  * Copyright (C) 2017 Facebook
307e4feadSOmar Sandoval  *
407e4feadSOmar Sandoval  * This program is free software; you can redistribute it and/or
507e4feadSOmar Sandoval  * modify it under the terms of the GNU General Public
607e4feadSOmar Sandoval  * License v2 as published by the Free Software Foundation.
707e4feadSOmar Sandoval  *
807e4feadSOmar Sandoval  * This program is distributed in the hope that it will be useful,
907e4feadSOmar Sandoval  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1007e4feadSOmar Sandoval  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1107e4feadSOmar Sandoval  * General Public License for more details.
1207e4feadSOmar Sandoval  *
1307e4feadSOmar Sandoval  * You should have received a copy of the GNU General Public License
1407e4feadSOmar Sandoval  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
1507e4feadSOmar Sandoval  */
1607e4feadSOmar Sandoval 
1707e4feadSOmar Sandoval #include <linux/kernel.h>
1807e4feadSOmar Sandoval #include <linux/blkdev.h>
1907e4feadSOmar Sandoval #include <linux/debugfs.h>
2007e4feadSOmar Sandoval 
2107e4feadSOmar Sandoval #include <linux/blk-mq.h>
2218fbda91SOmar Sandoval #include "blk.h"
2307e4feadSOmar Sandoval #include "blk-mq.h"
24d173a251SOmar Sandoval #include "blk-mq-debugfs.h"
25d96b37c0SOmar Sandoval #include "blk-mq-tag.h"
2607e4feadSOmar Sandoval 
2791d68905SBart Van Assche static int blk_flags_show(struct seq_file *m, const unsigned long flags,
2891d68905SBart Van Assche 			  const char *const *flag_name, int flag_name_count)
2991d68905SBart Van Assche {
3091d68905SBart Van Assche 	bool sep = false;
3191d68905SBart Van Assche 	int i;
3291d68905SBart Van Assche 
3391d68905SBart Van Assche 	for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) {
3491d68905SBart Van Assche 		if (!(flags & BIT(i)))
3591d68905SBart Van Assche 			continue;
3691d68905SBart Van Assche 		if (sep)
37bec03d6bSOmar Sandoval 			seq_puts(m, "|");
3891d68905SBart Van Assche 		sep = true;
3991d68905SBart Van Assche 		if (i < flag_name_count && flag_name[i])
4091d68905SBart Van Assche 			seq_puts(m, flag_name[i]);
4191d68905SBart Van Assche 		else
4291d68905SBart Van Assche 			seq_printf(m, "%d", i);
4391d68905SBart Van Assche 	}
4491d68905SBart Van Assche 	return 0;
4591d68905SBart Van Assche }
4691d68905SBart Van Assche 
471a435111SOmar Sandoval #define QUEUE_FLAG_NAME(name) [QUEUE_FLAG_##name] = #name
4891d68905SBart Van Assche static const char *const blk_queue_flag_name[] = {
491a435111SOmar Sandoval 	QUEUE_FLAG_NAME(QUEUED),
501a435111SOmar Sandoval 	QUEUE_FLAG_NAME(STOPPED),
511a435111SOmar Sandoval 	QUEUE_FLAG_NAME(SYNCFULL),
521a435111SOmar Sandoval 	QUEUE_FLAG_NAME(ASYNCFULL),
531a435111SOmar Sandoval 	QUEUE_FLAG_NAME(DYING),
541a435111SOmar Sandoval 	QUEUE_FLAG_NAME(BYPASS),
551a435111SOmar Sandoval 	QUEUE_FLAG_NAME(BIDI),
561a435111SOmar Sandoval 	QUEUE_FLAG_NAME(NOMERGES),
571a435111SOmar Sandoval 	QUEUE_FLAG_NAME(SAME_COMP),
581a435111SOmar Sandoval 	QUEUE_FLAG_NAME(FAIL_IO),
591a435111SOmar Sandoval 	QUEUE_FLAG_NAME(STACKABLE),
601a435111SOmar Sandoval 	QUEUE_FLAG_NAME(NONROT),
611a435111SOmar Sandoval 	QUEUE_FLAG_NAME(IO_STAT),
621a435111SOmar Sandoval 	QUEUE_FLAG_NAME(DISCARD),
631a435111SOmar Sandoval 	QUEUE_FLAG_NAME(NOXMERGES),
641a435111SOmar Sandoval 	QUEUE_FLAG_NAME(ADD_RANDOM),
651a435111SOmar Sandoval 	QUEUE_FLAG_NAME(SECERASE),
661a435111SOmar Sandoval 	QUEUE_FLAG_NAME(SAME_FORCE),
671a435111SOmar Sandoval 	QUEUE_FLAG_NAME(DEAD),
681a435111SOmar Sandoval 	QUEUE_FLAG_NAME(INIT_DONE),
691a435111SOmar Sandoval 	QUEUE_FLAG_NAME(NO_SG_MERGE),
701a435111SOmar Sandoval 	QUEUE_FLAG_NAME(POLL),
711a435111SOmar Sandoval 	QUEUE_FLAG_NAME(WC),
721a435111SOmar Sandoval 	QUEUE_FLAG_NAME(FUA),
731a435111SOmar Sandoval 	QUEUE_FLAG_NAME(FLUSH_NQ),
741a435111SOmar Sandoval 	QUEUE_FLAG_NAME(DAX),
751a435111SOmar Sandoval 	QUEUE_FLAG_NAME(STATS),
761a435111SOmar Sandoval 	QUEUE_FLAG_NAME(POLL_STATS),
771a435111SOmar Sandoval 	QUEUE_FLAG_NAME(REGISTERED),
7891d68905SBart Van Assche };
791a435111SOmar Sandoval #undef QUEUE_FLAG_NAME
8091d68905SBart Van Assche 
81f57de23aSOmar Sandoval static int queue_state_show(void *data, struct seq_file *m)
8291d68905SBart Van Assche {
83f57de23aSOmar Sandoval 	struct request_queue *q = data;
8491d68905SBart Van Assche 
8591d68905SBart Van Assche 	blk_flags_show(m, q->queue_flags, blk_queue_flag_name,
8691d68905SBart Van Assche 		       ARRAY_SIZE(blk_queue_flag_name));
87fd07dc81SBart Van Assche 	seq_puts(m, "\n");
8891d68905SBart Van Assche 	return 0;
8991d68905SBart Van Assche }
9091d68905SBart Van Assche 
91f57de23aSOmar Sandoval static ssize_t queue_state_write(void *data, const char __user *buf,
92c7e4145aSOmar Sandoval 				 size_t count, loff_t *ppos)
9391d68905SBart Van Assche {
94f57de23aSOmar Sandoval 	struct request_queue *q = data;
9571b90511SOmar Sandoval 	char opbuf[16] = { }, *op;
9691d68905SBart Van Assche 
9718d4d7d0SBart Van Assche 	/*
9818d4d7d0SBart Van Assche 	 * The "state" attribute is removed after blk_cleanup_queue() has called
9918d4d7d0SBart Van Assche 	 * blk_mq_free_queue(). Return if QUEUE_FLAG_DEAD has been set to avoid
10018d4d7d0SBart Van Assche 	 * triggering a use-after-free.
10118d4d7d0SBart Van Assche 	 */
10218d4d7d0SBart Van Assche 	if (blk_queue_dead(q))
10318d4d7d0SBart Van Assche 		return -ENOENT;
10418d4d7d0SBart Van Assche 
10571b90511SOmar Sandoval 	if (count >= sizeof(opbuf)) {
106c7e4145aSOmar Sandoval 		pr_err("%s: operation too long\n", __func__);
107c7e4145aSOmar Sandoval 		goto inval;
108c7e4145aSOmar Sandoval 	}
109c7e4145aSOmar Sandoval 
11071b90511SOmar Sandoval 	if (copy_from_user(opbuf, buf, count))
11191d68905SBart Van Assche 		return -EFAULT;
11271b90511SOmar Sandoval 	op = strstrip(opbuf);
11391d68905SBart Van Assche 	if (strcmp(op, "run") == 0) {
11491d68905SBart Van Assche 		blk_mq_run_hw_queues(q, true);
11591d68905SBart Van Assche 	} else if (strcmp(op, "start") == 0) {
11691d68905SBart Van Assche 		blk_mq_start_stopped_hw_queues(q, true);
11791d68905SBart Van Assche 	} else {
118c7e4145aSOmar Sandoval 		pr_err("%s: unsupported operation '%s'\n", __func__, op);
119c7e4145aSOmar Sandoval inval:
120c7e4145aSOmar Sandoval 		pr_err("%s: use either 'run' or 'start'\n", __func__);
12191d68905SBart Van Assche 		return -EINVAL;
12291d68905SBart Van Assche 	}
123c7e4145aSOmar Sandoval 	return count;
12491d68905SBart Van Assche }
12591d68905SBart Van Assche 
12634dbad5dSOmar Sandoval static void print_stat(struct seq_file *m, struct blk_rq_stat *stat)
12734dbad5dSOmar Sandoval {
12834dbad5dSOmar Sandoval 	if (stat->nr_samples) {
12934dbad5dSOmar Sandoval 		seq_printf(m, "samples=%d, mean=%lld, min=%llu, max=%llu",
13034dbad5dSOmar Sandoval 			   stat->nr_samples, stat->mean, stat->min, stat->max);
13134dbad5dSOmar Sandoval 	} else {
13234dbad5dSOmar Sandoval 		seq_puts(m, "samples=0");
13334dbad5dSOmar Sandoval 	}
13434dbad5dSOmar Sandoval }
13534dbad5dSOmar Sandoval 
136f57de23aSOmar Sandoval static int queue_poll_stat_show(void *data, struct seq_file *m)
13734dbad5dSOmar Sandoval {
138f57de23aSOmar Sandoval 	struct request_queue *q = data;
1390206319fSStephen Bates 	int bucket;
14034dbad5dSOmar Sandoval 
1410206319fSStephen Bates 	for (bucket = 0; bucket < BLK_MQ_POLL_STATS_BKTS/2; bucket++) {
1420206319fSStephen Bates 		seq_printf(m, "read  (%d Bytes): ", 1 << (9+bucket));
1430206319fSStephen Bates 		print_stat(m, &q->poll_stat[2*bucket]);
14434dbad5dSOmar Sandoval 		seq_puts(m, "\n");
14534dbad5dSOmar Sandoval 
1460206319fSStephen Bates 		seq_printf(m, "write (%d Bytes): ",  1 << (9+bucket));
1470206319fSStephen Bates 		print_stat(m, &q->poll_stat[2*bucket+1]);
14834dbad5dSOmar Sandoval 		seq_puts(m, "\n");
1490206319fSStephen Bates 	}
15034dbad5dSOmar Sandoval 	return 0;
15134dbad5dSOmar Sandoval }
15234dbad5dSOmar Sandoval 
1531a435111SOmar Sandoval #define HCTX_STATE_NAME(name) [BLK_MQ_S_##name] = #name
154f5c0b091SBart Van Assche static const char *const hctx_state_name[] = {
1551a435111SOmar Sandoval 	HCTX_STATE_NAME(STOPPED),
1561a435111SOmar Sandoval 	HCTX_STATE_NAME(TAG_ACTIVE),
1571a435111SOmar Sandoval 	HCTX_STATE_NAME(SCHED_RESTART),
1581a435111SOmar Sandoval 	HCTX_STATE_NAME(TAG_WAITING),
1591a435111SOmar Sandoval 	HCTX_STATE_NAME(START_ON_RUN),
160f5c0b091SBart Van Assche };
1611a435111SOmar Sandoval #undef HCTX_STATE_NAME
1621a435111SOmar Sandoval 
163f57de23aSOmar Sandoval static int hctx_state_show(void *data, struct seq_file *m)
1649abb2ad2SOmar Sandoval {
165f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
1669abb2ad2SOmar Sandoval 
167f5c0b091SBart Van Assche 	blk_flags_show(m, hctx->state, hctx_state_name,
168f5c0b091SBart Van Assche 		       ARRAY_SIZE(hctx_state_name));
169fd07dc81SBart Van Assche 	seq_puts(m, "\n");
1709abb2ad2SOmar Sandoval 	return 0;
1719abb2ad2SOmar Sandoval }
1729abb2ad2SOmar Sandoval 
1731a435111SOmar Sandoval #define BLK_TAG_ALLOC_NAME(name) [BLK_TAG_ALLOC_##name] = #name
174f5c0b091SBart Van Assche static const char *const alloc_policy_name[] = {
1751a435111SOmar Sandoval 	BLK_TAG_ALLOC_NAME(FIFO),
1761a435111SOmar Sandoval 	BLK_TAG_ALLOC_NAME(RR),
177f5c0b091SBart Van Assche };
1781a435111SOmar Sandoval #undef BLK_TAG_ALLOC_NAME
179f5c0b091SBart Van Assche 
1801a435111SOmar Sandoval #define HCTX_FLAG_NAME(name) [ilog2(BLK_MQ_F_##name)] = #name
181f5c0b091SBart Van Assche static const char *const hctx_flag_name[] = {
1821a435111SOmar Sandoval 	HCTX_FLAG_NAME(SHOULD_MERGE),
1831a435111SOmar Sandoval 	HCTX_FLAG_NAME(TAG_SHARED),
1841a435111SOmar Sandoval 	HCTX_FLAG_NAME(SG_MERGE),
1851a435111SOmar Sandoval 	HCTX_FLAG_NAME(BLOCKING),
1861a435111SOmar Sandoval 	HCTX_FLAG_NAME(NO_SCHED),
187f5c0b091SBart Van Assche };
1881a435111SOmar Sandoval #undef HCTX_FLAG_NAME
189f5c0b091SBart Van Assche 
190f57de23aSOmar Sandoval static int hctx_flags_show(void *data, struct seq_file *m)
1919abb2ad2SOmar Sandoval {
192f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
193f5c0b091SBart Van Assche 	const int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(hctx->flags);
1949abb2ad2SOmar Sandoval 
195f5c0b091SBart Van Assche 	seq_puts(m, "alloc_policy=");
196f5c0b091SBart Van Assche 	if (alloc_policy < ARRAY_SIZE(alloc_policy_name) &&
197f5c0b091SBart Van Assche 	    alloc_policy_name[alloc_policy])
198f5c0b091SBart Van Assche 		seq_puts(m, alloc_policy_name[alloc_policy]);
199f5c0b091SBart Van Assche 	else
200f5c0b091SBart Van Assche 		seq_printf(m, "%d", alloc_policy);
201f5c0b091SBart Van Assche 	seq_puts(m, " ");
202f5c0b091SBart Van Assche 	blk_flags_show(m,
203f5c0b091SBart Van Assche 		       hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy),
204f5c0b091SBart Van Assche 		       hctx_flag_name, ARRAY_SIZE(hctx_flag_name));
205fd07dc81SBart Van Assche 	seq_puts(m, "\n");
2069abb2ad2SOmar Sandoval 	return 0;
2079abb2ad2SOmar Sandoval }
2089abb2ad2SOmar Sandoval 
2091a435111SOmar Sandoval #define REQ_OP_NAME(name) [REQ_OP_##name] = #name
2108658dca8SBart Van Assche static const char *const op_name[] = {
2111a435111SOmar Sandoval 	REQ_OP_NAME(READ),
2121a435111SOmar Sandoval 	REQ_OP_NAME(WRITE),
2131a435111SOmar Sandoval 	REQ_OP_NAME(FLUSH),
2141a435111SOmar Sandoval 	REQ_OP_NAME(DISCARD),
2151a435111SOmar Sandoval 	REQ_OP_NAME(ZONE_REPORT),
2161a435111SOmar Sandoval 	REQ_OP_NAME(SECURE_ERASE),
2171a435111SOmar Sandoval 	REQ_OP_NAME(ZONE_RESET),
2181a435111SOmar Sandoval 	REQ_OP_NAME(WRITE_SAME),
2191a435111SOmar Sandoval 	REQ_OP_NAME(WRITE_ZEROES),
2201a435111SOmar Sandoval 	REQ_OP_NAME(SCSI_IN),
2211a435111SOmar Sandoval 	REQ_OP_NAME(SCSI_OUT),
2221a435111SOmar Sandoval 	REQ_OP_NAME(DRV_IN),
2231a435111SOmar Sandoval 	REQ_OP_NAME(DRV_OUT),
2248658dca8SBart Van Assche };
2251a435111SOmar Sandoval #undef REQ_OP_NAME
2268658dca8SBart Van Assche 
2271a435111SOmar Sandoval #define CMD_FLAG_NAME(name) [__REQ_##name] = #name
2288658dca8SBart Van Assche static const char *const cmd_flag_name[] = {
2291a435111SOmar Sandoval 	CMD_FLAG_NAME(FAILFAST_DEV),
2301a435111SOmar Sandoval 	CMD_FLAG_NAME(FAILFAST_TRANSPORT),
2311a435111SOmar Sandoval 	CMD_FLAG_NAME(FAILFAST_DRIVER),
2321a435111SOmar Sandoval 	CMD_FLAG_NAME(SYNC),
2331a435111SOmar Sandoval 	CMD_FLAG_NAME(META),
2341a435111SOmar Sandoval 	CMD_FLAG_NAME(PRIO),
2351a435111SOmar Sandoval 	CMD_FLAG_NAME(NOMERGE),
2361a435111SOmar Sandoval 	CMD_FLAG_NAME(IDLE),
2371a435111SOmar Sandoval 	CMD_FLAG_NAME(INTEGRITY),
2381a435111SOmar Sandoval 	CMD_FLAG_NAME(FUA),
2391a435111SOmar Sandoval 	CMD_FLAG_NAME(PREFLUSH),
2401a435111SOmar Sandoval 	CMD_FLAG_NAME(RAHEAD),
2411a435111SOmar Sandoval 	CMD_FLAG_NAME(BACKGROUND),
2421a435111SOmar Sandoval 	CMD_FLAG_NAME(NOUNMAP),
2438658dca8SBart Van Assche };
2441a435111SOmar Sandoval #undef CMD_FLAG_NAME
2458658dca8SBart Van Assche 
2461a435111SOmar Sandoval #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name
2478658dca8SBart Van Assche static const char *const rqf_name[] = {
2481a435111SOmar Sandoval 	RQF_NAME(SORTED),
2491a435111SOmar Sandoval 	RQF_NAME(STARTED),
2501a435111SOmar Sandoval 	RQF_NAME(QUEUED),
2511a435111SOmar Sandoval 	RQF_NAME(SOFTBARRIER),
2521a435111SOmar Sandoval 	RQF_NAME(FLUSH_SEQ),
2531a435111SOmar Sandoval 	RQF_NAME(MIXED_MERGE),
2541a435111SOmar Sandoval 	RQF_NAME(MQ_INFLIGHT),
2551a435111SOmar Sandoval 	RQF_NAME(DONTPREP),
2561a435111SOmar Sandoval 	RQF_NAME(PREEMPT),
2571a435111SOmar Sandoval 	RQF_NAME(COPY_USER),
2581a435111SOmar Sandoval 	RQF_NAME(FAILED),
2591a435111SOmar Sandoval 	RQF_NAME(QUIET),
2601a435111SOmar Sandoval 	RQF_NAME(ELVPRIV),
2611a435111SOmar Sandoval 	RQF_NAME(IO_STAT),
2621a435111SOmar Sandoval 	RQF_NAME(ALLOCED),
2631a435111SOmar Sandoval 	RQF_NAME(PM),
2641a435111SOmar Sandoval 	RQF_NAME(HASHED),
2651a435111SOmar Sandoval 	RQF_NAME(STATS),
2661a435111SOmar Sandoval 	RQF_NAME(SPECIAL_PAYLOAD),
2678658dca8SBart Van Assche };
2681a435111SOmar Sandoval #undef RQF_NAME
2698658dca8SBart Van Assche 
270*c0cb1c6dSBart Van Assche #define RQAF_NAME(name) [REQ_ATOM_##name] = #name
271*c0cb1c6dSBart Van Assche static const char *const rqaf_name[] = {
272*c0cb1c6dSBart Van Assche 	RQAF_NAME(COMPLETE),
273*c0cb1c6dSBart Van Assche 	RQAF_NAME(STARTED),
274*c0cb1c6dSBart Van Assche 	RQAF_NAME(POLL_SLEPT),
275*c0cb1c6dSBart Van Assche };
276*c0cb1c6dSBart Van Assche #undef RQAF_NAME
277*c0cb1c6dSBart Van Assche 
278daaadb3eSOmar Sandoval int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq)
279950cd7e9SOmar Sandoval {
2802836ee4bSBart Van Assche 	const struct blk_mq_ops *const mq_ops = rq->q->mq_ops;
2818658dca8SBart Van Assche 	const unsigned int op = rq->cmd_flags & REQ_OP_MASK;
282950cd7e9SOmar Sandoval 
2838658dca8SBart Van Assche 	seq_printf(m, "%p {.op=", rq);
2848658dca8SBart Van Assche 	if (op < ARRAY_SIZE(op_name) && op_name[op])
2858658dca8SBart Van Assche 		seq_printf(m, "%s", op_name[op]);
2868658dca8SBart Van Assche 	else
2878658dca8SBart Van Assche 		seq_printf(m, "%d", op);
2888658dca8SBart Van Assche 	seq_puts(m, ", .cmd_flags=");
2898658dca8SBart Van Assche 	blk_flags_show(m, rq->cmd_flags & ~REQ_OP_MASK, cmd_flag_name,
2908658dca8SBart Van Assche 		       ARRAY_SIZE(cmd_flag_name));
2918658dca8SBart Van Assche 	seq_puts(m, ", .rq_flags=");
2928658dca8SBart Van Assche 	blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name,
2938658dca8SBart Van Assche 		       ARRAY_SIZE(rqf_name));
294*c0cb1c6dSBart Van Assche 	seq_puts(m, ", .atomic_flags=");
295*c0cb1c6dSBart Van Assche 	blk_flags_show(m, rq->atomic_flags, rqaf_name, ARRAY_SIZE(rqaf_name));
2962836ee4bSBart Van Assche 	seq_printf(m, ", .tag=%d, .internal_tag=%d", rq->tag,
2978658dca8SBart Van Assche 		   rq->internal_tag);
2982836ee4bSBart Van Assche 	if (mq_ops->show_rq)
2992836ee4bSBart Van Assche 		mq_ops->show_rq(m, rq);
3002836ee4bSBart Van Assche 	seq_puts(m, "}\n");
301950cd7e9SOmar Sandoval 	return 0;
302950cd7e9SOmar Sandoval }
303daaadb3eSOmar Sandoval EXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show);
304daaadb3eSOmar Sandoval 
305daaadb3eSOmar Sandoval int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
306daaadb3eSOmar Sandoval {
307daaadb3eSOmar Sandoval 	return __blk_mq_debugfs_rq_show(m, list_entry_rq(v));
308daaadb3eSOmar Sandoval }
30916b738f6SOmar Sandoval EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show);
310950cd7e9SOmar Sandoval 
311950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos)
312f3bcb0e6SBart Van Assche 	__acquires(&hctx->lock)
313950cd7e9SOmar Sandoval {
314950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
315950cd7e9SOmar Sandoval 
316950cd7e9SOmar Sandoval 	spin_lock(&hctx->lock);
317950cd7e9SOmar Sandoval 	return seq_list_start(&hctx->dispatch, *pos);
318950cd7e9SOmar Sandoval }
319950cd7e9SOmar Sandoval 
320950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos)
321950cd7e9SOmar Sandoval {
322950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
323950cd7e9SOmar Sandoval 
324950cd7e9SOmar Sandoval 	return seq_list_next(v, &hctx->dispatch, pos);
325950cd7e9SOmar Sandoval }
326950cd7e9SOmar Sandoval 
327950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v)
328f3bcb0e6SBart Van Assche 	__releases(&hctx->lock)
329950cd7e9SOmar Sandoval {
330950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
331950cd7e9SOmar Sandoval 
332950cd7e9SOmar Sandoval 	spin_unlock(&hctx->lock);
333950cd7e9SOmar Sandoval }
334950cd7e9SOmar Sandoval 
335950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = {
336950cd7e9SOmar Sandoval 	.start	= hctx_dispatch_start,
337950cd7e9SOmar Sandoval 	.next	= hctx_dispatch_next,
338950cd7e9SOmar Sandoval 	.stop	= hctx_dispatch_stop,
339950cd7e9SOmar Sandoval 	.show	= blk_mq_debugfs_rq_show,
340950cd7e9SOmar Sandoval };
341950cd7e9SOmar Sandoval 
342f57de23aSOmar Sandoval static int hctx_ctx_map_show(void *data, struct seq_file *m)
343950cd7e9SOmar Sandoval {
344f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
3450bfa5288SOmar Sandoval 
3460bfa5288SOmar Sandoval 	sbitmap_bitmap_show(&hctx->ctx_map, m);
3470bfa5288SOmar Sandoval 	return 0;
3480bfa5288SOmar Sandoval }
3490bfa5288SOmar Sandoval 
350d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m,
351d96b37c0SOmar Sandoval 				     struct blk_mq_tags *tags)
352d96b37c0SOmar Sandoval {
353d96b37c0SOmar Sandoval 	seq_printf(m, "nr_tags=%u\n", tags->nr_tags);
354d96b37c0SOmar Sandoval 	seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags);
355d96b37c0SOmar Sandoval 	seq_printf(m, "active_queues=%d\n",
356d96b37c0SOmar Sandoval 		   atomic_read(&tags->active_queues));
357d96b37c0SOmar Sandoval 
358d96b37c0SOmar Sandoval 	seq_puts(m, "\nbitmap_tags:\n");
359d96b37c0SOmar Sandoval 	sbitmap_queue_show(&tags->bitmap_tags, m);
360d96b37c0SOmar Sandoval 
361d96b37c0SOmar Sandoval 	if (tags->nr_reserved_tags) {
362d96b37c0SOmar Sandoval 		seq_puts(m, "\nbreserved_tags:\n");
363d96b37c0SOmar Sandoval 		sbitmap_queue_show(&tags->breserved_tags, m);
364d96b37c0SOmar Sandoval 	}
365d96b37c0SOmar Sandoval }
366d96b37c0SOmar Sandoval 
367f57de23aSOmar Sandoval static int hctx_tags_show(void *data, struct seq_file *m)
368d96b37c0SOmar Sandoval {
369f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
370d96b37c0SOmar Sandoval 	struct request_queue *q = hctx->queue;
3718c0f14eaSBart Van Assche 	int res;
372d96b37c0SOmar Sandoval 
3738c0f14eaSBart Van Assche 	res = mutex_lock_interruptible(&q->sysfs_lock);
3748c0f14eaSBart Van Assche 	if (res)
3758c0f14eaSBart Van Assche 		goto out;
376d96b37c0SOmar Sandoval 	if (hctx->tags)
377d96b37c0SOmar Sandoval 		blk_mq_debugfs_tags_show(m, hctx->tags);
378d96b37c0SOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
379d96b37c0SOmar Sandoval 
3808c0f14eaSBart Van Assche out:
3818c0f14eaSBart Van Assche 	return res;
382d96b37c0SOmar Sandoval }
383d96b37c0SOmar Sandoval 
384f57de23aSOmar Sandoval static int hctx_tags_bitmap_show(void *data, struct seq_file *m)
385d96b37c0SOmar Sandoval {
386f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
387d7e3621aSOmar Sandoval 	struct request_queue *q = hctx->queue;
3888c0f14eaSBart Van Assche 	int res;
389d7e3621aSOmar Sandoval 
3908c0f14eaSBart Van Assche 	res = mutex_lock_interruptible(&q->sysfs_lock);
3918c0f14eaSBart Van Assche 	if (res)
3928c0f14eaSBart Van Assche 		goto out;
393d7e3621aSOmar Sandoval 	if (hctx->tags)
394d7e3621aSOmar Sandoval 		sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m);
395d7e3621aSOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
3968c0f14eaSBart Van Assche 
3978c0f14eaSBart Van Assche out:
3988c0f14eaSBart Van Assche 	return res;
399d7e3621aSOmar Sandoval }
400d7e3621aSOmar Sandoval 
401f57de23aSOmar Sandoval static int hctx_sched_tags_show(void *data, struct seq_file *m)
402d7e3621aSOmar Sandoval {
403f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
404d96b37c0SOmar Sandoval 	struct request_queue *q = hctx->queue;
4058c0f14eaSBart Van Assche 	int res;
406d96b37c0SOmar Sandoval 
4078c0f14eaSBart Van Assche 	res = mutex_lock_interruptible(&q->sysfs_lock);
4088c0f14eaSBart Van Assche 	if (res)
4098c0f14eaSBart Van Assche 		goto out;
410d96b37c0SOmar Sandoval 	if (hctx->sched_tags)
411d96b37c0SOmar Sandoval 		blk_mq_debugfs_tags_show(m, hctx->sched_tags);
412d96b37c0SOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
413d96b37c0SOmar Sandoval 
4148c0f14eaSBart Van Assche out:
4158c0f14eaSBart Van Assche 	return res;
416d96b37c0SOmar Sandoval }
417d96b37c0SOmar Sandoval 
418f57de23aSOmar Sandoval static int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m)
419d96b37c0SOmar Sandoval {
420f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
421d7e3621aSOmar Sandoval 	struct request_queue *q = hctx->queue;
4228c0f14eaSBart Van Assche 	int res;
423d7e3621aSOmar Sandoval 
4248c0f14eaSBart Van Assche 	res = mutex_lock_interruptible(&q->sysfs_lock);
4258c0f14eaSBart Van Assche 	if (res)
4268c0f14eaSBart Van Assche 		goto out;
427d7e3621aSOmar Sandoval 	if (hctx->sched_tags)
428d7e3621aSOmar Sandoval 		sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m);
429d7e3621aSOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
4308c0f14eaSBart Van Assche 
4318c0f14eaSBart Van Assche out:
4328c0f14eaSBart Van Assche 	return res;
433d7e3621aSOmar Sandoval }
434d7e3621aSOmar Sandoval 
435f57de23aSOmar Sandoval static int hctx_io_poll_show(void *data, struct seq_file *m)
436d7e3621aSOmar Sandoval {
437f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
438be215473SOmar Sandoval 
439be215473SOmar Sandoval 	seq_printf(m, "considered=%lu\n", hctx->poll_considered);
440be215473SOmar Sandoval 	seq_printf(m, "invoked=%lu\n", hctx->poll_invoked);
441be215473SOmar Sandoval 	seq_printf(m, "success=%lu\n", hctx->poll_success);
442be215473SOmar Sandoval 	return 0;
443be215473SOmar Sandoval }
444be215473SOmar Sandoval 
445f57de23aSOmar Sandoval static ssize_t hctx_io_poll_write(void *data, const char __user *buf,
446be215473SOmar Sandoval 				  size_t count, loff_t *ppos)
447be215473SOmar Sandoval {
448f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
449be215473SOmar Sandoval 
450be215473SOmar Sandoval 	hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0;
451be215473SOmar Sandoval 	return count;
452be215473SOmar Sandoval }
453be215473SOmar Sandoval 
454f57de23aSOmar Sandoval static int hctx_dispatched_show(void *data, struct seq_file *m)
455be215473SOmar Sandoval {
456f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
457be215473SOmar Sandoval 	int i;
458be215473SOmar Sandoval 
459be215473SOmar Sandoval 	seq_printf(m, "%8u\t%lu\n", 0U, hctx->dispatched[0]);
460be215473SOmar Sandoval 
461be215473SOmar Sandoval 	for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) {
462be215473SOmar Sandoval 		unsigned int d = 1U << (i - 1);
463be215473SOmar Sandoval 
464be215473SOmar Sandoval 		seq_printf(m, "%8u\t%lu\n", d, hctx->dispatched[i]);
465be215473SOmar Sandoval 	}
466be215473SOmar Sandoval 
467be215473SOmar Sandoval 	seq_printf(m, "%8u+\t%lu\n", 1U << (i - 1), hctx->dispatched[i]);
468be215473SOmar Sandoval 	return 0;
469be215473SOmar Sandoval }
470be215473SOmar Sandoval 
471f57de23aSOmar Sandoval static ssize_t hctx_dispatched_write(void *data, const char __user *buf,
472be215473SOmar Sandoval 				     size_t count, loff_t *ppos)
473be215473SOmar Sandoval {
474f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
475be215473SOmar Sandoval 	int i;
476be215473SOmar Sandoval 
477be215473SOmar Sandoval 	for (i = 0; i < BLK_MQ_MAX_DISPATCH_ORDER; i++)
478be215473SOmar Sandoval 		hctx->dispatched[i] = 0;
479be215473SOmar Sandoval 	return count;
480be215473SOmar Sandoval }
481be215473SOmar Sandoval 
482f57de23aSOmar Sandoval static int hctx_queued_show(void *data, struct seq_file *m)
4834a46f05eSOmar Sandoval {
484f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
4854a46f05eSOmar Sandoval 
4864a46f05eSOmar Sandoval 	seq_printf(m, "%lu\n", hctx->queued);
4874a46f05eSOmar Sandoval 	return 0;
4884a46f05eSOmar Sandoval }
4894a46f05eSOmar Sandoval 
490f57de23aSOmar Sandoval static ssize_t hctx_queued_write(void *data, const char __user *buf,
4914a46f05eSOmar Sandoval 				 size_t count, loff_t *ppos)
4924a46f05eSOmar Sandoval {
493f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
4944a46f05eSOmar Sandoval 
4954a46f05eSOmar Sandoval 	hctx->queued = 0;
4964a46f05eSOmar Sandoval 	return count;
4974a46f05eSOmar Sandoval }
4984a46f05eSOmar Sandoval 
499f57de23aSOmar Sandoval static int hctx_run_show(void *data, struct seq_file *m)
5004a46f05eSOmar Sandoval {
501f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
5024a46f05eSOmar Sandoval 
5034a46f05eSOmar Sandoval 	seq_printf(m, "%lu\n", hctx->run);
5044a46f05eSOmar Sandoval 	return 0;
5054a46f05eSOmar Sandoval }
5064a46f05eSOmar Sandoval 
507f57de23aSOmar Sandoval static ssize_t hctx_run_write(void *data, const char __user *buf, size_t count,
508f57de23aSOmar Sandoval 			      loff_t *ppos)
5094a46f05eSOmar Sandoval {
510f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
5114a46f05eSOmar Sandoval 
5124a46f05eSOmar Sandoval 	hctx->run = 0;
5134a46f05eSOmar Sandoval 	return count;
5144a46f05eSOmar Sandoval }
5154a46f05eSOmar Sandoval 
516f57de23aSOmar Sandoval static int hctx_active_show(void *data, struct seq_file *m)
5174a46f05eSOmar Sandoval {
518f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
5194a46f05eSOmar Sandoval 
5204a46f05eSOmar Sandoval 	seq_printf(m, "%d\n", atomic_read(&hctx->nr_active));
5214a46f05eSOmar Sandoval 	return 0;
5224a46f05eSOmar Sandoval }
5234a46f05eSOmar Sandoval 
524950cd7e9SOmar Sandoval static void *ctx_rq_list_start(struct seq_file *m, loff_t *pos)
525f3bcb0e6SBart Van Assche 	__acquires(&ctx->lock)
526950cd7e9SOmar Sandoval {
527950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
528950cd7e9SOmar Sandoval 
529950cd7e9SOmar Sandoval 	spin_lock(&ctx->lock);
530950cd7e9SOmar Sandoval 	return seq_list_start(&ctx->rq_list, *pos);
531950cd7e9SOmar Sandoval }
532950cd7e9SOmar Sandoval 
533950cd7e9SOmar Sandoval static void *ctx_rq_list_next(struct seq_file *m, void *v, loff_t *pos)
534950cd7e9SOmar Sandoval {
535950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
536950cd7e9SOmar Sandoval 
537950cd7e9SOmar Sandoval 	return seq_list_next(v, &ctx->rq_list, pos);
538950cd7e9SOmar Sandoval }
539950cd7e9SOmar Sandoval 
540950cd7e9SOmar Sandoval static void ctx_rq_list_stop(struct seq_file *m, void *v)
541f3bcb0e6SBart Van Assche 	__releases(&ctx->lock)
542950cd7e9SOmar Sandoval {
543950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
544950cd7e9SOmar Sandoval 
545950cd7e9SOmar Sandoval 	spin_unlock(&ctx->lock);
546950cd7e9SOmar Sandoval }
547950cd7e9SOmar Sandoval 
548950cd7e9SOmar Sandoval static const struct seq_operations ctx_rq_list_seq_ops = {
549950cd7e9SOmar Sandoval 	.start	= ctx_rq_list_start,
550950cd7e9SOmar Sandoval 	.next	= ctx_rq_list_next,
551950cd7e9SOmar Sandoval 	.stop	= ctx_rq_list_stop,
552950cd7e9SOmar Sandoval 	.show	= blk_mq_debugfs_rq_show,
553950cd7e9SOmar Sandoval };
554f57de23aSOmar Sandoval static int ctx_dispatched_show(void *data, struct seq_file *m)
555950cd7e9SOmar Sandoval {
556f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5574a46f05eSOmar Sandoval 
5584a46f05eSOmar Sandoval 	seq_printf(m, "%lu %lu\n", ctx->rq_dispatched[1], ctx->rq_dispatched[0]);
5594a46f05eSOmar Sandoval 	return 0;
5604a46f05eSOmar Sandoval }
5614a46f05eSOmar Sandoval 
562f57de23aSOmar Sandoval static ssize_t ctx_dispatched_write(void *data, const char __user *buf,
5634a46f05eSOmar Sandoval 				    size_t count, loff_t *ppos)
5644a46f05eSOmar Sandoval {
565f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5664a46f05eSOmar Sandoval 
5674a46f05eSOmar Sandoval 	ctx->rq_dispatched[0] = ctx->rq_dispatched[1] = 0;
5684a46f05eSOmar Sandoval 	return count;
5694a46f05eSOmar Sandoval }
5704a46f05eSOmar Sandoval 
571f57de23aSOmar Sandoval static int ctx_merged_show(void *data, struct seq_file *m)
5724a46f05eSOmar Sandoval {
573f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5744a46f05eSOmar Sandoval 
5754a46f05eSOmar Sandoval 	seq_printf(m, "%lu\n", ctx->rq_merged);
5764a46f05eSOmar Sandoval 	return 0;
5774a46f05eSOmar Sandoval }
5784a46f05eSOmar Sandoval 
579f57de23aSOmar Sandoval static ssize_t ctx_merged_write(void *data, const char __user *buf,
5804a46f05eSOmar Sandoval 				size_t count, loff_t *ppos)
5814a46f05eSOmar Sandoval {
582f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5834a46f05eSOmar Sandoval 
5844a46f05eSOmar Sandoval 	ctx->rq_merged = 0;
5854a46f05eSOmar Sandoval 	return count;
5864a46f05eSOmar Sandoval }
5874a46f05eSOmar Sandoval 
588f57de23aSOmar Sandoval static int ctx_completed_show(void *data, struct seq_file *m)
5894a46f05eSOmar Sandoval {
590f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5914a46f05eSOmar Sandoval 
5924a46f05eSOmar Sandoval 	seq_printf(m, "%lu %lu\n", ctx->rq_completed[1], ctx->rq_completed[0]);
5934a46f05eSOmar Sandoval 	return 0;
5944a46f05eSOmar Sandoval }
5954a46f05eSOmar Sandoval 
596f57de23aSOmar Sandoval static ssize_t ctx_completed_write(void *data, const char __user *buf,
5974a46f05eSOmar Sandoval 				   size_t count, loff_t *ppos)
5984a46f05eSOmar Sandoval {
599f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
6004a46f05eSOmar Sandoval 
6014a46f05eSOmar Sandoval 	ctx->rq_completed[0] = ctx->rq_completed[1] = 0;
6024a46f05eSOmar Sandoval 	return count;
6034a46f05eSOmar Sandoval }
6044a46f05eSOmar Sandoval 
605f57de23aSOmar Sandoval static int blk_mq_debugfs_show(struct seq_file *m, void *v)
606f57de23aSOmar Sandoval {
607f57de23aSOmar Sandoval 	const struct blk_mq_debugfs_attr *attr = m->private;
608f57de23aSOmar Sandoval 	void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private;
609f57de23aSOmar Sandoval 
610f57de23aSOmar Sandoval 	return attr->show(data, m);
611f57de23aSOmar Sandoval }
612f57de23aSOmar Sandoval 
613f57de23aSOmar Sandoval static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf,
614f57de23aSOmar Sandoval 				    size_t count, loff_t *ppos)
615f57de23aSOmar Sandoval {
616f57de23aSOmar Sandoval 	struct seq_file *m = file->private_data;
617f57de23aSOmar Sandoval 	const struct blk_mq_debugfs_attr *attr = m->private;
618f57de23aSOmar Sandoval 	void *data = d_inode(file->f_path.dentry->d_parent)->i_private;
619f57de23aSOmar Sandoval 
620f57de23aSOmar Sandoval 	if (!attr->write)
621f57de23aSOmar Sandoval 		return -EPERM;
622f57de23aSOmar Sandoval 
623f57de23aSOmar Sandoval 	return attr->write(data, buf, count, ppos);
624f57de23aSOmar Sandoval }
625f57de23aSOmar Sandoval 
626f57de23aSOmar Sandoval static int blk_mq_debugfs_open(struct inode *inode, struct file *file)
627f57de23aSOmar Sandoval {
628f57de23aSOmar Sandoval 	const struct blk_mq_debugfs_attr *attr = inode->i_private;
629f57de23aSOmar Sandoval 	void *data = d_inode(file->f_path.dentry->d_parent)->i_private;
630f57de23aSOmar Sandoval 	struct seq_file *m;
631f57de23aSOmar Sandoval 	int ret;
632f57de23aSOmar Sandoval 
633f57de23aSOmar Sandoval 	if (attr->seq_ops) {
634f57de23aSOmar Sandoval 		ret = seq_open(file, attr->seq_ops);
635f57de23aSOmar Sandoval 		if (!ret) {
636f57de23aSOmar Sandoval 			m = file->private_data;
637f57de23aSOmar Sandoval 			m->private = data;
638f57de23aSOmar Sandoval 		}
639f57de23aSOmar Sandoval 		return ret;
640f57de23aSOmar Sandoval 	}
641f57de23aSOmar Sandoval 
642f57de23aSOmar Sandoval 	if (WARN_ON_ONCE(!attr->show))
643f57de23aSOmar Sandoval 		return -EPERM;
644f57de23aSOmar Sandoval 
645f57de23aSOmar Sandoval 	return single_open(file, blk_mq_debugfs_show, inode->i_private);
646f57de23aSOmar Sandoval }
647f57de23aSOmar Sandoval 
648f57de23aSOmar Sandoval static int blk_mq_debugfs_release(struct inode *inode, struct file *file)
649f57de23aSOmar Sandoval {
650f57de23aSOmar Sandoval 	const struct blk_mq_debugfs_attr *attr = inode->i_private;
651f57de23aSOmar Sandoval 
652f57de23aSOmar Sandoval 	if (attr->show)
653f57de23aSOmar Sandoval 		return single_release(inode, file);
654f57de23aSOmar Sandoval 	else
655f57de23aSOmar Sandoval 		return seq_release(inode, file);
656f57de23aSOmar Sandoval }
657f57de23aSOmar Sandoval 
658f57de23aSOmar Sandoval const struct file_operations blk_mq_debugfs_fops = {
659f57de23aSOmar Sandoval 	.open		= blk_mq_debugfs_open,
6604a46f05eSOmar Sandoval 	.read		= seq_read,
661f57de23aSOmar Sandoval 	.write		= blk_mq_debugfs_write,
6624a46f05eSOmar Sandoval 	.llseek		= seq_lseek,
663f57de23aSOmar Sandoval 	.release	= blk_mq_debugfs_release,
6644a46f05eSOmar Sandoval };
6654a46f05eSOmar Sandoval 
66634dbad5dSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = {
667f57de23aSOmar Sandoval 	{"poll_stat", 0400, queue_poll_stat_show},
668f57de23aSOmar Sandoval 	{"state", 0600, queue_state_show, queue_state_write},
66934dbad5dSOmar Sandoval 	{},
67034dbad5dSOmar Sandoval };
67134dbad5dSOmar Sandoval 
67207e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = {
673f57de23aSOmar Sandoval 	{"state", 0400, hctx_state_show},
674f57de23aSOmar Sandoval 	{"flags", 0400, hctx_flags_show},
675f57de23aSOmar Sandoval 	{"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops},
676f57de23aSOmar Sandoval 	{"ctx_map", 0400, hctx_ctx_map_show},
677f57de23aSOmar Sandoval 	{"tags", 0400, hctx_tags_show},
678f57de23aSOmar Sandoval 	{"tags_bitmap", 0400, hctx_tags_bitmap_show},
679f57de23aSOmar Sandoval 	{"sched_tags", 0400, hctx_sched_tags_show},
680f57de23aSOmar Sandoval 	{"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show},
681f57de23aSOmar Sandoval 	{"io_poll", 0600, hctx_io_poll_show, hctx_io_poll_write},
682f57de23aSOmar Sandoval 	{"dispatched", 0600, hctx_dispatched_show, hctx_dispatched_write},
683f57de23aSOmar Sandoval 	{"queued", 0600, hctx_queued_show, hctx_queued_write},
684f57de23aSOmar Sandoval 	{"run", 0600, hctx_run_show, hctx_run_write},
685f57de23aSOmar Sandoval 	{"active", 0400, hctx_active_show},
68672f2f8f6SBart Van Assche 	{},
68707e4feadSOmar Sandoval };
68807e4feadSOmar Sandoval 
68907e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = {
690f57de23aSOmar Sandoval 	{"rq_list", 0400, .seq_ops = &ctx_rq_list_seq_ops},
691f57de23aSOmar Sandoval 	{"dispatched", 0600, ctx_dispatched_show, ctx_dispatched_write},
692f57de23aSOmar Sandoval 	{"merged", 0600, ctx_merged_show, ctx_merged_write},
693f57de23aSOmar Sandoval 	{"completed", 0600, ctx_completed_show, ctx_completed_write},
69472f2f8f6SBart Van Assche 	{},
69507e4feadSOmar Sandoval };
69607e4feadSOmar Sandoval 
69772f2f8f6SBart Van Assche static bool debugfs_create_files(struct dentry *parent, void *data,
69872f2f8f6SBart Van Assche 				 const struct blk_mq_debugfs_attr *attr)
69972f2f8f6SBart Van Assche {
700f57de23aSOmar Sandoval 	d_inode(parent)->i_private = data;
701f57de23aSOmar Sandoval 
70272f2f8f6SBart Van Assche 	for (; attr->name; attr++) {
70372f2f8f6SBart Van Assche 		if (!debugfs_create_file(attr->name, attr->mode, parent,
704f57de23aSOmar Sandoval 					 (void *)attr, &blk_mq_debugfs_fops))
70572f2f8f6SBart Van Assche 			return false;
70672f2f8f6SBart Van Assche 	}
70772f2f8f6SBart Van Assche 	return true;
70872f2f8f6SBart Van Assche }
70972f2f8f6SBart Van Assche 
7109c1051aaSOmar Sandoval int blk_mq_debugfs_register(struct request_queue *q)
7119c1051aaSOmar Sandoval {
7129c1051aaSOmar Sandoval 	struct blk_mq_hw_ctx *hctx;
7139c1051aaSOmar Sandoval 	int i;
7149c1051aaSOmar Sandoval 
7159c1051aaSOmar Sandoval 	if (!blk_debugfs_root)
7169c1051aaSOmar Sandoval 		return -ENOENT;
7179c1051aaSOmar Sandoval 
7189c1051aaSOmar Sandoval 	q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent),
7199c1051aaSOmar Sandoval 					    blk_debugfs_root);
7209c1051aaSOmar Sandoval 	if (!q->debugfs_dir)
7219c1051aaSOmar Sandoval 		return -ENOMEM;
7229c1051aaSOmar Sandoval 
7239c1051aaSOmar Sandoval 	if (!debugfs_create_files(q->debugfs_dir, q,
7249c1051aaSOmar Sandoval 				  blk_mq_debugfs_queue_attrs))
7259c1051aaSOmar Sandoval 		goto err;
7269c1051aaSOmar Sandoval 
7279c1051aaSOmar Sandoval 	/*
7289c1051aaSOmar Sandoval 	 * blk_mq_init_hctx() attempted to do this already, but q->debugfs_dir
7299c1051aaSOmar Sandoval 	 * didn't exist yet (because we don't know what to name the directory
7309c1051aaSOmar Sandoval 	 * until the queue is registered to a gendisk).
7319c1051aaSOmar Sandoval 	 */
7329c1051aaSOmar Sandoval 	queue_for_each_hw_ctx(q, hctx, i) {
7339c1051aaSOmar Sandoval 		if (!hctx->debugfs_dir && blk_mq_debugfs_register_hctx(q, hctx))
7349c1051aaSOmar Sandoval 			goto err;
735d332ce09SOmar Sandoval 		if (q->elevator && !hctx->sched_debugfs_dir &&
736d332ce09SOmar Sandoval 		    blk_mq_debugfs_register_sched_hctx(q, hctx))
737d332ce09SOmar Sandoval 			goto err;
7389c1051aaSOmar Sandoval 	}
7399c1051aaSOmar Sandoval 
7409c1051aaSOmar Sandoval 	return 0;
7419c1051aaSOmar Sandoval 
7429c1051aaSOmar Sandoval err:
7439c1051aaSOmar Sandoval 	blk_mq_debugfs_unregister(q);
7449c1051aaSOmar Sandoval 	return -ENOMEM;
7459c1051aaSOmar Sandoval }
7469c1051aaSOmar Sandoval 
7479c1051aaSOmar Sandoval void blk_mq_debugfs_unregister(struct request_queue *q)
7489c1051aaSOmar Sandoval {
7499c1051aaSOmar Sandoval 	debugfs_remove_recursive(q->debugfs_dir);
750d332ce09SOmar Sandoval 	q->sched_debugfs_dir = NULL;
7519c1051aaSOmar Sandoval 	q->debugfs_dir = NULL;
7529c1051aaSOmar Sandoval }
7539c1051aaSOmar Sandoval 
7549c1051aaSOmar Sandoval static int blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
7559c1051aaSOmar Sandoval 				       struct blk_mq_ctx *ctx)
75607e4feadSOmar Sandoval {
75707e4feadSOmar Sandoval 	struct dentry *ctx_dir;
75807e4feadSOmar Sandoval 	char name[20];
75907e4feadSOmar Sandoval 
76007e4feadSOmar Sandoval 	snprintf(name, sizeof(name), "cpu%u", ctx->cpu);
7619c1051aaSOmar Sandoval 	ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir);
76207e4feadSOmar Sandoval 	if (!ctx_dir)
76307e4feadSOmar Sandoval 		return -ENOMEM;
76407e4feadSOmar Sandoval 
76572f2f8f6SBart Van Assche 	if (!debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs))
76607e4feadSOmar Sandoval 		return -ENOMEM;
76707e4feadSOmar Sandoval 
76807e4feadSOmar Sandoval 	return 0;
76907e4feadSOmar Sandoval }
77007e4feadSOmar Sandoval 
7719c1051aaSOmar Sandoval int blk_mq_debugfs_register_hctx(struct request_queue *q,
77207e4feadSOmar Sandoval 				 struct blk_mq_hw_ctx *hctx)
77307e4feadSOmar Sandoval {
77407e4feadSOmar Sandoval 	struct blk_mq_ctx *ctx;
77507e4feadSOmar Sandoval 	char name[20];
77607e4feadSOmar Sandoval 	int i;
77707e4feadSOmar Sandoval 
77807e4feadSOmar Sandoval 	if (!q->debugfs_dir)
77907e4feadSOmar Sandoval 		return -ENOENT;
78007e4feadSOmar Sandoval 
7819c1051aaSOmar Sandoval 	snprintf(name, sizeof(name), "hctx%u", hctx->queue_num);
7829c1051aaSOmar Sandoval 	hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir);
7839c1051aaSOmar Sandoval 	if (!hctx->debugfs_dir)
7849c1051aaSOmar Sandoval 		return -ENOMEM;
7859c1051aaSOmar Sandoval 
7869c1051aaSOmar Sandoval 	if (!debugfs_create_files(hctx->debugfs_dir, hctx,
7879c1051aaSOmar Sandoval 				  blk_mq_debugfs_hctx_attrs))
78807e4feadSOmar Sandoval 		goto err;
78907e4feadSOmar Sandoval 
7909c1051aaSOmar Sandoval 	hctx_for_each_ctx(hctx, ctx, i) {
7919c1051aaSOmar Sandoval 		if (blk_mq_debugfs_register_ctx(hctx, ctx))
79207e4feadSOmar Sandoval 			goto err;
79307e4feadSOmar Sandoval 	}
79407e4feadSOmar Sandoval 
79507e4feadSOmar Sandoval 	return 0;
79607e4feadSOmar Sandoval 
79707e4feadSOmar Sandoval err:
7989c1051aaSOmar Sandoval 	blk_mq_debugfs_unregister_hctx(hctx);
79907e4feadSOmar Sandoval 	return -ENOMEM;
80007e4feadSOmar Sandoval }
80107e4feadSOmar Sandoval 
8029c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx)
80307e4feadSOmar Sandoval {
8049c1051aaSOmar Sandoval 	debugfs_remove_recursive(hctx->debugfs_dir);
805d332ce09SOmar Sandoval 	hctx->sched_debugfs_dir = NULL;
8069c1051aaSOmar Sandoval 	hctx->debugfs_dir = NULL;
8079c1051aaSOmar Sandoval }
8089c1051aaSOmar Sandoval 
8099c1051aaSOmar Sandoval int blk_mq_debugfs_register_hctxs(struct request_queue *q)
8109c1051aaSOmar Sandoval {
8119c1051aaSOmar Sandoval 	struct blk_mq_hw_ctx *hctx;
8129c1051aaSOmar Sandoval 	int i;
8139c1051aaSOmar Sandoval 
8149c1051aaSOmar Sandoval 	queue_for_each_hw_ctx(q, hctx, i) {
8159c1051aaSOmar Sandoval 		if (blk_mq_debugfs_register_hctx(q, hctx))
8169c1051aaSOmar Sandoval 			return -ENOMEM;
8179c1051aaSOmar Sandoval 	}
8189c1051aaSOmar Sandoval 
8199c1051aaSOmar Sandoval 	return 0;
8209c1051aaSOmar Sandoval }
8219c1051aaSOmar Sandoval 
8229c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
8239c1051aaSOmar Sandoval {
8249c1051aaSOmar Sandoval 	struct blk_mq_hw_ctx *hctx;
8259c1051aaSOmar Sandoval 	int i;
8269c1051aaSOmar Sandoval 
8279c1051aaSOmar Sandoval 	queue_for_each_hw_ctx(q, hctx, i)
8289c1051aaSOmar Sandoval 		blk_mq_debugfs_unregister_hctx(hctx);
82907e4feadSOmar Sandoval }
830d332ce09SOmar Sandoval 
831d332ce09SOmar Sandoval int blk_mq_debugfs_register_sched(struct request_queue *q)
832d332ce09SOmar Sandoval {
833d332ce09SOmar Sandoval 	struct elevator_type *e = q->elevator->type;
834d332ce09SOmar Sandoval 
835d332ce09SOmar Sandoval 	if (!q->debugfs_dir)
836d332ce09SOmar Sandoval 		return -ENOENT;
837d332ce09SOmar Sandoval 
838d332ce09SOmar Sandoval 	if (!e->queue_debugfs_attrs)
839d332ce09SOmar Sandoval 		return 0;
840d332ce09SOmar Sandoval 
841d332ce09SOmar Sandoval 	q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir);
842d332ce09SOmar Sandoval 	if (!q->sched_debugfs_dir)
843d332ce09SOmar Sandoval 		return -ENOMEM;
844d332ce09SOmar Sandoval 
845d332ce09SOmar Sandoval 	if (!debugfs_create_files(q->sched_debugfs_dir, q,
846d332ce09SOmar Sandoval 				  e->queue_debugfs_attrs))
847d332ce09SOmar Sandoval 		goto err;
848d332ce09SOmar Sandoval 
849d332ce09SOmar Sandoval 	return 0;
850d332ce09SOmar Sandoval 
851d332ce09SOmar Sandoval err:
852d332ce09SOmar Sandoval 	blk_mq_debugfs_unregister_sched(q);
853d332ce09SOmar Sandoval 	return -ENOMEM;
854d332ce09SOmar Sandoval }
855d332ce09SOmar Sandoval 
856d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched(struct request_queue *q)
857d332ce09SOmar Sandoval {
858d332ce09SOmar Sandoval 	debugfs_remove_recursive(q->sched_debugfs_dir);
859d332ce09SOmar Sandoval 	q->sched_debugfs_dir = NULL;
860d332ce09SOmar Sandoval }
861d332ce09SOmar Sandoval 
862d332ce09SOmar Sandoval int blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
863d332ce09SOmar Sandoval 				       struct blk_mq_hw_ctx *hctx)
864d332ce09SOmar Sandoval {
865d332ce09SOmar Sandoval 	struct elevator_type *e = q->elevator->type;
866d332ce09SOmar Sandoval 
867d332ce09SOmar Sandoval 	if (!hctx->debugfs_dir)
868d332ce09SOmar Sandoval 		return -ENOENT;
869d332ce09SOmar Sandoval 
870d332ce09SOmar Sandoval 	if (!e->hctx_debugfs_attrs)
871d332ce09SOmar Sandoval 		return 0;
872d332ce09SOmar Sandoval 
873d332ce09SOmar Sandoval 	hctx->sched_debugfs_dir = debugfs_create_dir("sched",
874d332ce09SOmar Sandoval 						     hctx->debugfs_dir);
875d332ce09SOmar Sandoval 	if (!hctx->sched_debugfs_dir)
876d332ce09SOmar Sandoval 		return -ENOMEM;
877d332ce09SOmar Sandoval 
878d332ce09SOmar Sandoval 	if (!debugfs_create_files(hctx->sched_debugfs_dir, hctx,
879d332ce09SOmar Sandoval 				  e->hctx_debugfs_attrs))
880d332ce09SOmar Sandoval 		return -ENOMEM;
881d332ce09SOmar Sandoval 
882d332ce09SOmar Sandoval 	return 0;
883d332ce09SOmar Sandoval }
884d332ce09SOmar Sandoval 
885d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx)
886d332ce09SOmar Sandoval {
887d332ce09SOmar Sandoval 	debugfs_remove_recursive(hctx->sched_debugfs_dir);
888d332ce09SOmar Sandoval 	hctx->sched_debugfs_dir = NULL;
889d332ce09SOmar Sandoval }
890