18c16567dSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0 207e4feadSOmar Sandoval /* 307e4feadSOmar Sandoval * Copyright (C) 2017 Facebook 407e4feadSOmar Sandoval */ 507e4feadSOmar Sandoval 607e4feadSOmar Sandoval #include <linux/kernel.h> 707e4feadSOmar Sandoval #include <linux/blkdev.h> 807e4feadSOmar Sandoval #include <linux/debugfs.h> 907e4feadSOmar Sandoval 1018fbda91SOmar Sandoval #include "blk.h" 1107e4feadSOmar Sandoval #include "blk-mq.h" 12d173a251SOmar Sandoval #include "blk-mq-debugfs.h" 132aa7745bSChristoph Hellwig #include "blk-mq-sched.h" 14cc56694fSMing Lei #include "blk-rq-qos.h" 1507e4feadSOmar Sandoval 161209cb7fSBart Van Assche static int queue_poll_stat_show(void *data, struct seq_file *m) 171209cb7fSBart Van Assche { 181209cb7fSBart Van Assche return 0; 191209cb7fSBart Van Assche } 201209cb7fSBart Van Assche 211209cb7fSBart Van Assche static void *queue_requeue_list_start(struct seq_file *m, loff_t *pos) 221209cb7fSBart Van Assche __acquires(&q->requeue_lock) 231209cb7fSBart Van Assche { 241209cb7fSBart Van Assche struct request_queue *q = m->private; 251209cb7fSBart Van Assche 261209cb7fSBart Van Assche spin_lock_irq(&q->requeue_lock); 271209cb7fSBart Van Assche return seq_list_start(&q->requeue_list, *pos); 281209cb7fSBart Van Assche } 291209cb7fSBart Van Assche 301209cb7fSBart Van Assche static void *queue_requeue_list_next(struct seq_file *m, void *v, loff_t *pos) 311209cb7fSBart Van Assche { 321209cb7fSBart Van Assche struct request_queue *q = m->private; 331209cb7fSBart Van Assche 341209cb7fSBart Van Assche return seq_list_next(v, &q->requeue_list, pos); 351209cb7fSBart Van Assche } 361209cb7fSBart Van Assche 371209cb7fSBart Van Assche static void queue_requeue_list_stop(struct seq_file *m, void *v) 381209cb7fSBart Van Assche __releases(&q->requeue_lock) 391209cb7fSBart Van Assche { 401209cb7fSBart Van Assche struct request_queue *q = m->private; 411209cb7fSBart Van Assche 421209cb7fSBart Van Assche spin_unlock_irq(&q->requeue_lock); 431209cb7fSBart Van Assche } 441209cb7fSBart Van Assche 451209cb7fSBart Van Assche static const struct seq_operations queue_requeue_list_seq_ops = { 461209cb7fSBart Van Assche .start = queue_requeue_list_start, 471209cb7fSBart Van Assche .next = queue_requeue_list_next, 481209cb7fSBart Van Assche .stop = queue_requeue_list_stop, 491209cb7fSBart Van Assche .show = blk_mq_debugfs_rq_show, 501209cb7fSBart Van Assche }; 511209cb7fSBart Van Assche 5291d68905SBart Van Assche static int blk_flags_show(struct seq_file *m, const unsigned long flags, 5391d68905SBart Van Assche const char *const *flag_name, int flag_name_count) 5491d68905SBart Van Assche { 5591d68905SBart Van Assche bool sep = false; 5691d68905SBart Van Assche int i; 5791d68905SBart Van Assche 5891d68905SBart Van Assche for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) { 5991d68905SBart Van Assche if (!(flags & BIT(i))) 6091d68905SBart Van Assche continue; 6191d68905SBart Van Assche if (sep) 62bec03d6bSOmar Sandoval seq_puts(m, "|"); 6391d68905SBart Van Assche sep = true; 6491d68905SBart Van Assche if (i < flag_name_count && flag_name[i]) 6591d68905SBart Van Assche seq_puts(m, flag_name[i]); 6691d68905SBart Van Assche else 6791d68905SBart Van Assche seq_printf(m, "%d", i); 6891d68905SBart Van Assche } 6991d68905SBart Van Assche return 0; 7091d68905SBart Van Assche } 7191d68905SBart Van Assche 72cd84a62eSBart Van Assche static int queue_pm_only_show(void *data, struct seq_file *m) 73cd84a62eSBart Van Assche { 74cd84a62eSBart Van Assche struct request_queue *q = data; 75cd84a62eSBart Van Assche 76cd84a62eSBart Van Assche seq_printf(m, "%d\n", atomic_read(&q->pm_only)); 77cd84a62eSBart Van Assche return 0; 78cd84a62eSBart Van Assche } 79cd84a62eSBart Van Assche 801a435111SOmar Sandoval #define QUEUE_FLAG_NAME(name) [QUEUE_FLAG_##name] = #name 8191d68905SBart Van Assche static const char *const blk_queue_flag_name[] = { 821a435111SOmar Sandoval QUEUE_FLAG_NAME(STOPPED), 831a435111SOmar Sandoval QUEUE_FLAG_NAME(DYING), 841a435111SOmar Sandoval QUEUE_FLAG_NAME(NOMERGES), 851a435111SOmar Sandoval QUEUE_FLAG_NAME(SAME_COMP), 861a435111SOmar Sandoval QUEUE_FLAG_NAME(FAIL_IO), 871a435111SOmar Sandoval QUEUE_FLAG_NAME(NONROT), 881a435111SOmar Sandoval QUEUE_FLAG_NAME(IO_STAT), 891a435111SOmar Sandoval QUEUE_FLAG_NAME(NOXMERGES), 901a435111SOmar Sandoval QUEUE_FLAG_NAME(ADD_RANDOM), 91*d5fb8726SBart Van Assche QUEUE_FLAG_NAME(SYNCHRONOUS), 921a435111SOmar Sandoval QUEUE_FLAG_NAME(SAME_FORCE), 931a435111SOmar Sandoval QUEUE_FLAG_NAME(INIT_DONE), 941cb039f3SChristoph Hellwig QUEUE_FLAG_NAME(STABLE_WRITES), 951a435111SOmar Sandoval QUEUE_FLAG_NAME(POLL), 961a435111SOmar Sandoval QUEUE_FLAG_NAME(WC), 971a435111SOmar Sandoval QUEUE_FLAG_NAME(FUA), 981a435111SOmar Sandoval QUEUE_FLAG_NAME(DAX), 991a435111SOmar Sandoval QUEUE_FLAG_NAME(STATS), 1001a435111SOmar Sandoval QUEUE_FLAG_NAME(REGISTERED), 10122d53821SBart Van Assche QUEUE_FLAG_NAME(QUIESCED), 102bfe373f6SHou Tao QUEUE_FLAG_NAME(PCI_P2PDMA), 103bfe373f6SHou Tao QUEUE_FLAG_NAME(ZONE_RESETALL), 104bfe373f6SHou Tao QUEUE_FLAG_NAME(RQ_ALLOC_TIME), 1051dbdd99bSJohannes Thumshirn QUEUE_FLAG_NAME(HCTX_ACTIVE), 106dc304326SAndres Freund QUEUE_FLAG_NAME(NOWAIT), 107*d5fb8726SBart Van Assche QUEUE_FLAG_NAME(SQ_SCHED), 108*d5fb8726SBart Van Assche QUEUE_FLAG_NAME(SKIP_TAGSET_QUIESCE), 10991d68905SBart Van Assche }; 1101a435111SOmar Sandoval #undef QUEUE_FLAG_NAME 11191d68905SBart Van Assche 112f57de23aSOmar Sandoval static int queue_state_show(void *data, struct seq_file *m) 11391d68905SBart Van Assche { 114f57de23aSOmar Sandoval struct request_queue *q = data; 11591d68905SBart Van Assche 11691d68905SBart Van Assche blk_flags_show(m, q->queue_flags, blk_queue_flag_name, 11791d68905SBart Van Assche ARRAY_SIZE(blk_queue_flag_name)); 118fd07dc81SBart Van Assche seq_puts(m, "\n"); 11991d68905SBart Van Assche return 0; 12091d68905SBart Van Assche } 12191d68905SBart Van Assche 122f57de23aSOmar Sandoval static ssize_t queue_state_write(void *data, const char __user *buf, 123c7e4145aSOmar Sandoval size_t count, loff_t *ppos) 12491d68905SBart Van Assche { 125f57de23aSOmar Sandoval struct request_queue *q = data; 12671b90511SOmar Sandoval char opbuf[16] = { }, *op; 12791d68905SBart Van Assche 12818d4d7d0SBart Van Assche /* 1291f90307eSChristoph Hellwig * The "state" attribute is removed when the queue is removed. Don't 1301f90307eSChristoph Hellwig * allow setting the state on a dying queue to avoid a use-after-free. 13118d4d7d0SBart Van Assche */ 1321f90307eSChristoph Hellwig if (blk_queue_dying(q)) 13318d4d7d0SBart Van Assche return -ENOENT; 13418d4d7d0SBart Van Assche 13571b90511SOmar Sandoval if (count >= sizeof(opbuf)) { 136c7e4145aSOmar Sandoval pr_err("%s: operation too long\n", __func__); 137c7e4145aSOmar Sandoval goto inval; 138c7e4145aSOmar Sandoval } 139c7e4145aSOmar Sandoval 14071b90511SOmar Sandoval if (copy_from_user(opbuf, buf, count)) 14191d68905SBart Van Assche return -EFAULT; 14271b90511SOmar Sandoval op = strstrip(opbuf); 14391d68905SBart Van Assche if (strcmp(op, "run") == 0) { 14491d68905SBart Van Assche blk_mq_run_hw_queues(q, true); 14591d68905SBart Van Assche } else if (strcmp(op, "start") == 0) { 14691d68905SBart Van Assche blk_mq_start_stopped_hw_queues(q, true); 147edea55abSBart Van Assche } else if (strcmp(op, "kick") == 0) { 148edea55abSBart Van Assche blk_mq_kick_requeue_list(q); 14991d68905SBart Van Assche } else { 150c7e4145aSOmar Sandoval pr_err("%s: unsupported operation '%s'\n", __func__, op); 151c7e4145aSOmar Sandoval inval: 152edea55abSBart Van Assche pr_err("%s: use 'run', 'start' or 'kick'\n", __func__); 15391d68905SBart Van Assche return -EINVAL; 15491d68905SBart Van Assche } 155c7e4145aSOmar Sandoval return count; 15691d68905SBart Van Assche } 15791d68905SBart Van Assche 1581209cb7fSBart Van Assche static const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = { 1591209cb7fSBart Van Assche { "poll_stat", 0400, queue_poll_stat_show }, 1601209cb7fSBart Van Assche { "requeue_list", 0400, .seq_ops = &queue_requeue_list_seq_ops }, 161cd84a62eSBart Van Assche { "pm_only", 0600, queue_pm_only_show, NULL }, 1621209cb7fSBart Van Assche { "state", 0600, queue_state_show, queue_state_write }, 16318bc4230SBart Van Assche { "zone_wlock", 0400, queue_zone_wlock_show, NULL }, 1641209cb7fSBart Van Assche { }, 1651209cb7fSBart Van Assche }; 16634dbad5dSOmar Sandoval 1671a435111SOmar Sandoval #define HCTX_STATE_NAME(name) [BLK_MQ_S_##name] = #name 168f5c0b091SBart Van Assche static const char *const hctx_state_name[] = { 1691a435111SOmar Sandoval HCTX_STATE_NAME(STOPPED), 1701a435111SOmar Sandoval HCTX_STATE_NAME(TAG_ACTIVE), 1711a435111SOmar Sandoval HCTX_STATE_NAME(SCHED_RESTART), 172bf0beec0SMing Lei HCTX_STATE_NAME(INACTIVE), 173f5c0b091SBart Van Assche }; 1741a435111SOmar Sandoval #undef HCTX_STATE_NAME 1751a435111SOmar Sandoval 176f57de23aSOmar Sandoval static int hctx_state_show(void *data, struct seq_file *m) 1779abb2ad2SOmar Sandoval { 178f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 1799abb2ad2SOmar Sandoval 180f5c0b091SBart Van Assche blk_flags_show(m, hctx->state, hctx_state_name, 181f5c0b091SBart Van Assche ARRAY_SIZE(hctx_state_name)); 182fd07dc81SBart Van Assche seq_puts(m, "\n"); 1839abb2ad2SOmar Sandoval return 0; 1849abb2ad2SOmar Sandoval } 1859abb2ad2SOmar Sandoval 1861a435111SOmar Sandoval #define BLK_TAG_ALLOC_NAME(name) [BLK_TAG_ALLOC_##name] = #name 187f5c0b091SBart Van Assche static const char *const alloc_policy_name[] = { 1881a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(FIFO), 1891a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(RR), 190f5c0b091SBart Van Assche }; 1911a435111SOmar Sandoval #undef BLK_TAG_ALLOC_NAME 192f5c0b091SBart Van Assche 1931a435111SOmar Sandoval #define HCTX_FLAG_NAME(name) [ilog2(BLK_MQ_F_##name)] = #name 194f5c0b091SBart Van Assche static const char *const hctx_flag_name[] = { 1951a435111SOmar Sandoval HCTX_FLAG_NAME(SHOULD_MERGE), 19651db1c37SMing Lei HCTX_FLAG_NAME(TAG_QUEUE_SHARED), 1971a435111SOmar Sandoval HCTX_FLAG_NAME(BLOCKING), 1981a435111SOmar Sandoval HCTX_FLAG_NAME(NO_SCHED), 199bf0beec0SMing Lei HCTX_FLAG_NAME(STACKING), 20002f938e9SJohn Garry HCTX_FLAG_NAME(TAG_HCTX_SHARED), 201f5c0b091SBart Van Assche }; 2021a435111SOmar Sandoval #undef HCTX_FLAG_NAME 203f5c0b091SBart Van Assche 204f57de23aSOmar Sandoval static int hctx_flags_show(void *data, struct seq_file *m) 2059abb2ad2SOmar Sandoval { 206f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 207f5c0b091SBart Van Assche const int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(hctx->flags); 2089abb2ad2SOmar Sandoval 209f5c0b091SBart Van Assche seq_puts(m, "alloc_policy="); 210f5c0b091SBart Van Assche if (alloc_policy < ARRAY_SIZE(alloc_policy_name) && 211f5c0b091SBart Van Assche alloc_policy_name[alloc_policy]) 212f5c0b091SBart Van Assche seq_puts(m, alloc_policy_name[alloc_policy]); 213f5c0b091SBart Van Assche else 214f5c0b091SBart Van Assche seq_printf(m, "%d", alloc_policy); 215f5c0b091SBart Van Assche seq_puts(m, " "); 216f5c0b091SBart Van Assche blk_flags_show(m, 217f5c0b091SBart Van Assche hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy), 218f5c0b091SBart Van Assche hctx_flag_name, ARRAY_SIZE(hctx_flag_name)); 219fd07dc81SBart Van Assche seq_puts(m, "\n"); 2209abb2ad2SOmar Sandoval return 0; 2219abb2ad2SOmar Sandoval } 2229abb2ad2SOmar Sandoval 2231a435111SOmar Sandoval #define CMD_FLAG_NAME(name) [__REQ_##name] = #name 2248658dca8SBart Van Assche static const char *const cmd_flag_name[] = { 2251a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DEV), 2261a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_TRANSPORT), 2271a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DRIVER), 2281a435111SOmar Sandoval CMD_FLAG_NAME(SYNC), 2291a435111SOmar Sandoval CMD_FLAG_NAME(META), 2301a435111SOmar Sandoval CMD_FLAG_NAME(PRIO), 2311a435111SOmar Sandoval CMD_FLAG_NAME(NOMERGE), 2321a435111SOmar Sandoval CMD_FLAG_NAME(IDLE), 2331a435111SOmar Sandoval CMD_FLAG_NAME(INTEGRITY), 2341a435111SOmar Sandoval CMD_FLAG_NAME(FUA), 2351a435111SOmar Sandoval CMD_FLAG_NAME(PREFLUSH), 2361a435111SOmar Sandoval CMD_FLAG_NAME(RAHEAD), 2371a435111SOmar Sandoval CMD_FLAG_NAME(BACKGROUND), 23822d53821SBart Van Assche CMD_FLAG_NAME(NOWAIT), 2391c26010cSJianchao Wang CMD_FLAG_NAME(NOUNMAP), 2406ce913feSChristoph Hellwig CMD_FLAG_NAME(POLLED), 2418658dca8SBart Van Assche }; 2421a435111SOmar Sandoval #undef CMD_FLAG_NAME 2438658dca8SBart Van Assche 2441a435111SOmar Sandoval #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name 2458658dca8SBart Van Assche static const char *const rqf_name[] = { 24685ba3effSJens Axboe RQF_NAME(STARTED), 2471a435111SOmar Sandoval RQF_NAME(SOFTBARRIER), 2481a435111SOmar Sandoval RQF_NAME(FLUSH_SEQ), 2491a435111SOmar Sandoval RQF_NAME(MIXED_MERGE), 2501a435111SOmar Sandoval RQF_NAME(MQ_INFLIGHT), 2511a435111SOmar Sandoval RQF_NAME(DONTPREP), 2521a435111SOmar Sandoval RQF_NAME(FAILED), 2531a435111SOmar Sandoval RQF_NAME(QUIET), 2541a435111SOmar Sandoval RQF_NAME(ELVPRIV), 2551a435111SOmar Sandoval RQF_NAME(IO_STAT), 2561a435111SOmar Sandoval RQF_NAME(PM), 2571a435111SOmar Sandoval RQF_NAME(HASHED), 2581a435111SOmar Sandoval RQF_NAME(STATS), 2591a435111SOmar Sandoval RQF_NAME(SPECIAL_PAYLOAD), 2605d75d3f2SJens Axboe RQF_NAME(ZONE_WRITE_LOCKED), 261745ed372SJens Axboe RQF_NAME(TIMED_OUT), 26262ba0c00SMing Lei RQF_NAME(ELV), 263745ed372SJens Axboe RQF_NAME(RESV), 2648658dca8SBart Van Assche }; 2651a435111SOmar Sandoval #undef RQF_NAME 2668658dca8SBart Van Assche 267ec6dcf63SBart Van Assche static const char *const blk_mq_rq_state_name_array[] = { 268ec6dcf63SBart Van Assche [MQ_RQ_IDLE] = "idle", 269ec6dcf63SBart Van Assche [MQ_RQ_IN_FLIGHT] = "in_flight", 270ec6dcf63SBart Van Assche [MQ_RQ_COMPLETE] = "complete", 271ec6dcf63SBart Van Assche }; 272ec6dcf63SBart Van Assche 273ec6dcf63SBart Van Assche static const char *blk_mq_rq_state_name(enum mq_rq_state rq_state) 274ec6dcf63SBart Van Assche { 275a1e79188SDan Carpenter if (WARN_ON_ONCE((unsigned int)rq_state >= 276ec6dcf63SBart Van Assche ARRAY_SIZE(blk_mq_rq_state_name_array))) 277ec6dcf63SBart Van Assche return "(?)"; 278ec6dcf63SBart Van Assche return blk_mq_rq_state_name_array[rq_state]; 279ec6dcf63SBart Van Assche } 280ec6dcf63SBart Van Assche 281daaadb3eSOmar Sandoval int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq) 282950cd7e9SOmar Sandoval { 2832836ee4bSBart Van Assche const struct blk_mq_ops *const mq_ops = rq->q->mq_ops; 28477e7ffd7SBart Van Assche const enum req_op op = req_op(rq); 285874c893bSChaitanya Kulkarni const char *op_str = blk_op_str(op); 286950cd7e9SOmar Sandoval 2878658dca8SBart Van Assche seq_printf(m, "%p {.op=", rq); 288874c893bSChaitanya Kulkarni if (strcmp(op_str, "UNKNOWN") == 0) 2893f6d385fSChaitanya Kulkarni seq_printf(m, "%u", op); 2908658dca8SBart Van Assche else 291874c893bSChaitanya Kulkarni seq_printf(m, "%s", op_str); 2928658dca8SBart Van Assche seq_puts(m, ", .cmd_flags="); 29316458cf3SBart Van Assche blk_flags_show(m, (__force unsigned int)(rq->cmd_flags & ~REQ_OP_MASK), 29416458cf3SBart Van Assche cmd_flag_name, ARRAY_SIZE(cmd_flag_name)); 2958658dca8SBart Van Assche seq_puts(m, ", .rq_flags="); 2968658dca8SBart Van Assche blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name, 2978658dca8SBart Van Assche ARRAY_SIZE(rqf_name)); 298ec6dcf63SBart Van Assche seq_printf(m, ", .state=%s", blk_mq_rq_state_name(blk_mq_rq_state(rq))); 2992836ee4bSBart Van Assche seq_printf(m, ", .tag=%d, .internal_tag=%d", rq->tag, 3008658dca8SBart Van Assche rq->internal_tag); 3012836ee4bSBart Van Assche if (mq_ops->show_rq) 3022836ee4bSBart Van Assche mq_ops->show_rq(m, rq); 3032836ee4bSBart Van Assche seq_puts(m, "}\n"); 304950cd7e9SOmar Sandoval return 0; 305950cd7e9SOmar Sandoval } 306daaadb3eSOmar Sandoval EXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show); 307daaadb3eSOmar Sandoval 308daaadb3eSOmar Sandoval int blk_mq_debugfs_rq_show(struct seq_file *m, void *v) 309daaadb3eSOmar Sandoval { 310daaadb3eSOmar Sandoval return __blk_mq_debugfs_rq_show(m, list_entry_rq(v)); 311daaadb3eSOmar Sandoval } 31216b738f6SOmar Sandoval EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show); 313950cd7e9SOmar Sandoval 314950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos) 315f3bcb0e6SBart Van Assche __acquires(&hctx->lock) 316950cd7e9SOmar Sandoval { 317950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 318950cd7e9SOmar Sandoval 319950cd7e9SOmar Sandoval spin_lock(&hctx->lock); 320950cd7e9SOmar Sandoval return seq_list_start(&hctx->dispatch, *pos); 321950cd7e9SOmar Sandoval } 322950cd7e9SOmar Sandoval 323950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos) 324950cd7e9SOmar Sandoval { 325950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 326950cd7e9SOmar Sandoval 327950cd7e9SOmar Sandoval return seq_list_next(v, &hctx->dispatch, pos); 328950cd7e9SOmar Sandoval } 329950cd7e9SOmar Sandoval 330950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v) 331f3bcb0e6SBart Van Assche __releases(&hctx->lock) 332950cd7e9SOmar Sandoval { 333950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 334950cd7e9SOmar Sandoval 335950cd7e9SOmar Sandoval spin_unlock(&hctx->lock); 336950cd7e9SOmar Sandoval } 337950cd7e9SOmar Sandoval 338950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = { 339950cd7e9SOmar Sandoval .start = hctx_dispatch_start, 340950cd7e9SOmar Sandoval .next = hctx_dispatch_next, 341950cd7e9SOmar Sandoval .stop = hctx_dispatch_stop, 342950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 343950cd7e9SOmar Sandoval }; 344950cd7e9SOmar Sandoval 3452720bab5SBart Van Assche struct show_busy_params { 3462720bab5SBart Van Assche struct seq_file *m; 3472720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx; 3482720bab5SBart Van Assche }; 3492720bab5SBart Van Assche 3502720bab5SBart Van Assche /* 3512720bab5SBart Van Assche * Note: the state of a request may change while this function is in progress, 3527baa8572SJens Axboe * e.g. due to a concurrent blk_mq_finish_request() call. Returns true to 3537baa8572SJens Axboe * keep iterating requests. 3542720bab5SBart Van Assche */ 3552dd6532eSJohn Garry static bool hctx_show_busy_rq(struct request *rq, void *data) 3562720bab5SBart Van Assche { 3572720bab5SBart Van Assche const struct show_busy_params *params = data; 3582720bab5SBart Van Assche 359ea4f995eSJens Axboe if (rq->mq_hctx == params->hctx) 360b5fc1e8bSHou Tao __blk_mq_debugfs_rq_show(params->m, rq); 3617baa8572SJens Axboe 3627baa8572SJens Axboe return true; 3632720bab5SBart Van Assche } 3642720bab5SBart Van Assche 3652720bab5SBart Van Assche static int hctx_busy_show(void *data, struct seq_file *m) 3662720bab5SBart Van Assche { 3672720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx = data; 3682720bab5SBart Van Assche struct show_busy_params params = { .m = m, .hctx = hctx }; 3692720bab5SBart Van Assche 3702720bab5SBart Van Assche blk_mq_tagset_busy_iter(hctx->queue->tag_set, hctx_show_busy_rq, 3712720bab5SBart Van Assche ¶ms); 3722720bab5SBart Van Assche 3732720bab5SBart Van Assche return 0; 3742720bab5SBart Van Assche } 3752720bab5SBart Van Assche 376346fc108SMing Lei static const char *const hctx_types[] = { 377346fc108SMing Lei [HCTX_TYPE_DEFAULT] = "default", 378346fc108SMing Lei [HCTX_TYPE_READ] = "read", 379346fc108SMing Lei [HCTX_TYPE_POLL] = "poll", 380346fc108SMing Lei }; 381346fc108SMing Lei 382346fc108SMing Lei static int hctx_type_show(void *data, struct seq_file *m) 383346fc108SMing Lei { 384346fc108SMing Lei struct blk_mq_hw_ctx *hctx = data; 385346fc108SMing Lei 386346fc108SMing Lei BUILD_BUG_ON(ARRAY_SIZE(hctx_types) != HCTX_MAX_TYPES); 387346fc108SMing Lei seq_printf(m, "%s\n", hctx_types[hctx->type]); 388346fc108SMing Lei return 0; 389346fc108SMing Lei } 390346fc108SMing Lei 391f57de23aSOmar Sandoval static int hctx_ctx_map_show(void *data, struct seq_file *m) 392950cd7e9SOmar Sandoval { 393f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 3940bfa5288SOmar Sandoval 3950bfa5288SOmar Sandoval sbitmap_bitmap_show(&hctx->ctx_map, m); 3960bfa5288SOmar Sandoval return 0; 3970bfa5288SOmar Sandoval } 3980bfa5288SOmar Sandoval 399d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m, 400d96b37c0SOmar Sandoval struct blk_mq_tags *tags) 401d96b37c0SOmar Sandoval { 402d96b37c0SOmar Sandoval seq_printf(m, "nr_tags=%u\n", tags->nr_tags); 403d96b37c0SOmar Sandoval seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags); 404d96b37c0SOmar Sandoval seq_printf(m, "active_queues=%d\n", 405d96b37c0SOmar Sandoval atomic_read(&tags->active_queues)); 406d96b37c0SOmar Sandoval 407d96b37c0SOmar Sandoval seq_puts(m, "\nbitmap_tags:\n"); 408ae0f1a73SJohn Garry sbitmap_queue_show(&tags->bitmap_tags, m); 409d96b37c0SOmar Sandoval 410d96b37c0SOmar Sandoval if (tags->nr_reserved_tags) { 411d96b37c0SOmar Sandoval seq_puts(m, "\nbreserved_tags:\n"); 412ae0f1a73SJohn Garry sbitmap_queue_show(&tags->breserved_tags, m); 413d96b37c0SOmar Sandoval } 414d96b37c0SOmar Sandoval } 415d96b37c0SOmar Sandoval 416f57de23aSOmar Sandoval static int hctx_tags_show(void *data, struct seq_file *m) 417d96b37c0SOmar Sandoval { 418f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 419d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 4208c0f14eaSBart Van Assche int res; 421d96b37c0SOmar Sandoval 4228c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4238c0f14eaSBart Van Assche if (res) 4248c0f14eaSBart Van Assche goto out; 425d96b37c0SOmar Sandoval if (hctx->tags) 426d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->tags); 427d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 428d96b37c0SOmar Sandoval 4298c0f14eaSBart Van Assche out: 4308c0f14eaSBart Van Assche return res; 431d96b37c0SOmar Sandoval } 432d96b37c0SOmar Sandoval 433f57de23aSOmar Sandoval static int hctx_tags_bitmap_show(void *data, struct seq_file *m) 434d96b37c0SOmar Sandoval { 435f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 436d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 4378c0f14eaSBart Van Assche int res; 438d7e3621aSOmar Sandoval 4398c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4408c0f14eaSBart Van Assche if (res) 4418c0f14eaSBart Van Assche goto out; 442d7e3621aSOmar Sandoval if (hctx->tags) 443ae0f1a73SJohn Garry sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m); 444d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 4458c0f14eaSBart Van Assche 4468c0f14eaSBart Van Assche out: 4478c0f14eaSBart Van Assche return res; 448d7e3621aSOmar Sandoval } 449d7e3621aSOmar Sandoval 450f57de23aSOmar Sandoval static int hctx_sched_tags_show(void *data, struct seq_file *m) 451d7e3621aSOmar Sandoval { 452f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 453d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 4548c0f14eaSBart Van Assche int res; 455d96b37c0SOmar Sandoval 4568c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4578c0f14eaSBart Van Assche if (res) 4588c0f14eaSBart Van Assche goto out; 459d96b37c0SOmar Sandoval if (hctx->sched_tags) 460d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->sched_tags); 461d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 462d96b37c0SOmar Sandoval 4638c0f14eaSBart Van Assche out: 4648c0f14eaSBart Van Assche return res; 465d96b37c0SOmar Sandoval } 466d96b37c0SOmar Sandoval 467f57de23aSOmar Sandoval static int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m) 468d96b37c0SOmar Sandoval { 469f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 470d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 4718c0f14eaSBart Van Assche int res; 472d7e3621aSOmar Sandoval 4738c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4748c0f14eaSBart Van Assche if (res) 4758c0f14eaSBart Van Assche goto out; 476d7e3621aSOmar Sandoval if (hctx->sched_tags) 477ae0f1a73SJohn Garry sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m); 478d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 4798c0f14eaSBart Van Assche 4808c0f14eaSBart Van Assche out: 4818c0f14eaSBart Van Assche return res; 482d7e3621aSOmar Sandoval } 483d7e3621aSOmar Sandoval 484f57de23aSOmar Sandoval static int hctx_run_show(void *data, struct seq_file *m) 4854a46f05eSOmar Sandoval { 486f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 4874a46f05eSOmar Sandoval 4884a46f05eSOmar Sandoval seq_printf(m, "%lu\n", hctx->run); 4894a46f05eSOmar Sandoval return 0; 4904a46f05eSOmar Sandoval } 4914a46f05eSOmar Sandoval 492f57de23aSOmar Sandoval static ssize_t hctx_run_write(void *data, const char __user *buf, size_t count, 493f57de23aSOmar Sandoval loff_t *ppos) 4944a46f05eSOmar Sandoval { 495f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 4964a46f05eSOmar Sandoval 4974a46f05eSOmar Sandoval hctx->run = 0; 4984a46f05eSOmar Sandoval return count; 4994a46f05eSOmar Sandoval } 5004a46f05eSOmar Sandoval 501f57de23aSOmar Sandoval static int hctx_active_show(void *data, struct seq_file *m) 5024a46f05eSOmar Sandoval { 503f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5044a46f05eSOmar Sandoval 5059b84c629SJohn Garry seq_printf(m, "%d\n", __blk_mq_active_requests(hctx)); 5064a46f05eSOmar Sandoval return 0; 5074a46f05eSOmar Sandoval } 5084a46f05eSOmar Sandoval 5096e768717SMing Lei static int hctx_dispatch_busy_show(void *data, struct seq_file *m) 5106e768717SMing Lei { 5116e768717SMing Lei struct blk_mq_hw_ctx *hctx = data; 5126e768717SMing Lei 5136e768717SMing Lei seq_printf(m, "%u\n", hctx->dispatch_busy); 5146e768717SMing Lei return 0; 5156e768717SMing Lei } 5166e768717SMing Lei 517c16d6b5aSMing Lei #define CTX_RQ_SEQ_OPS(name, type) \ 518c16d6b5aSMing Lei static void *ctx_##name##_rq_list_start(struct seq_file *m, loff_t *pos) \ 519c16d6b5aSMing Lei __acquires(&ctx->lock) \ 520c16d6b5aSMing Lei { \ 521c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 522c16d6b5aSMing Lei \ 523c16d6b5aSMing Lei spin_lock(&ctx->lock); \ 524c16d6b5aSMing Lei return seq_list_start(&ctx->rq_lists[type], *pos); \ 525c16d6b5aSMing Lei } \ 526c16d6b5aSMing Lei \ 527c16d6b5aSMing Lei static void *ctx_##name##_rq_list_next(struct seq_file *m, void *v, \ 528c16d6b5aSMing Lei loff_t *pos) \ 529c16d6b5aSMing Lei { \ 530c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 531c16d6b5aSMing Lei \ 532c16d6b5aSMing Lei return seq_list_next(v, &ctx->rq_lists[type], pos); \ 533c16d6b5aSMing Lei } \ 534c16d6b5aSMing Lei \ 535c16d6b5aSMing Lei static void ctx_##name##_rq_list_stop(struct seq_file *m, void *v) \ 536c16d6b5aSMing Lei __releases(&ctx->lock) \ 537c16d6b5aSMing Lei { \ 538c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 539c16d6b5aSMing Lei \ 540c16d6b5aSMing Lei spin_unlock(&ctx->lock); \ 541c16d6b5aSMing Lei } \ 542c16d6b5aSMing Lei \ 543c16d6b5aSMing Lei static const struct seq_operations ctx_##name##_rq_list_seq_ops = { \ 544c16d6b5aSMing Lei .start = ctx_##name##_rq_list_start, \ 545c16d6b5aSMing Lei .next = ctx_##name##_rq_list_next, \ 546c16d6b5aSMing Lei .stop = ctx_##name##_rq_list_stop, \ 547c16d6b5aSMing Lei .show = blk_mq_debugfs_rq_show, \ 548950cd7e9SOmar Sandoval } 549950cd7e9SOmar Sandoval 550c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(default, HCTX_TYPE_DEFAULT); 551c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(read, HCTX_TYPE_READ); 552c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(poll, HCTX_TYPE_POLL); 553950cd7e9SOmar Sandoval 554f57de23aSOmar Sandoval static int blk_mq_debugfs_show(struct seq_file *m, void *v) 555f57de23aSOmar Sandoval { 556f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 557f57de23aSOmar Sandoval void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private; 558f57de23aSOmar Sandoval 559f57de23aSOmar Sandoval return attr->show(data, m); 560f57de23aSOmar Sandoval } 561f57de23aSOmar Sandoval 562f57de23aSOmar Sandoval static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf, 563f57de23aSOmar Sandoval size_t count, loff_t *ppos) 564f57de23aSOmar Sandoval { 565f57de23aSOmar Sandoval struct seq_file *m = file->private_data; 566f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 567f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 568f57de23aSOmar Sandoval 5696b136a24SEryu Guan /* 5706b136a24SEryu Guan * Attributes that only implement .seq_ops are read-only and 'attr' is 5716b136a24SEryu Guan * the same with 'data' in this case. 5726b136a24SEryu Guan */ 5736b136a24SEryu Guan if (attr == data || !attr->write) 574f57de23aSOmar Sandoval return -EPERM; 575f57de23aSOmar Sandoval 576f57de23aSOmar Sandoval return attr->write(data, buf, count, ppos); 577f57de23aSOmar Sandoval } 578f57de23aSOmar Sandoval 579f57de23aSOmar Sandoval static int blk_mq_debugfs_open(struct inode *inode, struct file *file) 580f57de23aSOmar Sandoval { 581f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 582f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 583f57de23aSOmar Sandoval struct seq_file *m; 584f57de23aSOmar Sandoval int ret; 585f57de23aSOmar Sandoval 586f57de23aSOmar Sandoval if (attr->seq_ops) { 587f57de23aSOmar Sandoval ret = seq_open(file, attr->seq_ops); 588f57de23aSOmar Sandoval if (!ret) { 589f57de23aSOmar Sandoval m = file->private_data; 590f57de23aSOmar Sandoval m->private = data; 591f57de23aSOmar Sandoval } 592f57de23aSOmar Sandoval return ret; 593f57de23aSOmar Sandoval } 594f57de23aSOmar Sandoval 595f57de23aSOmar Sandoval if (WARN_ON_ONCE(!attr->show)) 596f57de23aSOmar Sandoval return -EPERM; 597f57de23aSOmar Sandoval 598f57de23aSOmar Sandoval return single_open(file, blk_mq_debugfs_show, inode->i_private); 599f57de23aSOmar Sandoval } 600f57de23aSOmar Sandoval 601f57de23aSOmar Sandoval static int blk_mq_debugfs_release(struct inode *inode, struct file *file) 602f57de23aSOmar Sandoval { 603f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 604f57de23aSOmar Sandoval 605f57de23aSOmar Sandoval if (attr->show) 606f57de23aSOmar Sandoval return single_release(inode, file); 607ee1e0359SChaitanya Kulkarni 608f57de23aSOmar Sandoval return seq_release(inode, file); 609f57de23aSOmar Sandoval } 610f57de23aSOmar Sandoval 611f8465933SBart Van Assche static const struct file_operations blk_mq_debugfs_fops = { 612f57de23aSOmar Sandoval .open = blk_mq_debugfs_open, 6134a46f05eSOmar Sandoval .read = seq_read, 614f57de23aSOmar Sandoval .write = blk_mq_debugfs_write, 6154a46f05eSOmar Sandoval .llseek = seq_lseek, 616f57de23aSOmar Sandoval .release = blk_mq_debugfs_release, 6174a46f05eSOmar Sandoval }; 6184a46f05eSOmar Sandoval 61907e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { 620f57de23aSOmar Sandoval {"state", 0400, hctx_state_show}, 621f57de23aSOmar Sandoval {"flags", 0400, hctx_flags_show}, 622f57de23aSOmar Sandoval {"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops}, 6232720bab5SBart Van Assche {"busy", 0400, hctx_busy_show}, 624f57de23aSOmar Sandoval {"ctx_map", 0400, hctx_ctx_map_show}, 625f57de23aSOmar Sandoval {"tags", 0400, hctx_tags_show}, 626f57de23aSOmar Sandoval {"tags_bitmap", 0400, hctx_tags_bitmap_show}, 627f57de23aSOmar Sandoval {"sched_tags", 0400, hctx_sched_tags_show}, 628f57de23aSOmar Sandoval {"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show}, 629f57de23aSOmar Sandoval {"run", 0600, hctx_run_show, hctx_run_write}, 630f57de23aSOmar Sandoval {"active", 0400, hctx_active_show}, 6316e768717SMing Lei {"dispatch_busy", 0400, hctx_dispatch_busy_show}, 632346fc108SMing Lei {"type", 0400, hctx_type_show}, 63372f2f8f6SBart Van Assche {}, 63407e4feadSOmar Sandoval }; 63507e4feadSOmar Sandoval 63607e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = { 637c16d6b5aSMing Lei {"default_rq_list", 0400, .seq_ops = &ctx_default_rq_list_seq_ops}, 638c16d6b5aSMing Lei {"read_rq_list", 0400, .seq_ops = &ctx_read_rq_list_seq_ops}, 639c16d6b5aSMing Lei {"poll_rq_list", 0400, .seq_ops = &ctx_poll_rq_list_seq_ops}, 64072f2f8f6SBart Van Assche {}, 64107e4feadSOmar Sandoval }; 64207e4feadSOmar Sandoval 6436cfc0081SGreg Kroah-Hartman static void debugfs_create_files(struct dentry *parent, void *data, 64472f2f8f6SBart Van Assche const struct blk_mq_debugfs_attr *attr) 64572f2f8f6SBart Van Assche { 64636991ca6SGreg Kroah-Hartman if (IS_ERR_OR_NULL(parent)) 6476cfc0081SGreg Kroah-Hartman return; 64836991ca6SGreg Kroah-Hartman 649f57de23aSOmar Sandoval d_inode(parent)->i_private = data; 650f57de23aSOmar Sandoval 6516cfc0081SGreg Kroah-Hartman for (; attr->name; attr++) 6526cfc0081SGreg Kroah-Hartman debugfs_create_file(attr->name, attr->mode, parent, 6536cfc0081SGreg Kroah-Hartman (void *)attr, &blk_mq_debugfs_fops); 65472f2f8f6SBart Van Assche } 65572f2f8f6SBart Van Assche 6566cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register(struct request_queue *q) 6579c1051aaSOmar Sandoval { 6589c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 6594f481208SMing Lei unsigned long i; 6609c1051aaSOmar Sandoval 6616cfc0081SGreg Kroah-Hartman debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs); 6629c1051aaSOmar Sandoval 6639c1051aaSOmar Sandoval /* 66470e62f4bSOmar Sandoval * blk_mq_init_sched() attempted to do this already, but q->debugfs_dir 6659c1051aaSOmar Sandoval * didn't exist yet (because we don't know what to name the directory 6669c1051aaSOmar Sandoval * until the queue is registered to a gendisk). 6679c1051aaSOmar Sandoval */ 66870e62f4bSOmar Sandoval if (q->elevator && !q->sched_debugfs_dir) 66970e62f4bSOmar Sandoval blk_mq_debugfs_register_sched(q); 67070e62f4bSOmar Sandoval 67170e62f4bSOmar Sandoval /* Similarly, blk_mq_init_hctx() couldn't do this previously. */ 6729c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) { 6736cfc0081SGreg Kroah-Hartman if (!hctx->debugfs_dir) 6746cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_hctx(q, hctx); 6756cfc0081SGreg Kroah-Hartman if (q->elevator && !hctx->sched_debugfs_dir) 6766cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_sched_hctx(q, hctx); 6779c1051aaSOmar Sandoval } 6789c1051aaSOmar Sandoval 679cc56694fSMing Lei if (q->rq_qos) { 680cc56694fSMing Lei struct rq_qos *rqos = q->rq_qos; 681cc56694fSMing Lei 682cc56694fSMing Lei while (rqos) { 683cc56694fSMing Lei blk_mq_debugfs_register_rqos(rqos); 684cc56694fSMing Lei rqos = rqos->next; 685cc56694fSMing Lei } 686cc56694fSMing Lei } 6879c1051aaSOmar Sandoval } 6889c1051aaSOmar Sandoval 6896cfc0081SGreg Kroah-Hartman static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx, 6909c1051aaSOmar Sandoval struct blk_mq_ctx *ctx) 69107e4feadSOmar Sandoval { 69207e4feadSOmar Sandoval struct dentry *ctx_dir; 69307e4feadSOmar Sandoval char name[20]; 69407e4feadSOmar Sandoval 69507e4feadSOmar Sandoval snprintf(name, sizeof(name), "cpu%u", ctx->cpu); 6969c1051aaSOmar Sandoval ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir); 69707e4feadSOmar Sandoval 6986cfc0081SGreg Kroah-Hartman debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs); 69907e4feadSOmar Sandoval } 70007e4feadSOmar Sandoval 7016cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_hctx(struct request_queue *q, 70207e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx) 70307e4feadSOmar Sandoval { 70407e4feadSOmar Sandoval struct blk_mq_ctx *ctx; 70507e4feadSOmar Sandoval char name[20]; 70607e4feadSOmar Sandoval int i; 70707e4feadSOmar Sandoval 708f3ec5d11SMing Lei if (!q->debugfs_dir) 709f3ec5d11SMing Lei return; 710f3ec5d11SMing Lei 7119c1051aaSOmar Sandoval snprintf(name, sizeof(name), "hctx%u", hctx->queue_num); 7129c1051aaSOmar Sandoval hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir); 7139c1051aaSOmar Sandoval 7146cfc0081SGreg Kroah-Hartman debugfs_create_files(hctx->debugfs_dir, hctx, blk_mq_debugfs_hctx_attrs); 71507e4feadSOmar Sandoval 7166cfc0081SGreg Kroah-Hartman hctx_for_each_ctx(hctx, ctx, i) 7176cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_ctx(hctx, ctx); 71807e4feadSOmar Sandoval } 71907e4feadSOmar Sandoval 7209c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx) 72107e4feadSOmar Sandoval { 7225cf9c91bSChristoph Hellwig if (!hctx->queue->debugfs_dir) 7235cf9c91bSChristoph Hellwig return; 7249c1051aaSOmar Sandoval debugfs_remove_recursive(hctx->debugfs_dir); 725d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 7269c1051aaSOmar Sandoval hctx->debugfs_dir = NULL; 7279c1051aaSOmar Sandoval } 7289c1051aaSOmar Sandoval 7296cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_hctxs(struct request_queue *q) 7309c1051aaSOmar Sandoval { 7319c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 7324f481208SMing Lei unsigned long i; 7339c1051aaSOmar Sandoval 7346cfc0081SGreg Kroah-Hartman queue_for_each_hw_ctx(q, hctx, i) 7356cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_hctx(q, hctx); 7369c1051aaSOmar Sandoval } 7379c1051aaSOmar Sandoval 7389c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q) 7399c1051aaSOmar Sandoval { 7409c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 7414f481208SMing Lei unsigned long i; 7429c1051aaSOmar Sandoval 7439c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) 7449c1051aaSOmar Sandoval blk_mq_debugfs_unregister_hctx(hctx); 74507e4feadSOmar Sandoval } 746d332ce09SOmar Sandoval 7476cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_sched(struct request_queue *q) 748d332ce09SOmar Sandoval { 749d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 750d332ce09SOmar Sandoval 7515cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 7525cf9c91bSChristoph Hellwig 7537e41c3c9SGreg Kroah-Hartman /* 7547e41c3c9SGreg Kroah-Hartman * If the parent directory has not been created yet, return, we will be 7557e41c3c9SGreg Kroah-Hartman * called again later on and the directory/files will be created then. 7567e41c3c9SGreg Kroah-Hartman */ 7577e41c3c9SGreg Kroah-Hartman if (!q->debugfs_dir) 7587e41c3c9SGreg Kroah-Hartman return; 7597e41c3c9SGreg Kroah-Hartman 760d332ce09SOmar Sandoval if (!e->queue_debugfs_attrs) 7616cfc0081SGreg Kroah-Hartman return; 762d332ce09SOmar Sandoval 763d332ce09SOmar Sandoval q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir); 764d332ce09SOmar Sandoval 7656cfc0081SGreg Kroah-Hartman debugfs_create_files(q->sched_debugfs_dir, q, e->queue_debugfs_attrs); 766d332ce09SOmar Sandoval } 767d332ce09SOmar Sandoval 768d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched(struct request_queue *q) 769d332ce09SOmar Sandoval { 7705cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 7715cf9c91bSChristoph Hellwig 772d332ce09SOmar Sandoval debugfs_remove_recursive(q->sched_debugfs_dir); 773d332ce09SOmar Sandoval q->sched_debugfs_dir = NULL; 774d332ce09SOmar Sandoval } 775d332ce09SOmar Sandoval 776fb44023eSBart Van Assche static const char *rq_qos_id_to_name(enum rq_qos_id id) 777fb44023eSBart Van Assche { 778fb44023eSBart Van Assche switch (id) { 779fb44023eSBart Van Assche case RQ_QOS_WBT: 780fb44023eSBart Van Assche return "wbt"; 781fb44023eSBart Van Assche case RQ_QOS_LATENCY: 782fb44023eSBart Van Assche return "latency"; 783fb44023eSBart Van Assche case RQ_QOS_COST: 784fb44023eSBart Van Assche return "cost"; 785fb44023eSBart Van Assche } 786fb44023eSBart Van Assche return "unknown"; 787fb44023eSBart Van Assche } 788fb44023eSBart Van Assche 789cc56694fSMing Lei void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos) 790cc56694fSMing Lei { 791ba91c849SChristoph Hellwig lockdep_assert_held(&rqos->disk->queue->debugfs_mutex); 7925cf9c91bSChristoph Hellwig 793ba91c849SChristoph Hellwig if (!rqos->disk->queue->debugfs_dir) 7945cf9c91bSChristoph Hellwig return; 795cc56694fSMing Lei debugfs_remove_recursive(rqos->debugfs_dir); 796cc56694fSMing Lei rqos->debugfs_dir = NULL; 797cc56694fSMing Lei } 798cc56694fSMing Lei 7996cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_rqos(struct rq_qos *rqos) 800cc56694fSMing Lei { 801ba91c849SChristoph Hellwig struct request_queue *q = rqos->disk->queue; 802cc56694fSMing Lei const char *dir_name = rq_qos_id_to_name(rqos->id); 803cc56694fSMing Lei 8045cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 8055cf9c91bSChristoph Hellwig 806cc56694fSMing Lei if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs) 8076cfc0081SGreg Kroah-Hartman return; 808cc56694fSMing Lei 8096cfc0081SGreg Kroah-Hartman if (!q->rqos_debugfs_dir) 810cc56694fSMing Lei q->rqos_debugfs_dir = debugfs_create_dir("rqos", 811cc56694fSMing Lei q->debugfs_dir); 812cc56694fSMing Lei 813ba91c849SChristoph Hellwig rqos->debugfs_dir = debugfs_create_dir(dir_name, q->rqos_debugfs_dir); 8146cfc0081SGreg Kroah-Hartman debugfs_create_files(rqos->debugfs_dir, rqos, rqos->ops->debugfs_attrs); 815cc56694fSMing Lei } 816cc56694fSMing Lei 8176cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_sched_hctx(struct request_queue *q, 818d332ce09SOmar Sandoval struct blk_mq_hw_ctx *hctx) 819d332ce09SOmar Sandoval { 820d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 821d332ce09SOmar Sandoval 8225cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 8235cf9c91bSChristoph Hellwig 8241e91e28eSSaravanan D /* 8251e91e28eSSaravanan D * If the parent debugfs directory has not been created yet, return; 8261e91e28eSSaravanan D * We will be called again later on with appropriate parent debugfs 8271e91e28eSSaravanan D * directory from blk_register_queue() 8281e91e28eSSaravanan D */ 8291e91e28eSSaravanan D if (!hctx->debugfs_dir) 8301e91e28eSSaravanan D return; 8311e91e28eSSaravanan D 832d332ce09SOmar Sandoval if (!e->hctx_debugfs_attrs) 8336cfc0081SGreg Kroah-Hartman return; 834d332ce09SOmar Sandoval 835d332ce09SOmar Sandoval hctx->sched_debugfs_dir = debugfs_create_dir("sched", 836d332ce09SOmar Sandoval hctx->debugfs_dir); 8376cfc0081SGreg Kroah-Hartman debugfs_create_files(hctx->sched_debugfs_dir, hctx, 8386cfc0081SGreg Kroah-Hartman e->hctx_debugfs_attrs); 839d332ce09SOmar Sandoval } 840d332ce09SOmar Sandoval 841d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx) 842d332ce09SOmar Sandoval { 8435cf9c91bSChristoph Hellwig lockdep_assert_held(&hctx->queue->debugfs_mutex); 8445cf9c91bSChristoph Hellwig 8455cf9c91bSChristoph Hellwig if (!hctx->queue->debugfs_dir) 8465cf9c91bSChristoph Hellwig return; 847d332ce09SOmar Sandoval debugfs_remove_recursive(hctx->sched_debugfs_dir); 848d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 849d332ce09SOmar Sandoval } 850