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