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> 8cce496deSJohn Garry #include <linux/build_bug.h> 907e4feadSOmar Sandoval #include <linux/debugfs.h> 1007e4feadSOmar Sandoval 1118fbda91SOmar Sandoval #include "blk.h" 1207e4feadSOmar Sandoval #include "blk-mq.h" 13d173a251SOmar Sandoval #include "blk-mq-debugfs.h" 142aa7745bSChristoph Hellwig #include "blk-mq-sched.h" 15cc56694fSMing Lei #include "blk-rq-qos.h" 1607e4feadSOmar Sandoval 171209cb7fSBart Van Assche static int queue_poll_stat_show(void *data, struct seq_file *m) 181209cb7fSBart Van Assche { 191209cb7fSBart Van Assche return 0; 201209cb7fSBart Van Assche } 211209cb7fSBart Van Assche 221209cb7fSBart Van Assche static void *queue_requeue_list_start(struct seq_file *m, loff_t *pos) 231209cb7fSBart Van Assche __acquires(&q->requeue_lock) 241209cb7fSBart Van Assche { 251209cb7fSBart Van Assche struct request_queue *q = m->private; 261209cb7fSBart Van Assche 271209cb7fSBart Van Assche spin_lock_irq(&q->requeue_lock); 281209cb7fSBart Van Assche return seq_list_start(&q->requeue_list, *pos); 291209cb7fSBart Van Assche } 301209cb7fSBart Van Assche 311209cb7fSBart Van Assche static void *queue_requeue_list_next(struct seq_file *m, void *v, loff_t *pos) 321209cb7fSBart Van Assche { 331209cb7fSBart Van Assche struct request_queue *q = m->private; 341209cb7fSBart Van Assche 351209cb7fSBart Van Assche return seq_list_next(v, &q->requeue_list, pos); 361209cb7fSBart Van Assche } 371209cb7fSBart Van Assche 381209cb7fSBart Van Assche static void queue_requeue_list_stop(struct seq_file *m, void *v) 391209cb7fSBart Van Assche __releases(&q->requeue_lock) 401209cb7fSBart Van Assche { 411209cb7fSBart Van Assche struct request_queue *q = m->private; 421209cb7fSBart Van Assche 431209cb7fSBart Van Assche spin_unlock_irq(&q->requeue_lock); 441209cb7fSBart Van Assche } 451209cb7fSBart Van Assche 461209cb7fSBart Van Assche static const struct seq_operations queue_requeue_list_seq_ops = { 471209cb7fSBart Van Assche .start = queue_requeue_list_start, 481209cb7fSBart Van Assche .next = queue_requeue_list_next, 491209cb7fSBart Van Assche .stop = queue_requeue_list_stop, 501209cb7fSBart Van Assche .show = blk_mq_debugfs_rq_show, 511209cb7fSBart Van Assche }; 521209cb7fSBart Van Assche 5391d68905SBart Van Assche static int blk_flags_show(struct seq_file *m, const unsigned long flags, 5491d68905SBart Van Assche const char *const *flag_name, int flag_name_count) 5591d68905SBart Van Assche { 5691d68905SBart Van Assche bool sep = false; 5791d68905SBart Van Assche int i; 5891d68905SBart Van Assche 5991d68905SBart Van Assche for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) { 6091d68905SBart Van Assche if (!(flags & BIT(i))) 6191d68905SBart Van Assche continue; 6291d68905SBart Van Assche if (sep) 63bec03d6bSOmar Sandoval seq_puts(m, "|"); 6491d68905SBart Van Assche sep = true; 6591d68905SBart Van Assche if (i < flag_name_count && flag_name[i]) 6691d68905SBart Van Assche seq_puts(m, flag_name[i]); 6791d68905SBart Van Assche else 6891d68905SBart Van Assche seq_printf(m, "%d", i); 6991d68905SBart Van Assche } 7091d68905SBart Van Assche return 0; 7191d68905SBart Van Assche } 7291d68905SBart Van Assche 73cd84a62eSBart Van Assche static int queue_pm_only_show(void *data, struct seq_file *m) 74cd84a62eSBart Van Assche { 75cd84a62eSBart Van Assche struct request_queue *q = data; 76cd84a62eSBart Van Assche 77cd84a62eSBart Van Assche seq_printf(m, "%d\n", atomic_read(&q->pm_only)); 78cd84a62eSBart Van Assche return 0; 79cd84a62eSBart Van Assche } 80cd84a62eSBart Van Assche 811a435111SOmar Sandoval #define QUEUE_FLAG_NAME(name) [QUEUE_FLAG_##name] = #name 8291d68905SBart Van Assche static const char *const blk_queue_flag_name[] = { 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(NOXMERGES), 881a435111SOmar Sandoval QUEUE_FLAG_NAME(SAME_FORCE), 891a435111SOmar Sandoval QUEUE_FLAG_NAME(INIT_DONE), 901a435111SOmar Sandoval QUEUE_FLAG_NAME(STATS), 911a435111SOmar Sandoval QUEUE_FLAG_NAME(REGISTERED), 9222d53821SBart Van Assche QUEUE_FLAG_NAME(QUIESCED), 93bfe373f6SHou Tao QUEUE_FLAG_NAME(RQ_ALLOC_TIME), 941dbdd99bSJohannes Thumshirn QUEUE_FLAG_NAME(HCTX_ACTIVE), 95d5fb8726SBart Van Assche QUEUE_FLAG_NAME(SQ_SCHED), 9691d68905SBart Van Assche }; 971a435111SOmar Sandoval #undef QUEUE_FLAG_NAME 9891d68905SBart Van Assche 99f57de23aSOmar Sandoval static int queue_state_show(void *data, struct seq_file *m) 10091d68905SBart Van Assche { 101f57de23aSOmar Sandoval struct request_queue *q = data; 10291d68905SBart Van Assche 103cce496deSJohn Garry BUILD_BUG_ON(ARRAY_SIZE(blk_queue_flag_name) != QUEUE_FLAG_MAX); 10491d68905SBart Van Assche blk_flags_show(m, q->queue_flags, blk_queue_flag_name, 10591d68905SBart Van Assche ARRAY_SIZE(blk_queue_flag_name)); 106fd07dc81SBart Van Assche seq_puts(m, "\n"); 10791d68905SBart Van Assche return 0; 10891d68905SBart Van Assche } 10991d68905SBart Van Assche 110f57de23aSOmar Sandoval static ssize_t queue_state_write(void *data, const char __user *buf, 111c7e4145aSOmar Sandoval size_t count, loff_t *ppos) 11291d68905SBart Van Assche { 113f57de23aSOmar Sandoval struct request_queue *q = data; 11471b90511SOmar Sandoval char opbuf[16] = { }, *op; 11591d68905SBart Van Assche 11618d4d7d0SBart Van Assche /* 1171f90307eSChristoph Hellwig * The "state" attribute is removed when the queue is removed. Don't 1181f90307eSChristoph Hellwig * allow setting the state on a dying queue to avoid a use-after-free. 11918d4d7d0SBart Van Assche */ 1201f90307eSChristoph Hellwig if (blk_queue_dying(q)) 12118d4d7d0SBart Van Assche return -ENOENT; 12218d4d7d0SBart Van Assche 12371b90511SOmar Sandoval if (count >= sizeof(opbuf)) { 124c7e4145aSOmar Sandoval pr_err("%s: operation too long\n", __func__); 125c7e4145aSOmar Sandoval goto inval; 126c7e4145aSOmar Sandoval } 127c7e4145aSOmar Sandoval 12871b90511SOmar Sandoval if (copy_from_user(opbuf, buf, count)) 12991d68905SBart Van Assche return -EFAULT; 13071b90511SOmar Sandoval op = strstrip(opbuf); 13191d68905SBart Van Assche if (strcmp(op, "run") == 0) { 13291d68905SBart Van Assche blk_mq_run_hw_queues(q, true); 13391d68905SBart Van Assche } else if (strcmp(op, "start") == 0) { 13491d68905SBart Van Assche blk_mq_start_stopped_hw_queues(q, true); 135edea55abSBart Van Assche } else if (strcmp(op, "kick") == 0) { 136edea55abSBart Van Assche blk_mq_kick_requeue_list(q); 13791d68905SBart Van Assche } else { 138c7e4145aSOmar Sandoval pr_err("%s: unsupported operation '%s'\n", __func__, op); 139c7e4145aSOmar Sandoval inval: 140edea55abSBart Van Assche pr_err("%s: use 'run', 'start' or 'kick'\n", __func__); 14191d68905SBart Van Assche return -EINVAL; 14291d68905SBart Van Assche } 143c7e4145aSOmar Sandoval return count; 14491d68905SBart Van Assche } 14591d68905SBart Van Assche 1461209cb7fSBart Van Assche static const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = { 1471209cb7fSBart Van Assche { "poll_stat", 0400, queue_poll_stat_show }, 1481209cb7fSBart Van Assche { "requeue_list", 0400, .seq_ops = &queue_requeue_list_seq_ops }, 149cd84a62eSBart Van Assche { "pm_only", 0600, queue_pm_only_show, NULL }, 1501209cb7fSBart Van Assche { "state", 0600, queue_state_show, queue_state_write }, 151a98b05b0SDamien Le Moal { "zone_wplugs", 0400, queue_zone_wplugs_show, NULL }, 1521209cb7fSBart Van Assche { }, 1531209cb7fSBart Van Assche }; 15434dbad5dSOmar Sandoval 1551a435111SOmar Sandoval #define HCTX_STATE_NAME(name) [BLK_MQ_S_##name] = #name 156f5c0b091SBart Van Assche static const char *const hctx_state_name[] = { 1571a435111SOmar Sandoval HCTX_STATE_NAME(STOPPED), 1581a435111SOmar Sandoval HCTX_STATE_NAME(TAG_ACTIVE), 1591a435111SOmar Sandoval HCTX_STATE_NAME(SCHED_RESTART), 160bf0beec0SMing Lei HCTX_STATE_NAME(INACTIVE), 161f5c0b091SBart Van Assche }; 1621a435111SOmar Sandoval #undef HCTX_STATE_NAME 1631a435111SOmar Sandoval 164f57de23aSOmar Sandoval static int hctx_state_show(void *data, struct seq_file *m) 1659abb2ad2SOmar Sandoval { 166f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 1679abb2ad2SOmar Sandoval 16823827310SJohn Garry BUILD_BUG_ON(ARRAY_SIZE(hctx_state_name) != BLK_MQ_S_MAX); 169f5c0b091SBart Van Assche blk_flags_show(m, hctx->state, hctx_state_name, 170f5c0b091SBart Van Assche ARRAY_SIZE(hctx_state_name)); 171fd07dc81SBart Van Assche seq_puts(m, "\n"); 1729abb2ad2SOmar Sandoval return 0; 1739abb2ad2SOmar Sandoval } 1749abb2ad2SOmar Sandoval 1751a435111SOmar Sandoval #define BLK_TAG_ALLOC_NAME(name) [BLK_TAG_ALLOC_##name] = #name 176f5c0b091SBart Van Assche static const char *const alloc_policy_name[] = { 1771a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(FIFO), 1781a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(RR), 179f5c0b091SBart Van Assche }; 1801a435111SOmar Sandoval #undef BLK_TAG_ALLOC_NAME 181f5c0b091SBart Van Assche 1821a435111SOmar Sandoval #define HCTX_FLAG_NAME(name) [ilog2(BLK_MQ_F_##name)] = #name 183f5c0b091SBart Van Assche static const char *const hctx_flag_name[] = { 1841a435111SOmar Sandoval HCTX_FLAG_NAME(SHOULD_MERGE), 18551db1c37SMing Lei HCTX_FLAG_NAME(TAG_QUEUE_SHARED), 186bf0beec0SMing Lei HCTX_FLAG_NAME(STACKING), 18702f938e9SJohn Garry HCTX_FLAG_NAME(TAG_HCTX_SHARED), 1881c83c537SJohn Garry HCTX_FLAG_NAME(BLOCKING), 1891c83c537SJohn Garry HCTX_FLAG_NAME(NO_SCHED), 1901c83c537SJohn Garry HCTX_FLAG_NAME(NO_SCHED_BY_DEFAULT), 191f5c0b091SBart Van Assche }; 1921a435111SOmar Sandoval #undef HCTX_FLAG_NAME 193f5c0b091SBart Van Assche 194f57de23aSOmar Sandoval static int hctx_flags_show(void *data, struct seq_file *m) 1959abb2ad2SOmar Sandoval { 196f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 197f5c0b091SBart Van Assche const int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(hctx->flags); 1989abb2ad2SOmar Sandoval 199226f0f6aSJohn Garry BUILD_BUG_ON(ARRAY_SIZE(hctx_flag_name) != 200226f0f6aSJohn Garry BLK_MQ_F_ALLOC_POLICY_START_BIT); 20126d3bdb5SJohn Garry BUILD_BUG_ON(ARRAY_SIZE(alloc_policy_name) != BLK_TAG_ALLOC_MAX); 202226f0f6aSJohn Garry 203f5c0b091SBart Van Assche seq_puts(m, "alloc_policy="); 204f5c0b091SBart Van Assche if (alloc_policy < ARRAY_SIZE(alloc_policy_name) && 205f5c0b091SBart Van Assche alloc_policy_name[alloc_policy]) 206f5c0b091SBart Van Assche seq_puts(m, alloc_policy_name[alloc_policy]); 207f5c0b091SBart Van Assche else 208f5c0b091SBart Van Assche seq_printf(m, "%d", alloc_policy); 209f5c0b091SBart Van Assche seq_puts(m, " "); 210f5c0b091SBart Van Assche blk_flags_show(m, 211f5c0b091SBart Van Assche hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy), 212f5c0b091SBart Van Assche hctx_flag_name, ARRAY_SIZE(hctx_flag_name)); 213fd07dc81SBart Van Assche seq_puts(m, "\n"); 2149abb2ad2SOmar Sandoval return 0; 2159abb2ad2SOmar Sandoval } 2169abb2ad2SOmar Sandoval 2171a435111SOmar Sandoval #define CMD_FLAG_NAME(name) [__REQ_##name] = #name 2188658dca8SBart Van Assche static const char *const cmd_flag_name[] = { 2191a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DEV), 2201a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_TRANSPORT), 2211a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DRIVER), 2221a435111SOmar Sandoval CMD_FLAG_NAME(SYNC), 2231a435111SOmar Sandoval CMD_FLAG_NAME(META), 2241a435111SOmar Sandoval CMD_FLAG_NAME(PRIO), 2251a435111SOmar Sandoval CMD_FLAG_NAME(NOMERGE), 2261a435111SOmar Sandoval CMD_FLAG_NAME(IDLE), 2271a435111SOmar Sandoval CMD_FLAG_NAME(INTEGRITY), 2281a435111SOmar Sandoval CMD_FLAG_NAME(FUA), 2291a435111SOmar Sandoval CMD_FLAG_NAME(PREFLUSH), 2301a435111SOmar Sandoval CMD_FLAG_NAME(RAHEAD), 2311a435111SOmar Sandoval CMD_FLAG_NAME(BACKGROUND), 23222d53821SBart Van Assche CMD_FLAG_NAME(NOWAIT), 2336ce913feSChristoph Hellwig CMD_FLAG_NAME(POLLED), 2346b3789e6SJohn Garry CMD_FLAG_NAME(ALLOC_CACHE), 2356b3789e6SJohn Garry CMD_FLAG_NAME(SWAP), 2366b3789e6SJohn Garry CMD_FLAG_NAME(DRV), 2376b3789e6SJohn Garry CMD_FLAG_NAME(FS_PRIVATE), 2386b3789e6SJohn Garry CMD_FLAG_NAME(ATOMIC), 2396b3789e6SJohn Garry CMD_FLAG_NAME(NOUNMAP), 2408658dca8SBart Van Assche }; 2411a435111SOmar Sandoval #undef CMD_FLAG_NAME 2428658dca8SBart Van Assche 2431a435111SOmar Sandoval #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name 2448658dca8SBart Van Assche static const char *const rqf_name[] = { 24585ba3effSJens Axboe RQF_NAME(STARTED), 2461a435111SOmar Sandoval RQF_NAME(FLUSH_SEQ), 2471a435111SOmar Sandoval RQF_NAME(MIXED_MERGE), 2481a435111SOmar Sandoval RQF_NAME(DONTPREP), 249dd6216bbSChristoph Hellwig RQF_NAME(SCHED_TAGS), 250dd6216bbSChristoph Hellwig RQF_NAME(USE_SCHED), 2511a435111SOmar Sandoval RQF_NAME(FAILED), 2521a435111SOmar Sandoval RQF_NAME(QUIET), 2531a435111SOmar Sandoval RQF_NAME(IO_STAT), 2541a435111SOmar Sandoval RQF_NAME(PM), 2551a435111SOmar Sandoval RQF_NAME(HASHED), 2561a435111SOmar Sandoval RQF_NAME(STATS), 2571a435111SOmar Sandoval RQF_NAME(SPECIAL_PAYLOAD), 258af54963fSJohn Garry RQF_NAME(ZONE_WRITE_PLUGGING), 259745ed372SJens Axboe RQF_NAME(TIMED_OUT), 260745ed372SJens Axboe RQF_NAME(RESV), 2618658dca8SBart Van Assche }; 2621a435111SOmar Sandoval #undef RQF_NAME 2638658dca8SBart Van Assche 264ec6dcf63SBart Van Assche static const char *const blk_mq_rq_state_name_array[] = { 265ec6dcf63SBart Van Assche [MQ_RQ_IDLE] = "idle", 266ec6dcf63SBart Van Assche [MQ_RQ_IN_FLIGHT] = "in_flight", 267ec6dcf63SBart Van Assche [MQ_RQ_COMPLETE] = "complete", 268ec6dcf63SBart Van Assche }; 269ec6dcf63SBart Van Assche 270ec6dcf63SBart Van Assche static const char *blk_mq_rq_state_name(enum mq_rq_state rq_state) 271ec6dcf63SBart Van Assche { 272a1e79188SDan Carpenter if (WARN_ON_ONCE((unsigned int)rq_state >= 273ec6dcf63SBart Van Assche ARRAY_SIZE(blk_mq_rq_state_name_array))) 274ec6dcf63SBart Van Assche return "(?)"; 275ec6dcf63SBart Van Assche return blk_mq_rq_state_name_array[rq_state]; 276ec6dcf63SBart Van Assche } 277ec6dcf63SBart Van Assche 278daaadb3eSOmar Sandoval int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq) 279950cd7e9SOmar Sandoval { 2802836ee4bSBart Van Assche const struct blk_mq_ops *const mq_ops = rq->q->mq_ops; 28177e7ffd7SBart Van Assche const enum req_op op = req_op(rq); 282874c893bSChaitanya Kulkarni const char *op_str = blk_op_str(op); 283950cd7e9SOmar Sandoval 284*6fa99325SJohn Garry BUILD_BUG_ON(ARRAY_SIZE(cmd_flag_name) != __REQ_NR_BITS); 285*6fa99325SJohn Garry 2868658dca8SBart Van Assche seq_printf(m, "%p {.op=", rq); 287874c893bSChaitanya Kulkarni if (strcmp(op_str, "UNKNOWN") == 0) 2883f6d385fSChaitanya Kulkarni seq_printf(m, "%u", op); 2898658dca8SBart Van Assche else 290874c893bSChaitanya Kulkarni seq_printf(m, "%s", op_str); 2918658dca8SBart Van Assche seq_puts(m, ", .cmd_flags="); 29216458cf3SBart Van Assche blk_flags_show(m, (__force unsigned int)(rq->cmd_flags & ~REQ_OP_MASK), 29316458cf3SBart Van Assche cmd_flag_name, ARRAY_SIZE(cmd_flag_name)); 2948658dca8SBart Van Assche seq_puts(m, ", .rq_flags="); 2958658dca8SBart Van Assche blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name, 2968658dca8SBart Van Assche ARRAY_SIZE(rqf_name)); 297ec6dcf63SBart Van Assche seq_printf(m, ", .state=%s", blk_mq_rq_state_name(blk_mq_rq_state(rq))); 2982836ee4bSBart Van Assche seq_printf(m, ", .tag=%d, .internal_tag=%d", rq->tag, 2998658dca8SBart Van Assche rq->internal_tag); 3002836ee4bSBart Van Assche if (mq_ops->show_rq) 3012836ee4bSBart Van Assche mq_ops->show_rq(m, rq); 3022836ee4bSBart Van Assche seq_puts(m, "}\n"); 303950cd7e9SOmar Sandoval return 0; 304950cd7e9SOmar Sandoval } 305daaadb3eSOmar Sandoval EXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show); 306daaadb3eSOmar Sandoval 307daaadb3eSOmar Sandoval int blk_mq_debugfs_rq_show(struct seq_file *m, void *v) 308daaadb3eSOmar Sandoval { 309daaadb3eSOmar Sandoval return __blk_mq_debugfs_rq_show(m, list_entry_rq(v)); 310daaadb3eSOmar Sandoval } 31116b738f6SOmar Sandoval EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show); 312950cd7e9SOmar Sandoval 313950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos) 314f3bcb0e6SBart Van Assche __acquires(&hctx->lock) 315950cd7e9SOmar Sandoval { 316950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 317950cd7e9SOmar Sandoval 318950cd7e9SOmar Sandoval spin_lock(&hctx->lock); 319950cd7e9SOmar Sandoval return seq_list_start(&hctx->dispatch, *pos); 320950cd7e9SOmar Sandoval } 321950cd7e9SOmar Sandoval 322950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos) 323950cd7e9SOmar Sandoval { 324950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 325950cd7e9SOmar Sandoval 326950cd7e9SOmar Sandoval return seq_list_next(v, &hctx->dispatch, pos); 327950cd7e9SOmar Sandoval } 328950cd7e9SOmar Sandoval 329950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v) 330f3bcb0e6SBart Van Assche __releases(&hctx->lock) 331950cd7e9SOmar Sandoval { 332950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 333950cd7e9SOmar Sandoval 334950cd7e9SOmar Sandoval spin_unlock(&hctx->lock); 335950cd7e9SOmar Sandoval } 336950cd7e9SOmar Sandoval 337950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = { 338950cd7e9SOmar Sandoval .start = hctx_dispatch_start, 339950cd7e9SOmar Sandoval .next = hctx_dispatch_next, 340950cd7e9SOmar Sandoval .stop = hctx_dispatch_stop, 341950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 342950cd7e9SOmar Sandoval }; 343950cd7e9SOmar Sandoval 3442720bab5SBart Van Assche struct show_busy_params { 3452720bab5SBart Van Assche struct seq_file *m; 3462720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx; 3472720bab5SBart Van Assche }; 3482720bab5SBart Van Assche 3492720bab5SBart Van Assche /* 3502720bab5SBart Van Assche * Note: the state of a request may change while this function is in progress, 3517baa8572SJens Axboe * e.g. due to a concurrent blk_mq_finish_request() call. Returns true to 3527baa8572SJens Axboe * keep iterating requests. 3532720bab5SBart Van Assche */ 3542dd6532eSJohn Garry static bool hctx_show_busy_rq(struct request *rq, void *data) 3552720bab5SBart Van Assche { 3562720bab5SBart Van Assche const struct show_busy_params *params = data; 3572720bab5SBart Van Assche 358ea4f995eSJens Axboe if (rq->mq_hctx == params->hctx) 359b5fc1e8bSHou Tao __blk_mq_debugfs_rq_show(params->m, rq); 3607baa8572SJens Axboe 3617baa8572SJens Axboe return true; 3622720bab5SBart Van Assche } 3632720bab5SBart Van Assche 3642720bab5SBart Van Assche static int hctx_busy_show(void *data, struct seq_file *m) 3652720bab5SBart Van Assche { 3662720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx = data; 3672720bab5SBart Van Assche struct show_busy_params params = { .m = m, .hctx = hctx }; 3682720bab5SBart Van Assche 3692720bab5SBart Van Assche blk_mq_tagset_busy_iter(hctx->queue->tag_set, hctx_show_busy_rq, 3702720bab5SBart Van Assche ¶ms); 3712720bab5SBart Van Assche 3722720bab5SBart Van Assche return 0; 3732720bab5SBart Van Assche } 3742720bab5SBart Van Assche 375346fc108SMing Lei static const char *const hctx_types[] = { 376346fc108SMing Lei [HCTX_TYPE_DEFAULT] = "default", 377346fc108SMing Lei [HCTX_TYPE_READ] = "read", 378346fc108SMing Lei [HCTX_TYPE_POLL] = "poll", 379346fc108SMing Lei }; 380346fc108SMing Lei 381346fc108SMing Lei static int hctx_type_show(void *data, struct seq_file *m) 382346fc108SMing Lei { 383346fc108SMing Lei struct blk_mq_hw_ctx *hctx = data; 384346fc108SMing Lei 385346fc108SMing Lei BUILD_BUG_ON(ARRAY_SIZE(hctx_types) != HCTX_MAX_TYPES); 386346fc108SMing Lei seq_printf(m, "%s\n", hctx_types[hctx->type]); 387346fc108SMing Lei return 0; 388346fc108SMing Lei } 389346fc108SMing Lei 390f57de23aSOmar Sandoval static int hctx_ctx_map_show(void *data, struct seq_file *m) 391950cd7e9SOmar Sandoval { 392f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 3930bfa5288SOmar Sandoval 3940bfa5288SOmar Sandoval sbitmap_bitmap_show(&hctx->ctx_map, m); 3950bfa5288SOmar Sandoval return 0; 3960bfa5288SOmar Sandoval } 3970bfa5288SOmar Sandoval 398d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m, 399d96b37c0SOmar Sandoval struct blk_mq_tags *tags) 400d96b37c0SOmar Sandoval { 401d96b37c0SOmar Sandoval seq_printf(m, "nr_tags=%u\n", tags->nr_tags); 402d96b37c0SOmar Sandoval seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags); 403d96b37c0SOmar Sandoval seq_printf(m, "active_queues=%d\n", 4044f1731dfSYu Kuai READ_ONCE(tags->active_queues)); 405d96b37c0SOmar Sandoval 406d96b37c0SOmar Sandoval seq_puts(m, "\nbitmap_tags:\n"); 407ae0f1a73SJohn Garry sbitmap_queue_show(&tags->bitmap_tags, m); 408d96b37c0SOmar Sandoval 409d96b37c0SOmar Sandoval if (tags->nr_reserved_tags) { 410d96b37c0SOmar Sandoval seq_puts(m, "\nbreserved_tags:\n"); 411ae0f1a73SJohn Garry sbitmap_queue_show(&tags->breserved_tags, m); 412d96b37c0SOmar Sandoval } 413d96b37c0SOmar Sandoval } 414d96b37c0SOmar Sandoval 415f57de23aSOmar Sandoval static int hctx_tags_show(void *data, struct seq_file *m) 416d96b37c0SOmar Sandoval { 417f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 418d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 4198c0f14eaSBart Van Assche int res; 420d96b37c0SOmar Sandoval 4218c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4228c0f14eaSBart Van Assche if (res) 4238c0f14eaSBart Van Assche goto out; 424d96b37c0SOmar Sandoval if (hctx->tags) 425d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->tags); 426d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 427d96b37c0SOmar Sandoval 4288c0f14eaSBart Van Assche out: 4298c0f14eaSBart Van Assche return res; 430d96b37c0SOmar Sandoval } 431d96b37c0SOmar Sandoval 432f57de23aSOmar Sandoval static int hctx_tags_bitmap_show(void *data, struct seq_file *m) 433d96b37c0SOmar Sandoval { 434f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 435d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 4368c0f14eaSBart Van Assche int res; 437d7e3621aSOmar Sandoval 4388c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4398c0f14eaSBart Van Assche if (res) 4408c0f14eaSBart Van Assche goto out; 441d7e3621aSOmar Sandoval if (hctx->tags) 442ae0f1a73SJohn Garry sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m); 443d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 4448c0f14eaSBart Van Assche 4458c0f14eaSBart Van Assche out: 4468c0f14eaSBart Van Assche return res; 447d7e3621aSOmar Sandoval } 448d7e3621aSOmar Sandoval 449f57de23aSOmar Sandoval static int hctx_sched_tags_show(void *data, struct seq_file *m) 450d7e3621aSOmar Sandoval { 451f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 452d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 4538c0f14eaSBart Van Assche int res; 454d96b37c0SOmar Sandoval 4558c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4568c0f14eaSBart Van Assche if (res) 4578c0f14eaSBart Van Assche goto out; 458d96b37c0SOmar Sandoval if (hctx->sched_tags) 459d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->sched_tags); 460d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 461d96b37c0SOmar Sandoval 4628c0f14eaSBart Van Assche out: 4638c0f14eaSBart Van Assche return res; 464d96b37c0SOmar Sandoval } 465d96b37c0SOmar Sandoval 466f57de23aSOmar Sandoval static int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m) 467d96b37c0SOmar Sandoval { 468f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 469d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 4708c0f14eaSBart Van Assche int res; 471d7e3621aSOmar Sandoval 4728c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4738c0f14eaSBart Van Assche if (res) 4748c0f14eaSBart Van Assche goto out; 475d7e3621aSOmar Sandoval if (hctx->sched_tags) 476ae0f1a73SJohn Garry sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m); 477d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 4788c0f14eaSBart Van Assche 4798c0f14eaSBart Van Assche out: 4808c0f14eaSBart Van Assche return res; 481d7e3621aSOmar Sandoval } 482d7e3621aSOmar Sandoval 483f57de23aSOmar Sandoval static int hctx_active_show(void *data, struct seq_file *m) 4844a46f05eSOmar Sandoval { 485f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 4864a46f05eSOmar Sandoval 4879b84c629SJohn Garry seq_printf(m, "%d\n", __blk_mq_active_requests(hctx)); 4884a46f05eSOmar Sandoval return 0; 4894a46f05eSOmar Sandoval } 4904a46f05eSOmar Sandoval 4916e768717SMing Lei static int hctx_dispatch_busy_show(void *data, struct seq_file *m) 4926e768717SMing Lei { 4936e768717SMing Lei struct blk_mq_hw_ctx *hctx = data; 4946e768717SMing Lei 4956e768717SMing Lei seq_printf(m, "%u\n", hctx->dispatch_busy); 4966e768717SMing Lei return 0; 4976e768717SMing Lei } 4986e768717SMing Lei 499c16d6b5aSMing Lei #define CTX_RQ_SEQ_OPS(name, type) \ 500c16d6b5aSMing Lei static void *ctx_##name##_rq_list_start(struct seq_file *m, loff_t *pos) \ 501c16d6b5aSMing Lei __acquires(&ctx->lock) \ 502c16d6b5aSMing Lei { \ 503c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 504c16d6b5aSMing Lei \ 505c16d6b5aSMing Lei spin_lock(&ctx->lock); \ 506c16d6b5aSMing Lei return seq_list_start(&ctx->rq_lists[type], *pos); \ 507c16d6b5aSMing Lei } \ 508c16d6b5aSMing Lei \ 509c16d6b5aSMing Lei static void *ctx_##name##_rq_list_next(struct seq_file *m, void *v, \ 510c16d6b5aSMing Lei loff_t *pos) \ 511c16d6b5aSMing Lei { \ 512c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 513c16d6b5aSMing Lei \ 514c16d6b5aSMing Lei return seq_list_next(v, &ctx->rq_lists[type], pos); \ 515c16d6b5aSMing Lei } \ 516c16d6b5aSMing Lei \ 517c16d6b5aSMing Lei static void ctx_##name##_rq_list_stop(struct seq_file *m, void *v) \ 518c16d6b5aSMing Lei __releases(&ctx->lock) \ 519c16d6b5aSMing Lei { \ 520c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 521c16d6b5aSMing Lei \ 522c16d6b5aSMing Lei spin_unlock(&ctx->lock); \ 523c16d6b5aSMing Lei } \ 524c16d6b5aSMing Lei \ 525c16d6b5aSMing Lei static const struct seq_operations ctx_##name##_rq_list_seq_ops = { \ 526c16d6b5aSMing Lei .start = ctx_##name##_rq_list_start, \ 527c16d6b5aSMing Lei .next = ctx_##name##_rq_list_next, \ 528c16d6b5aSMing Lei .stop = ctx_##name##_rq_list_stop, \ 529c16d6b5aSMing Lei .show = blk_mq_debugfs_rq_show, \ 530950cd7e9SOmar Sandoval } 531950cd7e9SOmar Sandoval 532c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(default, HCTX_TYPE_DEFAULT); 533c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(read, HCTX_TYPE_READ); 534c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(poll, HCTX_TYPE_POLL); 535950cd7e9SOmar Sandoval 536f57de23aSOmar Sandoval static int blk_mq_debugfs_show(struct seq_file *m, void *v) 537f57de23aSOmar Sandoval { 538f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 539f57de23aSOmar Sandoval void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private; 540f57de23aSOmar Sandoval 541f57de23aSOmar Sandoval return attr->show(data, m); 542f57de23aSOmar Sandoval } 543f57de23aSOmar Sandoval 544f57de23aSOmar Sandoval static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf, 545f57de23aSOmar Sandoval size_t count, loff_t *ppos) 546f57de23aSOmar Sandoval { 547f57de23aSOmar Sandoval struct seq_file *m = file->private_data; 548f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 549f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 550f57de23aSOmar Sandoval 5516b136a24SEryu Guan /* 5526b136a24SEryu Guan * Attributes that only implement .seq_ops are read-only and 'attr' is 5536b136a24SEryu Guan * the same with 'data' in this case. 5546b136a24SEryu Guan */ 5556b136a24SEryu Guan if (attr == data || !attr->write) 556f57de23aSOmar Sandoval return -EPERM; 557f57de23aSOmar Sandoval 558f57de23aSOmar Sandoval return attr->write(data, buf, count, ppos); 559f57de23aSOmar Sandoval } 560f57de23aSOmar Sandoval 561f57de23aSOmar Sandoval static int blk_mq_debugfs_open(struct inode *inode, struct file *file) 562f57de23aSOmar Sandoval { 563f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 564f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 565f57de23aSOmar Sandoval struct seq_file *m; 566f57de23aSOmar Sandoval int ret; 567f57de23aSOmar Sandoval 568f57de23aSOmar Sandoval if (attr->seq_ops) { 569f57de23aSOmar Sandoval ret = seq_open(file, attr->seq_ops); 570f57de23aSOmar Sandoval if (!ret) { 571f57de23aSOmar Sandoval m = file->private_data; 572f57de23aSOmar Sandoval m->private = data; 573f57de23aSOmar Sandoval } 574f57de23aSOmar Sandoval return ret; 575f57de23aSOmar Sandoval } 576f57de23aSOmar Sandoval 577f57de23aSOmar Sandoval if (WARN_ON_ONCE(!attr->show)) 578f57de23aSOmar Sandoval return -EPERM; 579f57de23aSOmar Sandoval 580f57de23aSOmar Sandoval return single_open(file, blk_mq_debugfs_show, inode->i_private); 581f57de23aSOmar Sandoval } 582f57de23aSOmar Sandoval 583f57de23aSOmar Sandoval static int blk_mq_debugfs_release(struct inode *inode, struct file *file) 584f57de23aSOmar Sandoval { 585f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 586f57de23aSOmar Sandoval 587f57de23aSOmar Sandoval if (attr->show) 588f57de23aSOmar Sandoval return single_release(inode, file); 589ee1e0359SChaitanya Kulkarni 590f57de23aSOmar Sandoval return seq_release(inode, file); 591f57de23aSOmar Sandoval } 592f57de23aSOmar Sandoval 593f8465933SBart Van Assche static const struct file_operations blk_mq_debugfs_fops = { 594f57de23aSOmar Sandoval .open = blk_mq_debugfs_open, 5954a46f05eSOmar Sandoval .read = seq_read, 596f57de23aSOmar Sandoval .write = blk_mq_debugfs_write, 5974a46f05eSOmar Sandoval .llseek = seq_lseek, 598f57de23aSOmar Sandoval .release = blk_mq_debugfs_release, 5994a46f05eSOmar Sandoval }; 6004a46f05eSOmar Sandoval 60107e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { 602f57de23aSOmar Sandoval {"state", 0400, hctx_state_show}, 603f57de23aSOmar Sandoval {"flags", 0400, hctx_flags_show}, 604f57de23aSOmar Sandoval {"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops}, 6052720bab5SBart Van Assche {"busy", 0400, hctx_busy_show}, 606f57de23aSOmar Sandoval {"ctx_map", 0400, hctx_ctx_map_show}, 607f57de23aSOmar Sandoval {"tags", 0400, hctx_tags_show}, 608f57de23aSOmar Sandoval {"tags_bitmap", 0400, hctx_tags_bitmap_show}, 609f57de23aSOmar Sandoval {"sched_tags", 0400, hctx_sched_tags_show}, 610f57de23aSOmar Sandoval {"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show}, 611f57de23aSOmar Sandoval {"active", 0400, hctx_active_show}, 6126e768717SMing Lei {"dispatch_busy", 0400, hctx_dispatch_busy_show}, 613346fc108SMing Lei {"type", 0400, hctx_type_show}, 61472f2f8f6SBart Van Assche {}, 61507e4feadSOmar Sandoval }; 61607e4feadSOmar Sandoval 61707e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = { 618c16d6b5aSMing Lei {"default_rq_list", 0400, .seq_ops = &ctx_default_rq_list_seq_ops}, 619c16d6b5aSMing Lei {"read_rq_list", 0400, .seq_ops = &ctx_read_rq_list_seq_ops}, 620c16d6b5aSMing Lei {"poll_rq_list", 0400, .seq_ops = &ctx_poll_rq_list_seq_ops}, 62172f2f8f6SBart Van Assche {}, 62207e4feadSOmar Sandoval }; 62307e4feadSOmar Sandoval 6246cfc0081SGreg Kroah-Hartman static void debugfs_create_files(struct dentry *parent, void *data, 62572f2f8f6SBart Van Assche const struct blk_mq_debugfs_attr *attr) 62672f2f8f6SBart Van Assche { 62736991ca6SGreg Kroah-Hartman if (IS_ERR_OR_NULL(parent)) 6286cfc0081SGreg Kroah-Hartman return; 62936991ca6SGreg Kroah-Hartman 630f57de23aSOmar Sandoval d_inode(parent)->i_private = data; 631f57de23aSOmar Sandoval 6326cfc0081SGreg Kroah-Hartman for (; attr->name; attr++) 6336cfc0081SGreg Kroah-Hartman debugfs_create_file(attr->name, attr->mode, parent, 6346cfc0081SGreg Kroah-Hartman (void *)attr, &blk_mq_debugfs_fops); 63572f2f8f6SBart Van Assche } 63672f2f8f6SBart Van Assche 6376cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register(struct request_queue *q) 6389c1051aaSOmar Sandoval { 6399c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 6404f481208SMing Lei unsigned long i; 6419c1051aaSOmar Sandoval 6426cfc0081SGreg Kroah-Hartman debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs); 6439c1051aaSOmar Sandoval 6449c1051aaSOmar Sandoval /* 64570e62f4bSOmar Sandoval * blk_mq_init_sched() attempted to do this already, but q->debugfs_dir 6469c1051aaSOmar Sandoval * didn't exist yet (because we don't know what to name the directory 6479c1051aaSOmar Sandoval * until the queue is registered to a gendisk). 6489c1051aaSOmar Sandoval */ 64970e62f4bSOmar Sandoval if (q->elevator && !q->sched_debugfs_dir) 65070e62f4bSOmar Sandoval blk_mq_debugfs_register_sched(q); 65170e62f4bSOmar Sandoval 65270e62f4bSOmar Sandoval /* Similarly, blk_mq_init_hctx() couldn't do this previously. */ 6539c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) { 6546cfc0081SGreg Kroah-Hartman if (!hctx->debugfs_dir) 6556cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_hctx(q, hctx); 6566cfc0081SGreg Kroah-Hartman if (q->elevator && !hctx->sched_debugfs_dir) 6576cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_sched_hctx(q, hctx); 6589c1051aaSOmar Sandoval } 6599c1051aaSOmar Sandoval 660cc56694fSMing Lei if (q->rq_qos) { 661cc56694fSMing Lei struct rq_qos *rqos = q->rq_qos; 662cc56694fSMing Lei 663cc56694fSMing Lei while (rqos) { 664cc56694fSMing Lei blk_mq_debugfs_register_rqos(rqos); 665cc56694fSMing Lei rqos = rqos->next; 666cc56694fSMing Lei } 667cc56694fSMing Lei } 6689c1051aaSOmar Sandoval } 6699c1051aaSOmar Sandoval 6706cfc0081SGreg Kroah-Hartman static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx, 6719c1051aaSOmar Sandoval struct blk_mq_ctx *ctx) 67207e4feadSOmar Sandoval { 67307e4feadSOmar Sandoval struct dentry *ctx_dir; 67407e4feadSOmar Sandoval char name[20]; 67507e4feadSOmar Sandoval 67607e4feadSOmar Sandoval snprintf(name, sizeof(name), "cpu%u", ctx->cpu); 6779c1051aaSOmar Sandoval ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir); 67807e4feadSOmar Sandoval 6796cfc0081SGreg Kroah-Hartman debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs); 68007e4feadSOmar Sandoval } 68107e4feadSOmar Sandoval 6826cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_hctx(struct request_queue *q, 68307e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx) 68407e4feadSOmar Sandoval { 68507e4feadSOmar Sandoval struct blk_mq_ctx *ctx; 68607e4feadSOmar Sandoval char name[20]; 68707e4feadSOmar Sandoval int i; 68807e4feadSOmar Sandoval 689f3ec5d11SMing Lei if (!q->debugfs_dir) 690f3ec5d11SMing Lei return; 691f3ec5d11SMing Lei 6929c1051aaSOmar Sandoval snprintf(name, sizeof(name), "hctx%u", hctx->queue_num); 6939c1051aaSOmar Sandoval hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir); 6949c1051aaSOmar Sandoval 6956cfc0081SGreg Kroah-Hartman debugfs_create_files(hctx->debugfs_dir, hctx, blk_mq_debugfs_hctx_attrs); 69607e4feadSOmar Sandoval 6976cfc0081SGreg Kroah-Hartman hctx_for_each_ctx(hctx, ctx, i) 6986cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_ctx(hctx, ctx); 69907e4feadSOmar Sandoval } 70007e4feadSOmar Sandoval 7019c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx) 70207e4feadSOmar Sandoval { 7035cf9c91bSChristoph Hellwig if (!hctx->queue->debugfs_dir) 7045cf9c91bSChristoph Hellwig return; 7059c1051aaSOmar Sandoval debugfs_remove_recursive(hctx->debugfs_dir); 706d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 7079c1051aaSOmar Sandoval hctx->debugfs_dir = NULL; 7089c1051aaSOmar Sandoval } 7099c1051aaSOmar Sandoval 7106cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_hctxs(struct request_queue *q) 7119c1051aaSOmar Sandoval { 7129c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 7134f481208SMing Lei unsigned long i; 7149c1051aaSOmar Sandoval 7156cfc0081SGreg Kroah-Hartman queue_for_each_hw_ctx(q, hctx, i) 7166cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_hctx(q, hctx); 7179c1051aaSOmar Sandoval } 7189c1051aaSOmar Sandoval 7199c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q) 7209c1051aaSOmar Sandoval { 7219c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 7224f481208SMing Lei unsigned long i; 7239c1051aaSOmar Sandoval 7249c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) 7259c1051aaSOmar Sandoval blk_mq_debugfs_unregister_hctx(hctx); 72607e4feadSOmar Sandoval } 727d332ce09SOmar Sandoval 7286cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_sched(struct request_queue *q) 729d332ce09SOmar Sandoval { 730d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 731d332ce09SOmar Sandoval 7325cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 7335cf9c91bSChristoph Hellwig 7347e41c3c9SGreg Kroah-Hartman /* 7357e41c3c9SGreg Kroah-Hartman * If the parent directory has not been created yet, return, we will be 7367e41c3c9SGreg Kroah-Hartman * called again later on and the directory/files will be created then. 7377e41c3c9SGreg Kroah-Hartman */ 7387e41c3c9SGreg Kroah-Hartman if (!q->debugfs_dir) 7397e41c3c9SGreg Kroah-Hartman return; 7407e41c3c9SGreg Kroah-Hartman 741d332ce09SOmar Sandoval if (!e->queue_debugfs_attrs) 7426cfc0081SGreg Kroah-Hartman return; 743d332ce09SOmar Sandoval 744d332ce09SOmar Sandoval q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir); 745d332ce09SOmar Sandoval 7466cfc0081SGreg Kroah-Hartman debugfs_create_files(q->sched_debugfs_dir, q, e->queue_debugfs_attrs); 747d332ce09SOmar Sandoval } 748d332ce09SOmar Sandoval 749d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched(struct request_queue *q) 750d332ce09SOmar Sandoval { 7515cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 7525cf9c91bSChristoph Hellwig 753d332ce09SOmar Sandoval debugfs_remove_recursive(q->sched_debugfs_dir); 754d332ce09SOmar Sandoval q->sched_debugfs_dir = NULL; 755d332ce09SOmar Sandoval } 756d332ce09SOmar Sandoval 757fb44023eSBart Van Assche static const char *rq_qos_id_to_name(enum rq_qos_id id) 758fb44023eSBart Van Assche { 759fb44023eSBart Van Assche switch (id) { 760fb44023eSBart Van Assche case RQ_QOS_WBT: 761fb44023eSBart Van Assche return "wbt"; 762fb44023eSBart Van Assche case RQ_QOS_LATENCY: 763fb44023eSBart Van Assche return "latency"; 764fb44023eSBart Van Assche case RQ_QOS_COST: 765fb44023eSBart Van Assche return "cost"; 766fb44023eSBart Van Assche } 767fb44023eSBart Van Assche return "unknown"; 768fb44023eSBart Van Assche } 769fb44023eSBart Van Assche 770cc56694fSMing Lei void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos) 771cc56694fSMing Lei { 772ba91c849SChristoph Hellwig lockdep_assert_held(&rqos->disk->queue->debugfs_mutex); 7735cf9c91bSChristoph Hellwig 774ba91c849SChristoph Hellwig if (!rqos->disk->queue->debugfs_dir) 7755cf9c91bSChristoph Hellwig return; 776cc56694fSMing Lei debugfs_remove_recursive(rqos->debugfs_dir); 777cc56694fSMing Lei rqos->debugfs_dir = NULL; 778cc56694fSMing Lei } 779cc56694fSMing Lei 7806cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_rqos(struct rq_qos *rqos) 781cc56694fSMing Lei { 782ba91c849SChristoph Hellwig struct request_queue *q = rqos->disk->queue; 783cc56694fSMing Lei const char *dir_name = rq_qos_id_to_name(rqos->id); 784cc56694fSMing Lei 7855cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 7865cf9c91bSChristoph Hellwig 787cc56694fSMing Lei if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs) 7886cfc0081SGreg Kroah-Hartman return; 789cc56694fSMing Lei 7906cfc0081SGreg Kroah-Hartman if (!q->rqos_debugfs_dir) 791cc56694fSMing Lei q->rqos_debugfs_dir = debugfs_create_dir("rqos", 792cc56694fSMing Lei q->debugfs_dir); 793cc56694fSMing Lei 794ba91c849SChristoph Hellwig rqos->debugfs_dir = debugfs_create_dir(dir_name, q->rqos_debugfs_dir); 7956cfc0081SGreg Kroah-Hartman debugfs_create_files(rqos->debugfs_dir, rqos, rqos->ops->debugfs_attrs); 796cc56694fSMing Lei } 797cc56694fSMing Lei 7986cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_sched_hctx(struct request_queue *q, 799d332ce09SOmar Sandoval struct blk_mq_hw_ctx *hctx) 800d332ce09SOmar Sandoval { 801d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 802d332ce09SOmar Sandoval 8035cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 8045cf9c91bSChristoph Hellwig 8051e91e28eSSaravanan D /* 8061e91e28eSSaravanan D * If the parent debugfs directory has not been created yet, return; 8071e91e28eSSaravanan D * We will be called again later on with appropriate parent debugfs 8081e91e28eSSaravanan D * directory from blk_register_queue() 8091e91e28eSSaravanan D */ 8101e91e28eSSaravanan D if (!hctx->debugfs_dir) 8111e91e28eSSaravanan D return; 8121e91e28eSSaravanan D 813d332ce09SOmar Sandoval if (!e->hctx_debugfs_attrs) 8146cfc0081SGreg Kroah-Hartman return; 815d332ce09SOmar Sandoval 816d332ce09SOmar Sandoval hctx->sched_debugfs_dir = debugfs_create_dir("sched", 817d332ce09SOmar Sandoval hctx->debugfs_dir); 8186cfc0081SGreg Kroah-Hartman debugfs_create_files(hctx->sched_debugfs_dir, hctx, 8196cfc0081SGreg Kroah-Hartman e->hctx_debugfs_attrs); 820d332ce09SOmar Sandoval } 821d332ce09SOmar Sandoval 822d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx) 823d332ce09SOmar Sandoval { 8245cf9c91bSChristoph Hellwig lockdep_assert_held(&hctx->queue->debugfs_mutex); 8255cf9c91bSChristoph Hellwig 8265cf9c91bSChristoph Hellwig if (!hctx->queue->debugfs_dir) 8275cf9c91bSChristoph Hellwig return; 828d332ce09SOmar Sandoval debugfs_remove_recursive(hctx->sched_debugfs_dir); 829d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 830d332ce09SOmar Sandoval } 831