xref: /linux/block/blk-mq-debugfs.c (revision d173a25165c124442182f6b21d0c2ec381a0eebe)
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"
24*d173a251SOmar Sandoval #include "blk-mq-debugfs.h"
25d96b37c0SOmar Sandoval #include "blk-mq-tag.h"
2607e4feadSOmar Sandoval 
2707e4feadSOmar Sandoval struct blk_mq_debugfs_attr {
2807e4feadSOmar Sandoval 	const char *name;
2907e4feadSOmar Sandoval 	umode_t mode;
30f57de23aSOmar Sandoval 	int (*show)(void *, struct seq_file *);
31f57de23aSOmar Sandoval 	ssize_t (*write)(void *, const char __user *, size_t, loff_t *);
32f57de23aSOmar Sandoval 	/* Set either .show or .seq_ops. */
33f57de23aSOmar Sandoval 	const struct seq_operations *seq_ops;
3407e4feadSOmar Sandoval };
3507e4feadSOmar Sandoval 
3691d68905SBart Van Assche static int blk_flags_show(struct seq_file *m, const unsigned long flags,
3791d68905SBart Van Assche 			  const char *const *flag_name, int flag_name_count)
3891d68905SBart Van Assche {
3991d68905SBart Van Assche 	bool sep = false;
4091d68905SBart Van Assche 	int i;
4191d68905SBart Van Assche 
4291d68905SBart Van Assche 	for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) {
4391d68905SBart Van Assche 		if (!(flags & BIT(i)))
4491d68905SBart Van Assche 			continue;
4591d68905SBart Van Assche 		if (sep)
46bec03d6bSOmar Sandoval 			seq_puts(m, "|");
4791d68905SBart Van Assche 		sep = true;
4891d68905SBart Van Assche 		if (i < flag_name_count && flag_name[i])
4991d68905SBart Van Assche 			seq_puts(m, flag_name[i]);
5091d68905SBart Van Assche 		else
5191d68905SBart Van Assche 			seq_printf(m, "%d", i);
5291d68905SBart Van Assche 	}
5391d68905SBart Van Assche 	return 0;
5491d68905SBart Van Assche }
5591d68905SBart Van Assche 
561a435111SOmar Sandoval #define QUEUE_FLAG_NAME(name) [QUEUE_FLAG_##name] = #name
5791d68905SBart Van Assche static const char *const blk_queue_flag_name[] = {
581a435111SOmar Sandoval 	QUEUE_FLAG_NAME(QUEUED),
591a435111SOmar Sandoval 	QUEUE_FLAG_NAME(STOPPED),
601a435111SOmar Sandoval 	QUEUE_FLAG_NAME(SYNCFULL),
611a435111SOmar Sandoval 	QUEUE_FLAG_NAME(ASYNCFULL),
621a435111SOmar Sandoval 	QUEUE_FLAG_NAME(DYING),
631a435111SOmar Sandoval 	QUEUE_FLAG_NAME(BYPASS),
641a435111SOmar Sandoval 	QUEUE_FLAG_NAME(BIDI),
651a435111SOmar Sandoval 	QUEUE_FLAG_NAME(NOMERGES),
661a435111SOmar Sandoval 	QUEUE_FLAG_NAME(SAME_COMP),
671a435111SOmar Sandoval 	QUEUE_FLAG_NAME(FAIL_IO),
681a435111SOmar Sandoval 	QUEUE_FLAG_NAME(STACKABLE),
691a435111SOmar Sandoval 	QUEUE_FLAG_NAME(NONROT),
701a435111SOmar Sandoval 	QUEUE_FLAG_NAME(IO_STAT),
711a435111SOmar Sandoval 	QUEUE_FLAG_NAME(DISCARD),
721a435111SOmar Sandoval 	QUEUE_FLAG_NAME(NOXMERGES),
731a435111SOmar Sandoval 	QUEUE_FLAG_NAME(ADD_RANDOM),
741a435111SOmar Sandoval 	QUEUE_FLAG_NAME(SECERASE),
751a435111SOmar Sandoval 	QUEUE_FLAG_NAME(SAME_FORCE),
761a435111SOmar Sandoval 	QUEUE_FLAG_NAME(DEAD),
771a435111SOmar Sandoval 	QUEUE_FLAG_NAME(INIT_DONE),
781a435111SOmar Sandoval 	QUEUE_FLAG_NAME(NO_SG_MERGE),
791a435111SOmar Sandoval 	QUEUE_FLAG_NAME(POLL),
801a435111SOmar Sandoval 	QUEUE_FLAG_NAME(WC),
811a435111SOmar Sandoval 	QUEUE_FLAG_NAME(FUA),
821a435111SOmar Sandoval 	QUEUE_FLAG_NAME(FLUSH_NQ),
831a435111SOmar Sandoval 	QUEUE_FLAG_NAME(DAX),
841a435111SOmar Sandoval 	QUEUE_FLAG_NAME(STATS),
851a435111SOmar Sandoval 	QUEUE_FLAG_NAME(POLL_STATS),
861a435111SOmar Sandoval 	QUEUE_FLAG_NAME(REGISTERED),
8791d68905SBart Van Assche };
881a435111SOmar Sandoval #undef QUEUE_FLAG_NAME
8991d68905SBart Van Assche 
90f57de23aSOmar Sandoval static int queue_state_show(void *data, struct seq_file *m)
9191d68905SBart Van Assche {
92f57de23aSOmar Sandoval 	struct request_queue *q = data;
9391d68905SBart Van Assche 
9491d68905SBart Van Assche 	blk_flags_show(m, q->queue_flags, blk_queue_flag_name,
9591d68905SBart Van Assche 		       ARRAY_SIZE(blk_queue_flag_name));
96fd07dc81SBart Van Assche 	seq_puts(m, "\n");
9791d68905SBart Van Assche 	return 0;
9891d68905SBart Van Assche }
9991d68905SBart Van Assche 
100f57de23aSOmar Sandoval static ssize_t queue_state_write(void *data, const char __user *buf,
101c7e4145aSOmar Sandoval 				 size_t count, loff_t *ppos)
10291d68905SBart Van Assche {
103f57de23aSOmar Sandoval 	struct request_queue *q = data;
10471b90511SOmar Sandoval 	char opbuf[16] = { }, *op;
10591d68905SBart Van Assche 
10618d4d7d0SBart Van Assche 	/*
10718d4d7d0SBart Van Assche 	 * The "state" attribute is removed after blk_cleanup_queue() has called
10818d4d7d0SBart Van Assche 	 * blk_mq_free_queue(). Return if QUEUE_FLAG_DEAD has been set to avoid
10918d4d7d0SBart Van Assche 	 * triggering a use-after-free.
11018d4d7d0SBart Van Assche 	 */
11118d4d7d0SBart Van Assche 	if (blk_queue_dead(q))
11218d4d7d0SBart Van Assche 		return -ENOENT;
11318d4d7d0SBart Van Assche 
11471b90511SOmar Sandoval 	if (count >= sizeof(opbuf)) {
115c7e4145aSOmar Sandoval 		pr_err("%s: operation too long\n", __func__);
116c7e4145aSOmar Sandoval 		goto inval;
117c7e4145aSOmar Sandoval 	}
118c7e4145aSOmar Sandoval 
11971b90511SOmar Sandoval 	if (copy_from_user(opbuf, buf, count))
12091d68905SBart Van Assche 		return -EFAULT;
12171b90511SOmar Sandoval 	op = strstrip(opbuf);
12291d68905SBart Van Assche 	if (strcmp(op, "run") == 0) {
12391d68905SBart Van Assche 		blk_mq_run_hw_queues(q, true);
12491d68905SBart Van Assche 	} else if (strcmp(op, "start") == 0) {
12591d68905SBart Van Assche 		blk_mq_start_stopped_hw_queues(q, true);
12691d68905SBart Van Assche 	} else {
127c7e4145aSOmar Sandoval 		pr_err("%s: unsupported operation '%s'\n", __func__, op);
128c7e4145aSOmar Sandoval inval:
129c7e4145aSOmar Sandoval 		pr_err("%s: use either 'run' or 'start'\n", __func__);
13091d68905SBart Van Assche 		return -EINVAL;
13191d68905SBart Van Assche 	}
132c7e4145aSOmar Sandoval 	return count;
13391d68905SBart Van Assche }
13491d68905SBart Van Assche 
13534dbad5dSOmar Sandoval static void print_stat(struct seq_file *m, struct blk_rq_stat *stat)
13634dbad5dSOmar Sandoval {
13734dbad5dSOmar Sandoval 	if (stat->nr_samples) {
13834dbad5dSOmar Sandoval 		seq_printf(m, "samples=%d, mean=%lld, min=%llu, max=%llu",
13934dbad5dSOmar Sandoval 			   stat->nr_samples, stat->mean, stat->min, stat->max);
14034dbad5dSOmar Sandoval 	} else {
14134dbad5dSOmar Sandoval 		seq_puts(m, "samples=0");
14234dbad5dSOmar Sandoval 	}
14334dbad5dSOmar Sandoval }
14434dbad5dSOmar Sandoval 
145f57de23aSOmar Sandoval static int queue_poll_stat_show(void *data, struct seq_file *m)
14634dbad5dSOmar Sandoval {
147f57de23aSOmar Sandoval 	struct request_queue *q = data;
1480206319fSStephen Bates 	int bucket;
14934dbad5dSOmar Sandoval 
1500206319fSStephen Bates 	for (bucket = 0; bucket < BLK_MQ_POLL_STATS_BKTS/2; bucket++) {
1510206319fSStephen Bates 		seq_printf(m, "read  (%d Bytes): ", 1 << (9+bucket));
1520206319fSStephen Bates 		print_stat(m, &q->poll_stat[2*bucket]);
15334dbad5dSOmar Sandoval 		seq_puts(m, "\n");
15434dbad5dSOmar Sandoval 
1550206319fSStephen Bates 		seq_printf(m, "write (%d Bytes): ",  1 << (9+bucket));
1560206319fSStephen Bates 		print_stat(m, &q->poll_stat[2*bucket+1]);
15734dbad5dSOmar Sandoval 		seq_puts(m, "\n");
1580206319fSStephen Bates 	}
15934dbad5dSOmar Sandoval 	return 0;
16034dbad5dSOmar Sandoval }
16134dbad5dSOmar Sandoval 
1621a435111SOmar Sandoval #define HCTX_STATE_NAME(name) [BLK_MQ_S_##name] = #name
163f5c0b091SBart Van Assche static const char *const hctx_state_name[] = {
1641a435111SOmar Sandoval 	HCTX_STATE_NAME(STOPPED),
1651a435111SOmar Sandoval 	HCTX_STATE_NAME(TAG_ACTIVE),
1661a435111SOmar Sandoval 	HCTX_STATE_NAME(SCHED_RESTART),
1671a435111SOmar Sandoval 	HCTX_STATE_NAME(TAG_WAITING),
1681a435111SOmar Sandoval 	HCTX_STATE_NAME(START_ON_RUN),
169f5c0b091SBart Van Assche };
1701a435111SOmar Sandoval #undef HCTX_STATE_NAME
1711a435111SOmar Sandoval 
172f57de23aSOmar Sandoval static int hctx_state_show(void *data, struct seq_file *m)
1739abb2ad2SOmar Sandoval {
174f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
1759abb2ad2SOmar Sandoval 
176f5c0b091SBart Van Assche 	blk_flags_show(m, hctx->state, hctx_state_name,
177f5c0b091SBart Van Assche 		       ARRAY_SIZE(hctx_state_name));
178fd07dc81SBart Van Assche 	seq_puts(m, "\n");
1799abb2ad2SOmar Sandoval 	return 0;
1809abb2ad2SOmar Sandoval }
1819abb2ad2SOmar Sandoval 
1821a435111SOmar Sandoval #define BLK_TAG_ALLOC_NAME(name) [BLK_TAG_ALLOC_##name] = #name
183f5c0b091SBart Van Assche static const char *const alloc_policy_name[] = {
1841a435111SOmar Sandoval 	BLK_TAG_ALLOC_NAME(FIFO),
1851a435111SOmar Sandoval 	BLK_TAG_ALLOC_NAME(RR),
186f5c0b091SBart Van Assche };
1871a435111SOmar Sandoval #undef BLK_TAG_ALLOC_NAME
188f5c0b091SBart Van Assche 
1891a435111SOmar Sandoval #define HCTX_FLAG_NAME(name) [ilog2(BLK_MQ_F_##name)] = #name
190f5c0b091SBart Van Assche static const char *const hctx_flag_name[] = {
1911a435111SOmar Sandoval 	HCTX_FLAG_NAME(SHOULD_MERGE),
1921a435111SOmar Sandoval 	HCTX_FLAG_NAME(TAG_SHARED),
1931a435111SOmar Sandoval 	HCTX_FLAG_NAME(SG_MERGE),
1941a435111SOmar Sandoval 	HCTX_FLAG_NAME(BLOCKING),
1951a435111SOmar Sandoval 	HCTX_FLAG_NAME(NO_SCHED),
196f5c0b091SBart Van Assche };
1971a435111SOmar Sandoval #undef HCTX_FLAG_NAME
198f5c0b091SBart Van Assche 
199f57de23aSOmar Sandoval static int hctx_flags_show(void *data, struct seq_file *m)
2009abb2ad2SOmar Sandoval {
201f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
202f5c0b091SBart Van Assche 	const int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(hctx->flags);
2039abb2ad2SOmar Sandoval 
204f5c0b091SBart Van Assche 	seq_puts(m, "alloc_policy=");
205f5c0b091SBart Van Assche 	if (alloc_policy < ARRAY_SIZE(alloc_policy_name) &&
206f5c0b091SBart Van Assche 	    alloc_policy_name[alloc_policy])
207f5c0b091SBart Van Assche 		seq_puts(m, alloc_policy_name[alloc_policy]);
208f5c0b091SBart Van Assche 	else
209f5c0b091SBart Van Assche 		seq_printf(m, "%d", alloc_policy);
210f5c0b091SBart Van Assche 	seq_puts(m, " ");
211f5c0b091SBart Van Assche 	blk_flags_show(m,
212f5c0b091SBart Van Assche 		       hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy),
213f5c0b091SBart Van Assche 		       hctx_flag_name, ARRAY_SIZE(hctx_flag_name));
214fd07dc81SBart Van Assche 	seq_puts(m, "\n");
2159abb2ad2SOmar Sandoval 	return 0;
2169abb2ad2SOmar Sandoval }
2179abb2ad2SOmar Sandoval 
2181a435111SOmar Sandoval #define REQ_OP_NAME(name) [REQ_OP_##name] = #name
2198658dca8SBart Van Assche static const char *const op_name[] = {
2201a435111SOmar Sandoval 	REQ_OP_NAME(READ),
2211a435111SOmar Sandoval 	REQ_OP_NAME(WRITE),
2221a435111SOmar Sandoval 	REQ_OP_NAME(FLUSH),
2231a435111SOmar Sandoval 	REQ_OP_NAME(DISCARD),
2241a435111SOmar Sandoval 	REQ_OP_NAME(ZONE_REPORT),
2251a435111SOmar Sandoval 	REQ_OP_NAME(SECURE_ERASE),
2261a435111SOmar Sandoval 	REQ_OP_NAME(ZONE_RESET),
2271a435111SOmar Sandoval 	REQ_OP_NAME(WRITE_SAME),
2281a435111SOmar Sandoval 	REQ_OP_NAME(WRITE_ZEROES),
2291a435111SOmar Sandoval 	REQ_OP_NAME(SCSI_IN),
2301a435111SOmar Sandoval 	REQ_OP_NAME(SCSI_OUT),
2311a435111SOmar Sandoval 	REQ_OP_NAME(DRV_IN),
2321a435111SOmar Sandoval 	REQ_OP_NAME(DRV_OUT),
2338658dca8SBart Van Assche };
2341a435111SOmar Sandoval #undef REQ_OP_NAME
2358658dca8SBart Van Assche 
2361a435111SOmar Sandoval #define CMD_FLAG_NAME(name) [__REQ_##name] = #name
2378658dca8SBart Van Assche static const char *const cmd_flag_name[] = {
2381a435111SOmar Sandoval 	CMD_FLAG_NAME(FAILFAST_DEV),
2391a435111SOmar Sandoval 	CMD_FLAG_NAME(FAILFAST_TRANSPORT),
2401a435111SOmar Sandoval 	CMD_FLAG_NAME(FAILFAST_DRIVER),
2411a435111SOmar Sandoval 	CMD_FLAG_NAME(SYNC),
2421a435111SOmar Sandoval 	CMD_FLAG_NAME(META),
2431a435111SOmar Sandoval 	CMD_FLAG_NAME(PRIO),
2441a435111SOmar Sandoval 	CMD_FLAG_NAME(NOMERGE),
2451a435111SOmar Sandoval 	CMD_FLAG_NAME(IDLE),
2461a435111SOmar Sandoval 	CMD_FLAG_NAME(INTEGRITY),
2471a435111SOmar Sandoval 	CMD_FLAG_NAME(FUA),
2481a435111SOmar Sandoval 	CMD_FLAG_NAME(PREFLUSH),
2491a435111SOmar Sandoval 	CMD_FLAG_NAME(RAHEAD),
2501a435111SOmar Sandoval 	CMD_FLAG_NAME(BACKGROUND),
2511a435111SOmar Sandoval 	CMD_FLAG_NAME(NOUNMAP),
2528658dca8SBart Van Assche };
2531a435111SOmar Sandoval #undef CMD_FLAG_NAME
2548658dca8SBart Van Assche 
2551a435111SOmar Sandoval #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name
2568658dca8SBart Van Assche static const char *const rqf_name[] = {
2571a435111SOmar Sandoval 	RQF_NAME(SORTED),
2581a435111SOmar Sandoval 	RQF_NAME(STARTED),
2591a435111SOmar Sandoval 	RQF_NAME(QUEUED),
2601a435111SOmar Sandoval 	RQF_NAME(SOFTBARRIER),
2611a435111SOmar Sandoval 	RQF_NAME(FLUSH_SEQ),
2621a435111SOmar Sandoval 	RQF_NAME(MIXED_MERGE),
2631a435111SOmar Sandoval 	RQF_NAME(MQ_INFLIGHT),
2641a435111SOmar Sandoval 	RQF_NAME(DONTPREP),
2651a435111SOmar Sandoval 	RQF_NAME(PREEMPT),
2661a435111SOmar Sandoval 	RQF_NAME(COPY_USER),
2671a435111SOmar Sandoval 	RQF_NAME(FAILED),
2681a435111SOmar Sandoval 	RQF_NAME(QUIET),
2691a435111SOmar Sandoval 	RQF_NAME(ELVPRIV),
2701a435111SOmar Sandoval 	RQF_NAME(IO_STAT),
2711a435111SOmar Sandoval 	RQF_NAME(ALLOCED),
2721a435111SOmar Sandoval 	RQF_NAME(PM),
2731a435111SOmar Sandoval 	RQF_NAME(HASHED),
2741a435111SOmar Sandoval 	RQF_NAME(STATS),
2751a435111SOmar Sandoval 	RQF_NAME(SPECIAL_PAYLOAD),
2768658dca8SBart Van Assche };
2771a435111SOmar Sandoval #undef RQF_NAME
2788658dca8SBart Van Assche 
279950cd7e9SOmar Sandoval static int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
280950cd7e9SOmar Sandoval {
281950cd7e9SOmar Sandoval 	struct request *rq = list_entry_rq(v);
2822836ee4bSBart Van Assche 	const struct blk_mq_ops *const mq_ops = rq->q->mq_ops;
2838658dca8SBart Van Assche 	const unsigned int op = rq->cmd_flags & REQ_OP_MASK;
284950cd7e9SOmar Sandoval 
2858658dca8SBart Van Assche 	seq_printf(m, "%p {.op=", rq);
2868658dca8SBart Van Assche 	if (op < ARRAY_SIZE(op_name) && op_name[op])
2878658dca8SBart Van Assche 		seq_printf(m, "%s", op_name[op]);
2888658dca8SBart Van Assche 	else
2898658dca8SBart Van Assche 		seq_printf(m, "%d", op);
2908658dca8SBart Van Assche 	seq_puts(m, ", .cmd_flags=");
2918658dca8SBart Van Assche 	blk_flags_show(m, rq->cmd_flags & ~REQ_OP_MASK, cmd_flag_name,
2928658dca8SBart Van Assche 		       ARRAY_SIZE(cmd_flag_name));
2938658dca8SBart Van Assche 	seq_puts(m, ", .rq_flags=");
2948658dca8SBart Van Assche 	blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name,
2958658dca8SBart Van Assche 		       ARRAY_SIZE(rqf_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 }
303950cd7e9SOmar Sandoval 
304950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos)
305f3bcb0e6SBart Van Assche 	__acquires(&hctx->lock)
306950cd7e9SOmar Sandoval {
307950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
308950cd7e9SOmar Sandoval 
309950cd7e9SOmar Sandoval 	spin_lock(&hctx->lock);
310950cd7e9SOmar Sandoval 	return seq_list_start(&hctx->dispatch, *pos);
311950cd7e9SOmar Sandoval }
312950cd7e9SOmar Sandoval 
313950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos)
314950cd7e9SOmar Sandoval {
315950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
316950cd7e9SOmar Sandoval 
317950cd7e9SOmar Sandoval 	return seq_list_next(v, &hctx->dispatch, pos);
318950cd7e9SOmar Sandoval }
319950cd7e9SOmar Sandoval 
320950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v)
321f3bcb0e6SBart Van Assche 	__releases(&hctx->lock)
322950cd7e9SOmar Sandoval {
323950cd7e9SOmar Sandoval 	struct blk_mq_hw_ctx *hctx = m->private;
324950cd7e9SOmar Sandoval 
325950cd7e9SOmar Sandoval 	spin_unlock(&hctx->lock);
326950cd7e9SOmar Sandoval }
327950cd7e9SOmar Sandoval 
328950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = {
329950cd7e9SOmar Sandoval 	.start	= hctx_dispatch_start,
330950cd7e9SOmar Sandoval 	.next	= hctx_dispatch_next,
331950cd7e9SOmar Sandoval 	.stop	= hctx_dispatch_stop,
332950cd7e9SOmar Sandoval 	.show	= blk_mq_debugfs_rq_show,
333950cd7e9SOmar Sandoval };
334950cd7e9SOmar Sandoval 
335f57de23aSOmar Sandoval static int hctx_ctx_map_show(void *data, struct seq_file *m)
336950cd7e9SOmar Sandoval {
337f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
3380bfa5288SOmar Sandoval 
3390bfa5288SOmar Sandoval 	sbitmap_bitmap_show(&hctx->ctx_map, m);
3400bfa5288SOmar Sandoval 	return 0;
3410bfa5288SOmar Sandoval }
3420bfa5288SOmar Sandoval 
343d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m,
344d96b37c0SOmar Sandoval 				     struct blk_mq_tags *tags)
345d96b37c0SOmar Sandoval {
346d96b37c0SOmar Sandoval 	seq_printf(m, "nr_tags=%u\n", tags->nr_tags);
347d96b37c0SOmar Sandoval 	seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags);
348d96b37c0SOmar Sandoval 	seq_printf(m, "active_queues=%d\n",
349d96b37c0SOmar Sandoval 		   atomic_read(&tags->active_queues));
350d96b37c0SOmar Sandoval 
351d96b37c0SOmar Sandoval 	seq_puts(m, "\nbitmap_tags:\n");
352d96b37c0SOmar Sandoval 	sbitmap_queue_show(&tags->bitmap_tags, m);
353d96b37c0SOmar Sandoval 
354d96b37c0SOmar Sandoval 	if (tags->nr_reserved_tags) {
355d96b37c0SOmar Sandoval 		seq_puts(m, "\nbreserved_tags:\n");
356d96b37c0SOmar Sandoval 		sbitmap_queue_show(&tags->breserved_tags, m);
357d96b37c0SOmar Sandoval 	}
358d96b37c0SOmar Sandoval }
359d96b37c0SOmar Sandoval 
360f57de23aSOmar Sandoval static int hctx_tags_show(void *data, struct seq_file *m)
361d96b37c0SOmar Sandoval {
362f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
363d96b37c0SOmar Sandoval 	struct request_queue *q = hctx->queue;
3648c0f14eaSBart Van Assche 	int res;
365d96b37c0SOmar Sandoval 
3668c0f14eaSBart Van Assche 	res = mutex_lock_interruptible(&q->sysfs_lock);
3678c0f14eaSBart Van Assche 	if (res)
3688c0f14eaSBart Van Assche 		goto out;
369d96b37c0SOmar Sandoval 	if (hctx->tags)
370d96b37c0SOmar Sandoval 		blk_mq_debugfs_tags_show(m, hctx->tags);
371d96b37c0SOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
372d96b37c0SOmar Sandoval 
3738c0f14eaSBart Van Assche out:
3748c0f14eaSBart Van Assche 	return res;
375d96b37c0SOmar Sandoval }
376d96b37c0SOmar Sandoval 
377f57de23aSOmar Sandoval static int hctx_tags_bitmap_show(void *data, struct seq_file *m)
378d96b37c0SOmar Sandoval {
379f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
380d7e3621aSOmar Sandoval 	struct request_queue *q = hctx->queue;
3818c0f14eaSBart Van Assche 	int res;
382d7e3621aSOmar Sandoval 
3838c0f14eaSBart Van Assche 	res = mutex_lock_interruptible(&q->sysfs_lock);
3848c0f14eaSBart Van Assche 	if (res)
3858c0f14eaSBart Van Assche 		goto out;
386d7e3621aSOmar Sandoval 	if (hctx->tags)
387d7e3621aSOmar Sandoval 		sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m);
388d7e3621aSOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
3898c0f14eaSBart Van Assche 
3908c0f14eaSBart Van Assche out:
3918c0f14eaSBart Van Assche 	return res;
392d7e3621aSOmar Sandoval }
393d7e3621aSOmar Sandoval 
394f57de23aSOmar Sandoval static int hctx_sched_tags_show(void *data, struct seq_file *m)
395d7e3621aSOmar Sandoval {
396f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
397d96b37c0SOmar Sandoval 	struct request_queue *q = hctx->queue;
3988c0f14eaSBart Van Assche 	int res;
399d96b37c0SOmar Sandoval 
4008c0f14eaSBart Van Assche 	res = mutex_lock_interruptible(&q->sysfs_lock);
4018c0f14eaSBart Van Assche 	if (res)
4028c0f14eaSBart Van Assche 		goto out;
403d96b37c0SOmar Sandoval 	if (hctx->sched_tags)
404d96b37c0SOmar Sandoval 		blk_mq_debugfs_tags_show(m, hctx->sched_tags);
405d96b37c0SOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
406d96b37c0SOmar Sandoval 
4078c0f14eaSBart Van Assche out:
4088c0f14eaSBart Van Assche 	return res;
409d96b37c0SOmar Sandoval }
410d96b37c0SOmar Sandoval 
411f57de23aSOmar Sandoval static int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m)
412d96b37c0SOmar Sandoval {
413f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
414d7e3621aSOmar Sandoval 	struct request_queue *q = hctx->queue;
4158c0f14eaSBart Van Assche 	int res;
416d7e3621aSOmar Sandoval 
4178c0f14eaSBart Van Assche 	res = mutex_lock_interruptible(&q->sysfs_lock);
4188c0f14eaSBart Van Assche 	if (res)
4198c0f14eaSBart Van Assche 		goto out;
420d7e3621aSOmar Sandoval 	if (hctx->sched_tags)
421d7e3621aSOmar Sandoval 		sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m);
422d7e3621aSOmar Sandoval 	mutex_unlock(&q->sysfs_lock);
4238c0f14eaSBart Van Assche 
4248c0f14eaSBart Van Assche out:
4258c0f14eaSBart Van Assche 	return res;
426d7e3621aSOmar Sandoval }
427d7e3621aSOmar Sandoval 
428f57de23aSOmar Sandoval static int hctx_io_poll_show(void *data, struct seq_file *m)
429d7e3621aSOmar Sandoval {
430f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
431be215473SOmar Sandoval 
432be215473SOmar Sandoval 	seq_printf(m, "considered=%lu\n", hctx->poll_considered);
433be215473SOmar Sandoval 	seq_printf(m, "invoked=%lu\n", hctx->poll_invoked);
434be215473SOmar Sandoval 	seq_printf(m, "success=%lu\n", hctx->poll_success);
435be215473SOmar Sandoval 	return 0;
436be215473SOmar Sandoval }
437be215473SOmar Sandoval 
438f57de23aSOmar Sandoval static ssize_t hctx_io_poll_write(void *data, const char __user *buf,
439be215473SOmar Sandoval 				  size_t count, loff_t *ppos)
440be215473SOmar Sandoval {
441f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
442be215473SOmar Sandoval 
443be215473SOmar Sandoval 	hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0;
444be215473SOmar Sandoval 	return count;
445be215473SOmar Sandoval }
446be215473SOmar Sandoval 
447f57de23aSOmar Sandoval static int hctx_dispatched_show(void *data, struct seq_file *m)
448be215473SOmar Sandoval {
449f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
450be215473SOmar Sandoval 	int i;
451be215473SOmar Sandoval 
452be215473SOmar Sandoval 	seq_printf(m, "%8u\t%lu\n", 0U, hctx->dispatched[0]);
453be215473SOmar Sandoval 
454be215473SOmar Sandoval 	for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) {
455be215473SOmar Sandoval 		unsigned int d = 1U << (i - 1);
456be215473SOmar Sandoval 
457be215473SOmar Sandoval 		seq_printf(m, "%8u\t%lu\n", d, hctx->dispatched[i]);
458be215473SOmar Sandoval 	}
459be215473SOmar Sandoval 
460be215473SOmar Sandoval 	seq_printf(m, "%8u+\t%lu\n", 1U << (i - 1), hctx->dispatched[i]);
461be215473SOmar Sandoval 	return 0;
462be215473SOmar Sandoval }
463be215473SOmar Sandoval 
464f57de23aSOmar Sandoval static ssize_t hctx_dispatched_write(void *data, const char __user *buf,
465be215473SOmar Sandoval 				     size_t count, loff_t *ppos)
466be215473SOmar Sandoval {
467f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
468be215473SOmar Sandoval 	int i;
469be215473SOmar Sandoval 
470be215473SOmar Sandoval 	for (i = 0; i < BLK_MQ_MAX_DISPATCH_ORDER; i++)
471be215473SOmar Sandoval 		hctx->dispatched[i] = 0;
472be215473SOmar Sandoval 	return count;
473be215473SOmar Sandoval }
474be215473SOmar Sandoval 
475f57de23aSOmar Sandoval static int hctx_queued_show(void *data, struct seq_file *m)
4764a46f05eSOmar Sandoval {
477f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
4784a46f05eSOmar Sandoval 
4794a46f05eSOmar Sandoval 	seq_printf(m, "%lu\n", hctx->queued);
4804a46f05eSOmar Sandoval 	return 0;
4814a46f05eSOmar Sandoval }
4824a46f05eSOmar Sandoval 
483f57de23aSOmar Sandoval static ssize_t hctx_queued_write(void *data, const char __user *buf,
4844a46f05eSOmar Sandoval 				 size_t count, loff_t *ppos)
4854a46f05eSOmar Sandoval {
486f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
4874a46f05eSOmar Sandoval 
4884a46f05eSOmar Sandoval 	hctx->queued = 0;
4894a46f05eSOmar Sandoval 	return count;
4904a46f05eSOmar Sandoval }
4914a46f05eSOmar Sandoval 
492f57de23aSOmar Sandoval static int hctx_run_show(void *data, struct seq_file *m)
4934a46f05eSOmar Sandoval {
494f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
4954a46f05eSOmar Sandoval 
4964a46f05eSOmar Sandoval 	seq_printf(m, "%lu\n", hctx->run);
4974a46f05eSOmar Sandoval 	return 0;
4984a46f05eSOmar Sandoval }
4994a46f05eSOmar Sandoval 
500f57de23aSOmar Sandoval static ssize_t hctx_run_write(void *data, const char __user *buf, size_t count,
501f57de23aSOmar Sandoval 			      loff_t *ppos)
5024a46f05eSOmar Sandoval {
503f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
5044a46f05eSOmar Sandoval 
5054a46f05eSOmar Sandoval 	hctx->run = 0;
5064a46f05eSOmar Sandoval 	return count;
5074a46f05eSOmar Sandoval }
5084a46f05eSOmar Sandoval 
509f57de23aSOmar Sandoval static int hctx_active_show(void *data, struct seq_file *m)
5104a46f05eSOmar Sandoval {
511f57de23aSOmar Sandoval 	struct blk_mq_hw_ctx *hctx = data;
5124a46f05eSOmar Sandoval 
5134a46f05eSOmar Sandoval 	seq_printf(m, "%d\n", atomic_read(&hctx->nr_active));
5144a46f05eSOmar Sandoval 	return 0;
5154a46f05eSOmar Sandoval }
5164a46f05eSOmar Sandoval 
517950cd7e9SOmar Sandoval static void *ctx_rq_list_start(struct seq_file *m, loff_t *pos)
518f3bcb0e6SBart Van Assche 	__acquires(&ctx->lock)
519950cd7e9SOmar Sandoval {
520950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
521950cd7e9SOmar Sandoval 
522950cd7e9SOmar Sandoval 	spin_lock(&ctx->lock);
523950cd7e9SOmar Sandoval 	return seq_list_start(&ctx->rq_list, *pos);
524950cd7e9SOmar Sandoval }
525950cd7e9SOmar Sandoval 
526950cd7e9SOmar Sandoval static void *ctx_rq_list_next(struct seq_file *m, void *v, loff_t *pos)
527950cd7e9SOmar Sandoval {
528950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
529950cd7e9SOmar Sandoval 
530950cd7e9SOmar Sandoval 	return seq_list_next(v, &ctx->rq_list, pos);
531950cd7e9SOmar Sandoval }
532950cd7e9SOmar Sandoval 
533950cd7e9SOmar Sandoval static void ctx_rq_list_stop(struct seq_file *m, void *v)
534f3bcb0e6SBart Van Assche 	__releases(&ctx->lock)
535950cd7e9SOmar Sandoval {
536950cd7e9SOmar Sandoval 	struct blk_mq_ctx *ctx = m->private;
537950cd7e9SOmar Sandoval 
538950cd7e9SOmar Sandoval 	spin_unlock(&ctx->lock);
539950cd7e9SOmar Sandoval }
540950cd7e9SOmar Sandoval 
541950cd7e9SOmar Sandoval static const struct seq_operations ctx_rq_list_seq_ops = {
542950cd7e9SOmar Sandoval 	.start	= ctx_rq_list_start,
543950cd7e9SOmar Sandoval 	.next	= ctx_rq_list_next,
544950cd7e9SOmar Sandoval 	.stop	= ctx_rq_list_stop,
545950cd7e9SOmar Sandoval 	.show	= blk_mq_debugfs_rq_show,
546950cd7e9SOmar Sandoval };
547f57de23aSOmar Sandoval static int ctx_dispatched_show(void *data, struct seq_file *m)
548950cd7e9SOmar Sandoval {
549f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5504a46f05eSOmar Sandoval 
5514a46f05eSOmar Sandoval 	seq_printf(m, "%lu %lu\n", ctx->rq_dispatched[1], ctx->rq_dispatched[0]);
5524a46f05eSOmar Sandoval 	return 0;
5534a46f05eSOmar Sandoval }
5544a46f05eSOmar Sandoval 
555f57de23aSOmar Sandoval static ssize_t ctx_dispatched_write(void *data, const char __user *buf,
5564a46f05eSOmar Sandoval 				    size_t count, loff_t *ppos)
5574a46f05eSOmar Sandoval {
558f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5594a46f05eSOmar Sandoval 
5604a46f05eSOmar Sandoval 	ctx->rq_dispatched[0] = ctx->rq_dispatched[1] = 0;
5614a46f05eSOmar Sandoval 	return count;
5624a46f05eSOmar Sandoval }
5634a46f05eSOmar Sandoval 
564f57de23aSOmar Sandoval static int ctx_merged_show(void *data, struct seq_file *m)
5654a46f05eSOmar Sandoval {
566f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5674a46f05eSOmar Sandoval 
5684a46f05eSOmar Sandoval 	seq_printf(m, "%lu\n", ctx->rq_merged);
5694a46f05eSOmar Sandoval 	return 0;
5704a46f05eSOmar Sandoval }
5714a46f05eSOmar Sandoval 
572f57de23aSOmar Sandoval static ssize_t ctx_merged_write(void *data, const char __user *buf,
5734a46f05eSOmar Sandoval 				size_t count, loff_t *ppos)
5744a46f05eSOmar Sandoval {
575f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5764a46f05eSOmar Sandoval 
5774a46f05eSOmar Sandoval 	ctx->rq_merged = 0;
5784a46f05eSOmar Sandoval 	return count;
5794a46f05eSOmar Sandoval }
5804a46f05eSOmar Sandoval 
581f57de23aSOmar Sandoval static int ctx_completed_show(void *data, struct seq_file *m)
5824a46f05eSOmar Sandoval {
583f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5844a46f05eSOmar Sandoval 
5854a46f05eSOmar Sandoval 	seq_printf(m, "%lu %lu\n", ctx->rq_completed[1], ctx->rq_completed[0]);
5864a46f05eSOmar Sandoval 	return 0;
5874a46f05eSOmar Sandoval }
5884a46f05eSOmar Sandoval 
589f57de23aSOmar Sandoval static ssize_t ctx_completed_write(void *data, const char __user *buf,
5904a46f05eSOmar Sandoval 				   size_t count, loff_t *ppos)
5914a46f05eSOmar Sandoval {
592f57de23aSOmar Sandoval 	struct blk_mq_ctx *ctx = data;
5934a46f05eSOmar Sandoval 
5944a46f05eSOmar Sandoval 	ctx->rq_completed[0] = ctx->rq_completed[1] = 0;
5954a46f05eSOmar Sandoval 	return count;
5964a46f05eSOmar Sandoval }
5974a46f05eSOmar Sandoval 
598f57de23aSOmar Sandoval static int blk_mq_debugfs_show(struct seq_file *m, void *v)
599f57de23aSOmar Sandoval {
600f57de23aSOmar Sandoval 	const struct blk_mq_debugfs_attr *attr = m->private;
601f57de23aSOmar Sandoval 	void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private;
602f57de23aSOmar Sandoval 
603f57de23aSOmar Sandoval 	return attr->show(data, m);
604f57de23aSOmar Sandoval }
605f57de23aSOmar Sandoval 
606f57de23aSOmar Sandoval static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf,
607f57de23aSOmar Sandoval 				    size_t count, loff_t *ppos)
608f57de23aSOmar Sandoval {
609f57de23aSOmar Sandoval 	struct seq_file *m = file->private_data;
610f57de23aSOmar Sandoval 	const struct blk_mq_debugfs_attr *attr = m->private;
611f57de23aSOmar Sandoval 	void *data = d_inode(file->f_path.dentry->d_parent)->i_private;
612f57de23aSOmar Sandoval 
613f57de23aSOmar Sandoval 	if (!attr->write)
614f57de23aSOmar Sandoval 		return -EPERM;
615f57de23aSOmar Sandoval 
616f57de23aSOmar Sandoval 	return attr->write(data, buf, count, ppos);
617f57de23aSOmar Sandoval }
618f57de23aSOmar Sandoval 
619f57de23aSOmar Sandoval static int blk_mq_debugfs_open(struct inode *inode, struct file *file)
620f57de23aSOmar Sandoval {
621f57de23aSOmar Sandoval 	const struct blk_mq_debugfs_attr *attr = inode->i_private;
622f57de23aSOmar Sandoval 	void *data = d_inode(file->f_path.dentry->d_parent)->i_private;
623f57de23aSOmar Sandoval 	struct seq_file *m;
624f57de23aSOmar Sandoval 	int ret;
625f57de23aSOmar Sandoval 
626f57de23aSOmar Sandoval 	if (attr->seq_ops) {
627f57de23aSOmar Sandoval 		ret = seq_open(file, attr->seq_ops);
628f57de23aSOmar Sandoval 		if (!ret) {
629f57de23aSOmar Sandoval 			m = file->private_data;
630f57de23aSOmar Sandoval 			m->private = data;
631f57de23aSOmar Sandoval 		}
632f57de23aSOmar Sandoval 		return ret;
633f57de23aSOmar Sandoval 	}
634f57de23aSOmar Sandoval 
635f57de23aSOmar Sandoval 	if (WARN_ON_ONCE(!attr->show))
636f57de23aSOmar Sandoval 		return -EPERM;
637f57de23aSOmar Sandoval 
638f57de23aSOmar Sandoval 	return single_open(file, blk_mq_debugfs_show, inode->i_private);
639f57de23aSOmar Sandoval }
640f57de23aSOmar Sandoval 
641f57de23aSOmar Sandoval static int blk_mq_debugfs_release(struct inode *inode, struct file *file)
642f57de23aSOmar Sandoval {
643f57de23aSOmar Sandoval 	const struct blk_mq_debugfs_attr *attr = inode->i_private;
644f57de23aSOmar Sandoval 
645f57de23aSOmar Sandoval 	if (attr->show)
646f57de23aSOmar Sandoval 		return single_release(inode, file);
647f57de23aSOmar Sandoval 	else
648f57de23aSOmar Sandoval 		return seq_release(inode, file);
649f57de23aSOmar Sandoval }
650f57de23aSOmar Sandoval 
651f57de23aSOmar Sandoval const struct file_operations blk_mq_debugfs_fops = {
652f57de23aSOmar Sandoval 	.open		= blk_mq_debugfs_open,
6534a46f05eSOmar Sandoval 	.read		= seq_read,
654f57de23aSOmar Sandoval 	.write		= blk_mq_debugfs_write,
6554a46f05eSOmar Sandoval 	.llseek		= seq_lseek,
656f57de23aSOmar Sandoval 	.release	= blk_mq_debugfs_release,
6574a46f05eSOmar Sandoval };
6584a46f05eSOmar Sandoval 
65934dbad5dSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = {
660f57de23aSOmar Sandoval 	{"poll_stat", 0400, queue_poll_stat_show},
661f57de23aSOmar Sandoval 	{"state", 0600, queue_state_show, queue_state_write},
66234dbad5dSOmar Sandoval 	{},
66334dbad5dSOmar Sandoval };
66434dbad5dSOmar Sandoval 
66507e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = {
666f57de23aSOmar Sandoval 	{"state", 0400, hctx_state_show},
667f57de23aSOmar Sandoval 	{"flags", 0400, hctx_flags_show},
668f57de23aSOmar Sandoval 	{"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops},
669f57de23aSOmar Sandoval 	{"ctx_map", 0400, hctx_ctx_map_show},
670f57de23aSOmar Sandoval 	{"tags", 0400, hctx_tags_show},
671f57de23aSOmar Sandoval 	{"tags_bitmap", 0400, hctx_tags_bitmap_show},
672f57de23aSOmar Sandoval 	{"sched_tags", 0400, hctx_sched_tags_show},
673f57de23aSOmar Sandoval 	{"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show},
674f57de23aSOmar Sandoval 	{"io_poll", 0600, hctx_io_poll_show, hctx_io_poll_write},
675f57de23aSOmar Sandoval 	{"dispatched", 0600, hctx_dispatched_show, hctx_dispatched_write},
676f57de23aSOmar Sandoval 	{"queued", 0600, hctx_queued_show, hctx_queued_write},
677f57de23aSOmar Sandoval 	{"run", 0600, hctx_run_show, hctx_run_write},
678f57de23aSOmar Sandoval 	{"active", 0400, hctx_active_show},
67972f2f8f6SBart Van Assche 	{},
68007e4feadSOmar Sandoval };
68107e4feadSOmar Sandoval 
68207e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = {
683f57de23aSOmar Sandoval 	{"rq_list", 0400, .seq_ops = &ctx_rq_list_seq_ops},
684f57de23aSOmar Sandoval 	{"dispatched", 0600, ctx_dispatched_show, ctx_dispatched_write},
685f57de23aSOmar Sandoval 	{"merged", 0600, ctx_merged_show, ctx_merged_write},
686f57de23aSOmar Sandoval 	{"completed", 0600, ctx_completed_show, ctx_completed_write},
68772f2f8f6SBart Van Assche 	{},
68807e4feadSOmar Sandoval };
68907e4feadSOmar Sandoval 
6904c9e4019SBart Van Assche int blk_mq_debugfs_register(struct request_queue *q)
69107e4feadSOmar Sandoval {
69218fbda91SOmar Sandoval 	if (!blk_debugfs_root)
69307e4feadSOmar Sandoval 		return -ENOENT;
69407e4feadSOmar Sandoval 
6954c9e4019SBart Van Assche 	q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent),
6964c9e4019SBart Van Assche 					    blk_debugfs_root);
69707e4feadSOmar Sandoval 	if (!q->debugfs_dir)
69807e4feadSOmar Sandoval 		goto err;
69907e4feadSOmar Sandoval 
70062d6c949SBart Van Assche 	if (blk_mq_debugfs_register_mq(q))
70107e4feadSOmar Sandoval 		goto err;
70207e4feadSOmar Sandoval 
70307e4feadSOmar Sandoval 	return 0;
70407e4feadSOmar Sandoval 
70507e4feadSOmar Sandoval err:
70607e4feadSOmar Sandoval 	blk_mq_debugfs_unregister(q);
70707e4feadSOmar Sandoval 	return -ENOMEM;
70807e4feadSOmar Sandoval }
70907e4feadSOmar Sandoval 
71007e4feadSOmar Sandoval void blk_mq_debugfs_unregister(struct request_queue *q)
71107e4feadSOmar Sandoval {
71207e4feadSOmar Sandoval 	debugfs_remove_recursive(q->debugfs_dir);
71307e4feadSOmar Sandoval 	q->mq_debugfs_dir = NULL;
71407e4feadSOmar Sandoval 	q->debugfs_dir = NULL;
71507e4feadSOmar Sandoval }
71607e4feadSOmar Sandoval 
71772f2f8f6SBart Van Assche static bool debugfs_create_files(struct dentry *parent, void *data,
71872f2f8f6SBart Van Assche 				 const struct blk_mq_debugfs_attr *attr)
71972f2f8f6SBart Van Assche {
720f57de23aSOmar Sandoval 	d_inode(parent)->i_private = data;
721f57de23aSOmar Sandoval 
72272f2f8f6SBart Van Assche 	for (; attr->name; attr++) {
72372f2f8f6SBart Van Assche 		if (!debugfs_create_file(attr->name, attr->mode, parent,
724f57de23aSOmar Sandoval 					 (void *)attr, &blk_mq_debugfs_fops))
72572f2f8f6SBart Van Assche 			return false;
72672f2f8f6SBart Van Assche 	}
72772f2f8f6SBart Van Assche 	return true;
72872f2f8f6SBart Van Assche }
72972f2f8f6SBart Van Assche 
73007e4feadSOmar Sandoval static int blk_mq_debugfs_register_ctx(struct request_queue *q,
73107e4feadSOmar Sandoval 				       struct blk_mq_ctx *ctx,
73207e4feadSOmar Sandoval 				       struct dentry *hctx_dir)
73307e4feadSOmar Sandoval {
73407e4feadSOmar Sandoval 	struct dentry *ctx_dir;
73507e4feadSOmar Sandoval 	char name[20];
73607e4feadSOmar Sandoval 
73707e4feadSOmar Sandoval 	snprintf(name, sizeof(name), "cpu%u", ctx->cpu);
73807e4feadSOmar Sandoval 	ctx_dir = debugfs_create_dir(name, hctx_dir);
73907e4feadSOmar Sandoval 	if (!ctx_dir)
74007e4feadSOmar Sandoval 		return -ENOMEM;
74107e4feadSOmar Sandoval 
74272f2f8f6SBart Van Assche 	if (!debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs))
74307e4feadSOmar Sandoval 		return -ENOMEM;
74407e4feadSOmar Sandoval 
74507e4feadSOmar Sandoval 	return 0;
74607e4feadSOmar Sandoval }
74707e4feadSOmar Sandoval 
74807e4feadSOmar Sandoval static int blk_mq_debugfs_register_hctx(struct request_queue *q,
74907e4feadSOmar Sandoval 					struct blk_mq_hw_ctx *hctx)
75007e4feadSOmar Sandoval {
75107e4feadSOmar Sandoval 	struct blk_mq_ctx *ctx;
75207e4feadSOmar Sandoval 	struct dentry *hctx_dir;
75307e4feadSOmar Sandoval 	char name[20];
75407e4feadSOmar Sandoval 	int i;
75507e4feadSOmar Sandoval 
75688aabbd7SOmar Sandoval 	snprintf(name, sizeof(name), "hctx%u", hctx->queue_num);
75707e4feadSOmar Sandoval 	hctx_dir = debugfs_create_dir(name, q->mq_debugfs_dir);
75807e4feadSOmar Sandoval 	if (!hctx_dir)
75907e4feadSOmar Sandoval 		return -ENOMEM;
76007e4feadSOmar Sandoval 
76172f2f8f6SBart Van Assche 	if (!debugfs_create_files(hctx_dir, hctx, blk_mq_debugfs_hctx_attrs))
76207e4feadSOmar Sandoval 		return -ENOMEM;
76307e4feadSOmar Sandoval 
76407e4feadSOmar Sandoval 	hctx_for_each_ctx(hctx, ctx, i) {
76507e4feadSOmar Sandoval 		if (blk_mq_debugfs_register_ctx(q, ctx, hctx_dir))
76607e4feadSOmar Sandoval 			return -ENOMEM;
76707e4feadSOmar Sandoval 	}
76807e4feadSOmar Sandoval 
76907e4feadSOmar Sandoval 	return 0;
77007e4feadSOmar Sandoval }
77107e4feadSOmar Sandoval 
77262d6c949SBart Van Assche int blk_mq_debugfs_register_mq(struct request_queue *q)
77307e4feadSOmar Sandoval {
77407e4feadSOmar Sandoval 	struct blk_mq_hw_ctx *hctx;
77507e4feadSOmar Sandoval 	int i;
77607e4feadSOmar Sandoval 
77707e4feadSOmar Sandoval 	if (!q->debugfs_dir)
77807e4feadSOmar Sandoval 		return -ENOENT;
77907e4feadSOmar Sandoval 
78007e4feadSOmar Sandoval 	q->mq_debugfs_dir = debugfs_create_dir("mq", q->debugfs_dir);
78107e4feadSOmar Sandoval 	if (!q->mq_debugfs_dir)
78207e4feadSOmar Sandoval 		goto err;
78307e4feadSOmar Sandoval 
78434dbad5dSOmar Sandoval 	if (!debugfs_create_files(q->mq_debugfs_dir, q, blk_mq_debugfs_queue_attrs))
78534dbad5dSOmar Sandoval 		goto err;
78634dbad5dSOmar Sandoval 
78707e4feadSOmar Sandoval 	queue_for_each_hw_ctx(q, hctx, i) {
78807e4feadSOmar Sandoval 		if (blk_mq_debugfs_register_hctx(q, hctx))
78907e4feadSOmar Sandoval 			goto err;
79007e4feadSOmar Sandoval 	}
79107e4feadSOmar Sandoval 
79207e4feadSOmar Sandoval 	return 0;
79307e4feadSOmar Sandoval 
79407e4feadSOmar Sandoval err:
79562d6c949SBart Van Assche 	blk_mq_debugfs_unregister_mq(q);
79607e4feadSOmar Sandoval 	return -ENOMEM;
79707e4feadSOmar Sandoval }
79807e4feadSOmar Sandoval 
79962d6c949SBart Van Assche void blk_mq_debugfs_unregister_mq(struct request_queue *q)
80007e4feadSOmar Sandoval {
80107e4feadSOmar Sandoval 	debugfs_remove_recursive(q->mq_debugfs_dir);
80207e4feadSOmar Sandoval 	q->mq_debugfs_dir = NULL;
80307e4feadSOmar Sandoval }
804