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 168*23827310SJohn 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 199f5c0b091SBart Van Assche seq_puts(m, "alloc_policy="); 200f5c0b091SBart Van Assche if (alloc_policy < ARRAY_SIZE(alloc_policy_name) && 201f5c0b091SBart Van Assche alloc_policy_name[alloc_policy]) 202f5c0b091SBart Van Assche seq_puts(m, alloc_policy_name[alloc_policy]); 203f5c0b091SBart Van Assche else 204f5c0b091SBart Van Assche seq_printf(m, "%d", alloc_policy); 205f5c0b091SBart Van Assche seq_puts(m, " "); 206f5c0b091SBart Van Assche blk_flags_show(m, 207f5c0b091SBart Van Assche hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy), 208f5c0b091SBart Van Assche hctx_flag_name, ARRAY_SIZE(hctx_flag_name)); 209fd07dc81SBart Van Assche seq_puts(m, "\n"); 2109abb2ad2SOmar Sandoval return 0; 2119abb2ad2SOmar Sandoval } 2129abb2ad2SOmar Sandoval 2131a435111SOmar Sandoval #define CMD_FLAG_NAME(name) [__REQ_##name] = #name 2148658dca8SBart Van Assche static const char *const cmd_flag_name[] = { 2151a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DEV), 2161a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_TRANSPORT), 2171a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DRIVER), 2181a435111SOmar Sandoval CMD_FLAG_NAME(SYNC), 2191a435111SOmar Sandoval CMD_FLAG_NAME(META), 2201a435111SOmar Sandoval CMD_FLAG_NAME(PRIO), 2211a435111SOmar Sandoval CMD_FLAG_NAME(NOMERGE), 2221a435111SOmar Sandoval CMD_FLAG_NAME(IDLE), 2231a435111SOmar Sandoval CMD_FLAG_NAME(INTEGRITY), 2241a435111SOmar Sandoval CMD_FLAG_NAME(FUA), 2251a435111SOmar Sandoval CMD_FLAG_NAME(PREFLUSH), 2261a435111SOmar Sandoval CMD_FLAG_NAME(RAHEAD), 2271a435111SOmar Sandoval CMD_FLAG_NAME(BACKGROUND), 22822d53821SBart Van Assche CMD_FLAG_NAME(NOWAIT), 2296ce913feSChristoph Hellwig CMD_FLAG_NAME(POLLED), 2306b3789e6SJohn Garry CMD_FLAG_NAME(ALLOC_CACHE), 2316b3789e6SJohn Garry CMD_FLAG_NAME(SWAP), 2326b3789e6SJohn Garry CMD_FLAG_NAME(DRV), 2336b3789e6SJohn Garry CMD_FLAG_NAME(FS_PRIVATE), 2346b3789e6SJohn Garry CMD_FLAG_NAME(ATOMIC), 2356b3789e6SJohn Garry CMD_FLAG_NAME(NOUNMAP), 2368658dca8SBart Van Assche }; 2371a435111SOmar Sandoval #undef CMD_FLAG_NAME 2388658dca8SBart Van Assche 2391a435111SOmar Sandoval #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name 2408658dca8SBart Van Assche static const char *const rqf_name[] = { 24185ba3effSJens Axboe RQF_NAME(STARTED), 2421a435111SOmar Sandoval RQF_NAME(FLUSH_SEQ), 2431a435111SOmar Sandoval RQF_NAME(MIXED_MERGE), 2441a435111SOmar Sandoval RQF_NAME(DONTPREP), 245dd6216bbSChristoph Hellwig RQF_NAME(SCHED_TAGS), 246dd6216bbSChristoph Hellwig RQF_NAME(USE_SCHED), 2471a435111SOmar Sandoval RQF_NAME(FAILED), 2481a435111SOmar Sandoval RQF_NAME(QUIET), 2491a435111SOmar Sandoval RQF_NAME(IO_STAT), 2501a435111SOmar Sandoval RQF_NAME(PM), 2511a435111SOmar Sandoval RQF_NAME(HASHED), 2521a435111SOmar Sandoval RQF_NAME(STATS), 2531a435111SOmar Sandoval RQF_NAME(SPECIAL_PAYLOAD), 254af54963fSJohn Garry RQF_NAME(ZONE_WRITE_PLUGGING), 255745ed372SJens Axboe RQF_NAME(TIMED_OUT), 256745ed372SJens Axboe RQF_NAME(RESV), 2578658dca8SBart Van Assche }; 2581a435111SOmar Sandoval #undef RQF_NAME 2598658dca8SBart Van Assche 260ec6dcf63SBart Van Assche static const char *const blk_mq_rq_state_name_array[] = { 261ec6dcf63SBart Van Assche [MQ_RQ_IDLE] = "idle", 262ec6dcf63SBart Van Assche [MQ_RQ_IN_FLIGHT] = "in_flight", 263ec6dcf63SBart Van Assche [MQ_RQ_COMPLETE] = "complete", 264ec6dcf63SBart Van Assche }; 265ec6dcf63SBart Van Assche 266ec6dcf63SBart Van Assche static const char *blk_mq_rq_state_name(enum mq_rq_state rq_state) 267ec6dcf63SBart Van Assche { 268a1e79188SDan Carpenter if (WARN_ON_ONCE((unsigned int)rq_state >= 269ec6dcf63SBart Van Assche ARRAY_SIZE(blk_mq_rq_state_name_array))) 270ec6dcf63SBart Van Assche return "(?)"; 271ec6dcf63SBart Van Assche return blk_mq_rq_state_name_array[rq_state]; 272ec6dcf63SBart Van Assche } 273ec6dcf63SBart Van Assche 274daaadb3eSOmar Sandoval int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq) 275950cd7e9SOmar Sandoval { 2762836ee4bSBart Van Assche const struct blk_mq_ops *const mq_ops = rq->q->mq_ops; 27777e7ffd7SBart Van Assche const enum req_op op = req_op(rq); 278874c893bSChaitanya Kulkarni const char *op_str = blk_op_str(op); 279950cd7e9SOmar Sandoval 2808658dca8SBart Van Assche seq_printf(m, "%p {.op=", rq); 281874c893bSChaitanya Kulkarni if (strcmp(op_str, "UNKNOWN") == 0) 2823f6d385fSChaitanya Kulkarni seq_printf(m, "%u", op); 2838658dca8SBart Van Assche else 284874c893bSChaitanya Kulkarni seq_printf(m, "%s", op_str); 2858658dca8SBart Van Assche seq_puts(m, ", .cmd_flags="); 28616458cf3SBart Van Assche blk_flags_show(m, (__force unsigned int)(rq->cmd_flags & ~REQ_OP_MASK), 28716458cf3SBart Van Assche cmd_flag_name, ARRAY_SIZE(cmd_flag_name)); 2888658dca8SBart Van Assche seq_puts(m, ", .rq_flags="); 2898658dca8SBart Van Assche blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name, 2908658dca8SBart Van Assche ARRAY_SIZE(rqf_name)); 291ec6dcf63SBart Van Assche seq_printf(m, ", .state=%s", blk_mq_rq_state_name(blk_mq_rq_state(rq))); 2922836ee4bSBart Van Assche seq_printf(m, ", .tag=%d, .internal_tag=%d", rq->tag, 2938658dca8SBart Van Assche rq->internal_tag); 2942836ee4bSBart Van Assche if (mq_ops->show_rq) 2952836ee4bSBart Van Assche mq_ops->show_rq(m, rq); 2962836ee4bSBart Van Assche seq_puts(m, "}\n"); 297950cd7e9SOmar Sandoval return 0; 298950cd7e9SOmar Sandoval } 299daaadb3eSOmar Sandoval EXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show); 300daaadb3eSOmar Sandoval 301daaadb3eSOmar Sandoval int blk_mq_debugfs_rq_show(struct seq_file *m, void *v) 302daaadb3eSOmar Sandoval { 303daaadb3eSOmar Sandoval return __blk_mq_debugfs_rq_show(m, list_entry_rq(v)); 304daaadb3eSOmar Sandoval } 30516b738f6SOmar Sandoval EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show); 306950cd7e9SOmar Sandoval 307950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos) 308f3bcb0e6SBart Van Assche __acquires(&hctx->lock) 309950cd7e9SOmar Sandoval { 310950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 311950cd7e9SOmar Sandoval 312950cd7e9SOmar Sandoval spin_lock(&hctx->lock); 313950cd7e9SOmar Sandoval return seq_list_start(&hctx->dispatch, *pos); 314950cd7e9SOmar Sandoval } 315950cd7e9SOmar Sandoval 316950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos) 317950cd7e9SOmar Sandoval { 318950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 319950cd7e9SOmar Sandoval 320950cd7e9SOmar Sandoval return seq_list_next(v, &hctx->dispatch, pos); 321950cd7e9SOmar Sandoval } 322950cd7e9SOmar Sandoval 323950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v) 324f3bcb0e6SBart Van Assche __releases(&hctx->lock) 325950cd7e9SOmar Sandoval { 326950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 327950cd7e9SOmar Sandoval 328950cd7e9SOmar Sandoval spin_unlock(&hctx->lock); 329950cd7e9SOmar Sandoval } 330950cd7e9SOmar Sandoval 331950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = { 332950cd7e9SOmar Sandoval .start = hctx_dispatch_start, 333950cd7e9SOmar Sandoval .next = hctx_dispatch_next, 334950cd7e9SOmar Sandoval .stop = hctx_dispatch_stop, 335950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 336950cd7e9SOmar Sandoval }; 337950cd7e9SOmar Sandoval 3382720bab5SBart Van Assche struct show_busy_params { 3392720bab5SBart Van Assche struct seq_file *m; 3402720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx; 3412720bab5SBart Van Assche }; 3422720bab5SBart Van Assche 3432720bab5SBart Van Assche /* 3442720bab5SBart Van Assche * Note: the state of a request may change while this function is in progress, 3457baa8572SJens Axboe * e.g. due to a concurrent blk_mq_finish_request() call. Returns true to 3467baa8572SJens Axboe * keep iterating requests. 3472720bab5SBart Van Assche */ 3482dd6532eSJohn Garry static bool hctx_show_busy_rq(struct request *rq, void *data) 3492720bab5SBart Van Assche { 3502720bab5SBart Van Assche const struct show_busy_params *params = data; 3512720bab5SBart Van Assche 352ea4f995eSJens Axboe if (rq->mq_hctx == params->hctx) 353b5fc1e8bSHou Tao __blk_mq_debugfs_rq_show(params->m, rq); 3547baa8572SJens Axboe 3557baa8572SJens Axboe return true; 3562720bab5SBart Van Assche } 3572720bab5SBart Van Assche 3582720bab5SBart Van Assche static int hctx_busy_show(void *data, struct seq_file *m) 3592720bab5SBart Van Assche { 3602720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx = data; 3612720bab5SBart Van Assche struct show_busy_params params = { .m = m, .hctx = hctx }; 3622720bab5SBart Van Assche 3632720bab5SBart Van Assche blk_mq_tagset_busy_iter(hctx->queue->tag_set, hctx_show_busy_rq, 3642720bab5SBart Van Assche ¶ms); 3652720bab5SBart Van Assche 3662720bab5SBart Van Assche return 0; 3672720bab5SBart Van Assche } 3682720bab5SBart Van Assche 369346fc108SMing Lei static const char *const hctx_types[] = { 370346fc108SMing Lei [HCTX_TYPE_DEFAULT] = "default", 371346fc108SMing Lei [HCTX_TYPE_READ] = "read", 372346fc108SMing Lei [HCTX_TYPE_POLL] = "poll", 373346fc108SMing Lei }; 374346fc108SMing Lei 375346fc108SMing Lei static int hctx_type_show(void *data, struct seq_file *m) 376346fc108SMing Lei { 377346fc108SMing Lei struct blk_mq_hw_ctx *hctx = data; 378346fc108SMing Lei 379346fc108SMing Lei BUILD_BUG_ON(ARRAY_SIZE(hctx_types) != HCTX_MAX_TYPES); 380346fc108SMing Lei seq_printf(m, "%s\n", hctx_types[hctx->type]); 381346fc108SMing Lei return 0; 382346fc108SMing Lei } 383346fc108SMing Lei 384f57de23aSOmar Sandoval static int hctx_ctx_map_show(void *data, struct seq_file *m) 385950cd7e9SOmar Sandoval { 386f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 3870bfa5288SOmar Sandoval 3880bfa5288SOmar Sandoval sbitmap_bitmap_show(&hctx->ctx_map, m); 3890bfa5288SOmar Sandoval return 0; 3900bfa5288SOmar Sandoval } 3910bfa5288SOmar Sandoval 392d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m, 393d96b37c0SOmar Sandoval struct blk_mq_tags *tags) 394d96b37c0SOmar Sandoval { 395d96b37c0SOmar Sandoval seq_printf(m, "nr_tags=%u\n", tags->nr_tags); 396d96b37c0SOmar Sandoval seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags); 397d96b37c0SOmar Sandoval seq_printf(m, "active_queues=%d\n", 3984f1731dfSYu Kuai READ_ONCE(tags->active_queues)); 399d96b37c0SOmar Sandoval 400d96b37c0SOmar Sandoval seq_puts(m, "\nbitmap_tags:\n"); 401ae0f1a73SJohn Garry sbitmap_queue_show(&tags->bitmap_tags, m); 402d96b37c0SOmar Sandoval 403d96b37c0SOmar Sandoval if (tags->nr_reserved_tags) { 404d96b37c0SOmar Sandoval seq_puts(m, "\nbreserved_tags:\n"); 405ae0f1a73SJohn Garry sbitmap_queue_show(&tags->breserved_tags, m); 406d96b37c0SOmar Sandoval } 407d96b37c0SOmar Sandoval } 408d96b37c0SOmar Sandoval 409f57de23aSOmar Sandoval static int hctx_tags_show(void *data, struct seq_file *m) 410d96b37c0SOmar Sandoval { 411f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 412d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 4138c0f14eaSBart Van Assche int res; 414d96b37c0SOmar Sandoval 4158c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4168c0f14eaSBart Van Assche if (res) 4178c0f14eaSBart Van Assche goto out; 418d96b37c0SOmar Sandoval if (hctx->tags) 419d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->tags); 420d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 421d96b37c0SOmar Sandoval 4228c0f14eaSBart Van Assche out: 4238c0f14eaSBart Van Assche return res; 424d96b37c0SOmar Sandoval } 425d96b37c0SOmar Sandoval 426f57de23aSOmar Sandoval static int hctx_tags_bitmap_show(void *data, struct seq_file *m) 427d96b37c0SOmar Sandoval { 428f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 429d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 4308c0f14eaSBart Van Assche int res; 431d7e3621aSOmar Sandoval 4328c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4338c0f14eaSBart Van Assche if (res) 4348c0f14eaSBart Van Assche goto out; 435d7e3621aSOmar Sandoval if (hctx->tags) 436ae0f1a73SJohn Garry sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m); 437d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 4388c0f14eaSBart Van Assche 4398c0f14eaSBart Van Assche out: 4408c0f14eaSBart Van Assche return res; 441d7e3621aSOmar Sandoval } 442d7e3621aSOmar Sandoval 443f57de23aSOmar Sandoval static int hctx_sched_tags_show(void *data, struct seq_file *m) 444d7e3621aSOmar Sandoval { 445f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 446d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 4478c0f14eaSBart Van Assche int res; 448d96b37c0SOmar Sandoval 4498c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4508c0f14eaSBart Van Assche if (res) 4518c0f14eaSBart Van Assche goto out; 452d96b37c0SOmar Sandoval if (hctx->sched_tags) 453d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->sched_tags); 454d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 455d96b37c0SOmar Sandoval 4568c0f14eaSBart Van Assche out: 4578c0f14eaSBart Van Assche return res; 458d96b37c0SOmar Sandoval } 459d96b37c0SOmar Sandoval 460f57de23aSOmar Sandoval static int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m) 461d96b37c0SOmar Sandoval { 462f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 463d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 4648c0f14eaSBart Van Assche int res; 465d7e3621aSOmar Sandoval 4668c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4678c0f14eaSBart Van Assche if (res) 4688c0f14eaSBart Van Assche goto out; 469d7e3621aSOmar Sandoval if (hctx->sched_tags) 470ae0f1a73SJohn Garry sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m); 471d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 4728c0f14eaSBart Van Assche 4738c0f14eaSBart Van Assche out: 4748c0f14eaSBart Van Assche return res; 475d7e3621aSOmar Sandoval } 476d7e3621aSOmar Sandoval 477f57de23aSOmar Sandoval static int hctx_active_show(void *data, struct seq_file *m) 4784a46f05eSOmar Sandoval { 479f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 4804a46f05eSOmar Sandoval 4819b84c629SJohn Garry seq_printf(m, "%d\n", __blk_mq_active_requests(hctx)); 4824a46f05eSOmar Sandoval return 0; 4834a46f05eSOmar Sandoval } 4844a46f05eSOmar Sandoval 4856e768717SMing Lei static int hctx_dispatch_busy_show(void *data, struct seq_file *m) 4866e768717SMing Lei { 4876e768717SMing Lei struct blk_mq_hw_ctx *hctx = data; 4886e768717SMing Lei 4896e768717SMing Lei seq_printf(m, "%u\n", hctx->dispatch_busy); 4906e768717SMing Lei return 0; 4916e768717SMing Lei } 4926e768717SMing Lei 493c16d6b5aSMing Lei #define CTX_RQ_SEQ_OPS(name, type) \ 494c16d6b5aSMing Lei static void *ctx_##name##_rq_list_start(struct seq_file *m, loff_t *pos) \ 495c16d6b5aSMing Lei __acquires(&ctx->lock) \ 496c16d6b5aSMing Lei { \ 497c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 498c16d6b5aSMing Lei \ 499c16d6b5aSMing Lei spin_lock(&ctx->lock); \ 500c16d6b5aSMing Lei return seq_list_start(&ctx->rq_lists[type], *pos); \ 501c16d6b5aSMing Lei } \ 502c16d6b5aSMing Lei \ 503c16d6b5aSMing Lei static void *ctx_##name##_rq_list_next(struct seq_file *m, void *v, \ 504c16d6b5aSMing Lei loff_t *pos) \ 505c16d6b5aSMing Lei { \ 506c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 507c16d6b5aSMing Lei \ 508c16d6b5aSMing Lei return seq_list_next(v, &ctx->rq_lists[type], pos); \ 509c16d6b5aSMing Lei } \ 510c16d6b5aSMing Lei \ 511c16d6b5aSMing Lei static void ctx_##name##_rq_list_stop(struct seq_file *m, void *v) \ 512c16d6b5aSMing Lei __releases(&ctx->lock) \ 513c16d6b5aSMing Lei { \ 514c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 515c16d6b5aSMing Lei \ 516c16d6b5aSMing Lei spin_unlock(&ctx->lock); \ 517c16d6b5aSMing Lei } \ 518c16d6b5aSMing Lei \ 519c16d6b5aSMing Lei static const struct seq_operations ctx_##name##_rq_list_seq_ops = { \ 520c16d6b5aSMing Lei .start = ctx_##name##_rq_list_start, \ 521c16d6b5aSMing Lei .next = ctx_##name##_rq_list_next, \ 522c16d6b5aSMing Lei .stop = ctx_##name##_rq_list_stop, \ 523c16d6b5aSMing Lei .show = blk_mq_debugfs_rq_show, \ 524950cd7e9SOmar Sandoval } 525950cd7e9SOmar Sandoval 526c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(default, HCTX_TYPE_DEFAULT); 527c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(read, HCTX_TYPE_READ); 528c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(poll, HCTX_TYPE_POLL); 529950cd7e9SOmar Sandoval 530f57de23aSOmar Sandoval static int blk_mq_debugfs_show(struct seq_file *m, void *v) 531f57de23aSOmar Sandoval { 532f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 533f57de23aSOmar Sandoval void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private; 534f57de23aSOmar Sandoval 535f57de23aSOmar Sandoval return attr->show(data, m); 536f57de23aSOmar Sandoval } 537f57de23aSOmar Sandoval 538f57de23aSOmar Sandoval static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf, 539f57de23aSOmar Sandoval size_t count, loff_t *ppos) 540f57de23aSOmar Sandoval { 541f57de23aSOmar Sandoval struct seq_file *m = file->private_data; 542f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 543f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 544f57de23aSOmar Sandoval 5456b136a24SEryu Guan /* 5466b136a24SEryu Guan * Attributes that only implement .seq_ops are read-only and 'attr' is 5476b136a24SEryu Guan * the same with 'data' in this case. 5486b136a24SEryu Guan */ 5496b136a24SEryu Guan if (attr == data || !attr->write) 550f57de23aSOmar Sandoval return -EPERM; 551f57de23aSOmar Sandoval 552f57de23aSOmar Sandoval return attr->write(data, buf, count, ppos); 553f57de23aSOmar Sandoval } 554f57de23aSOmar Sandoval 555f57de23aSOmar Sandoval static int blk_mq_debugfs_open(struct inode *inode, struct file *file) 556f57de23aSOmar Sandoval { 557f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 558f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 559f57de23aSOmar Sandoval struct seq_file *m; 560f57de23aSOmar Sandoval int ret; 561f57de23aSOmar Sandoval 562f57de23aSOmar Sandoval if (attr->seq_ops) { 563f57de23aSOmar Sandoval ret = seq_open(file, attr->seq_ops); 564f57de23aSOmar Sandoval if (!ret) { 565f57de23aSOmar Sandoval m = file->private_data; 566f57de23aSOmar Sandoval m->private = data; 567f57de23aSOmar Sandoval } 568f57de23aSOmar Sandoval return ret; 569f57de23aSOmar Sandoval } 570f57de23aSOmar Sandoval 571f57de23aSOmar Sandoval if (WARN_ON_ONCE(!attr->show)) 572f57de23aSOmar Sandoval return -EPERM; 573f57de23aSOmar Sandoval 574f57de23aSOmar Sandoval return single_open(file, blk_mq_debugfs_show, inode->i_private); 575f57de23aSOmar Sandoval } 576f57de23aSOmar Sandoval 577f57de23aSOmar Sandoval static int blk_mq_debugfs_release(struct inode *inode, struct file *file) 578f57de23aSOmar Sandoval { 579f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 580f57de23aSOmar Sandoval 581f57de23aSOmar Sandoval if (attr->show) 582f57de23aSOmar Sandoval return single_release(inode, file); 583ee1e0359SChaitanya Kulkarni 584f57de23aSOmar Sandoval return seq_release(inode, file); 585f57de23aSOmar Sandoval } 586f57de23aSOmar Sandoval 587f8465933SBart Van Assche static const struct file_operations blk_mq_debugfs_fops = { 588f57de23aSOmar Sandoval .open = blk_mq_debugfs_open, 5894a46f05eSOmar Sandoval .read = seq_read, 590f57de23aSOmar Sandoval .write = blk_mq_debugfs_write, 5914a46f05eSOmar Sandoval .llseek = seq_lseek, 592f57de23aSOmar Sandoval .release = blk_mq_debugfs_release, 5934a46f05eSOmar Sandoval }; 5944a46f05eSOmar Sandoval 59507e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { 596f57de23aSOmar Sandoval {"state", 0400, hctx_state_show}, 597f57de23aSOmar Sandoval {"flags", 0400, hctx_flags_show}, 598f57de23aSOmar Sandoval {"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops}, 5992720bab5SBart Van Assche {"busy", 0400, hctx_busy_show}, 600f57de23aSOmar Sandoval {"ctx_map", 0400, hctx_ctx_map_show}, 601f57de23aSOmar Sandoval {"tags", 0400, hctx_tags_show}, 602f57de23aSOmar Sandoval {"tags_bitmap", 0400, hctx_tags_bitmap_show}, 603f57de23aSOmar Sandoval {"sched_tags", 0400, hctx_sched_tags_show}, 604f57de23aSOmar Sandoval {"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show}, 605f57de23aSOmar Sandoval {"active", 0400, hctx_active_show}, 6066e768717SMing Lei {"dispatch_busy", 0400, hctx_dispatch_busy_show}, 607346fc108SMing Lei {"type", 0400, hctx_type_show}, 60872f2f8f6SBart Van Assche {}, 60907e4feadSOmar Sandoval }; 61007e4feadSOmar Sandoval 61107e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = { 612c16d6b5aSMing Lei {"default_rq_list", 0400, .seq_ops = &ctx_default_rq_list_seq_ops}, 613c16d6b5aSMing Lei {"read_rq_list", 0400, .seq_ops = &ctx_read_rq_list_seq_ops}, 614c16d6b5aSMing Lei {"poll_rq_list", 0400, .seq_ops = &ctx_poll_rq_list_seq_ops}, 61572f2f8f6SBart Van Assche {}, 61607e4feadSOmar Sandoval }; 61707e4feadSOmar Sandoval 6186cfc0081SGreg Kroah-Hartman static void debugfs_create_files(struct dentry *parent, void *data, 61972f2f8f6SBart Van Assche const struct blk_mq_debugfs_attr *attr) 62072f2f8f6SBart Van Assche { 62136991ca6SGreg Kroah-Hartman if (IS_ERR_OR_NULL(parent)) 6226cfc0081SGreg Kroah-Hartman return; 62336991ca6SGreg Kroah-Hartman 624f57de23aSOmar Sandoval d_inode(parent)->i_private = data; 625f57de23aSOmar Sandoval 6266cfc0081SGreg Kroah-Hartman for (; attr->name; attr++) 6276cfc0081SGreg Kroah-Hartman debugfs_create_file(attr->name, attr->mode, parent, 6286cfc0081SGreg Kroah-Hartman (void *)attr, &blk_mq_debugfs_fops); 62972f2f8f6SBart Van Assche } 63072f2f8f6SBart Van Assche 6316cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register(struct request_queue *q) 6329c1051aaSOmar Sandoval { 6339c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 6344f481208SMing Lei unsigned long i; 6359c1051aaSOmar Sandoval 6366cfc0081SGreg Kroah-Hartman debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs); 6379c1051aaSOmar Sandoval 6389c1051aaSOmar Sandoval /* 63970e62f4bSOmar Sandoval * blk_mq_init_sched() attempted to do this already, but q->debugfs_dir 6409c1051aaSOmar Sandoval * didn't exist yet (because we don't know what to name the directory 6419c1051aaSOmar Sandoval * until the queue is registered to a gendisk). 6429c1051aaSOmar Sandoval */ 64370e62f4bSOmar Sandoval if (q->elevator && !q->sched_debugfs_dir) 64470e62f4bSOmar Sandoval blk_mq_debugfs_register_sched(q); 64570e62f4bSOmar Sandoval 64670e62f4bSOmar Sandoval /* Similarly, blk_mq_init_hctx() couldn't do this previously. */ 6479c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) { 6486cfc0081SGreg Kroah-Hartman if (!hctx->debugfs_dir) 6496cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_hctx(q, hctx); 6506cfc0081SGreg Kroah-Hartman if (q->elevator && !hctx->sched_debugfs_dir) 6516cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_sched_hctx(q, hctx); 6529c1051aaSOmar Sandoval } 6539c1051aaSOmar Sandoval 654cc56694fSMing Lei if (q->rq_qos) { 655cc56694fSMing Lei struct rq_qos *rqos = q->rq_qos; 656cc56694fSMing Lei 657cc56694fSMing Lei while (rqos) { 658cc56694fSMing Lei blk_mq_debugfs_register_rqos(rqos); 659cc56694fSMing Lei rqos = rqos->next; 660cc56694fSMing Lei } 661cc56694fSMing Lei } 6629c1051aaSOmar Sandoval } 6639c1051aaSOmar Sandoval 6646cfc0081SGreg Kroah-Hartman static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx, 6659c1051aaSOmar Sandoval struct blk_mq_ctx *ctx) 66607e4feadSOmar Sandoval { 66707e4feadSOmar Sandoval struct dentry *ctx_dir; 66807e4feadSOmar Sandoval char name[20]; 66907e4feadSOmar Sandoval 67007e4feadSOmar Sandoval snprintf(name, sizeof(name), "cpu%u", ctx->cpu); 6719c1051aaSOmar Sandoval ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir); 67207e4feadSOmar Sandoval 6736cfc0081SGreg Kroah-Hartman debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs); 67407e4feadSOmar Sandoval } 67507e4feadSOmar Sandoval 6766cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_hctx(struct request_queue *q, 67707e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx) 67807e4feadSOmar Sandoval { 67907e4feadSOmar Sandoval struct blk_mq_ctx *ctx; 68007e4feadSOmar Sandoval char name[20]; 68107e4feadSOmar Sandoval int i; 68207e4feadSOmar Sandoval 683f3ec5d11SMing Lei if (!q->debugfs_dir) 684f3ec5d11SMing Lei return; 685f3ec5d11SMing Lei 6869c1051aaSOmar Sandoval snprintf(name, sizeof(name), "hctx%u", hctx->queue_num); 6879c1051aaSOmar Sandoval hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir); 6889c1051aaSOmar Sandoval 6896cfc0081SGreg Kroah-Hartman debugfs_create_files(hctx->debugfs_dir, hctx, blk_mq_debugfs_hctx_attrs); 69007e4feadSOmar Sandoval 6916cfc0081SGreg Kroah-Hartman hctx_for_each_ctx(hctx, ctx, i) 6926cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_ctx(hctx, ctx); 69307e4feadSOmar Sandoval } 69407e4feadSOmar Sandoval 6959c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx) 69607e4feadSOmar Sandoval { 6975cf9c91bSChristoph Hellwig if (!hctx->queue->debugfs_dir) 6985cf9c91bSChristoph Hellwig return; 6999c1051aaSOmar Sandoval debugfs_remove_recursive(hctx->debugfs_dir); 700d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 7019c1051aaSOmar Sandoval hctx->debugfs_dir = NULL; 7029c1051aaSOmar Sandoval } 7039c1051aaSOmar Sandoval 7046cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_hctxs(struct request_queue *q) 7059c1051aaSOmar Sandoval { 7069c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 7074f481208SMing Lei unsigned long i; 7089c1051aaSOmar Sandoval 7096cfc0081SGreg Kroah-Hartman queue_for_each_hw_ctx(q, hctx, i) 7106cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_hctx(q, hctx); 7119c1051aaSOmar Sandoval } 7129c1051aaSOmar Sandoval 7139c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q) 7149c1051aaSOmar Sandoval { 7159c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 7164f481208SMing Lei unsigned long i; 7179c1051aaSOmar Sandoval 7189c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) 7199c1051aaSOmar Sandoval blk_mq_debugfs_unregister_hctx(hctx); 72007e4feadSOmar Sandoval } 721d332ce09SOmar Sandoval 7226cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_sched(struct request_queue *q) 723d332ce09SOmar Sandoval { 724d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 725d332ce09SOmar Sandoval 7265cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 7275cf9c91bSChristoph Hellwig 7287e41c3c9SGreg Kroah-Hartman /* 7297e41c3c9SGreg Kroah-Hartman * If the parent directory has not been created yet, return, we will be 7307e41c3c9SGreg Kroah-Hartman * called again later on and the directory/files will be created then. 7317e41c3c9SGreg Kroah-Hartman */ 7327e41c3c9SGreg Kroah-Hartman if (!q->debugfs_dir) 7337e41c3c9SGreg Kroah-Hartman return; 7347e41c3c9SGreg Kroah-Hartman 735d332ce09SOmar Sandoval if (!e->queue_debugfs_attrs) 7366cfc0081SGreg Kroah-Hartman return; 737d332ce09SOmar Sandoval 738d332ce09SOmar Sandoval q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir); 739d332ce09SOmar Sandoval 7406cfc0081SGreg Kroah-Hartman debugfs_create_files(q->sched_debugfs_dir, q, e->queue_debugfs_attrs); 741d332ce09SOmar Sandoval } 742d332ce09SOmar Sandoval 743d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched(struct request_queue *q) 744d332ce09SOmar Sandoval { 7455cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 7465cf9c91bSChristoph Hellwig 747d332ce09SOmar Sandoval debugfs_remove_recursive(q->sched_debugfs_dir); 748d332ce09SOmar Sandoval q->sched_debugfs_dir = NULL; 749d332ce09SOmar Sandoval } 750d332ce09SOmar Sandoval 751fb44023eSBart Van Assche static const char *rq_qos_id_to_name(enum rq_qos_id id) 752fb44023eSBart Van Assche { 753fb44023eSBart Van Assche switch (id) { 754fb44023eSBart Van Assche case RQ_QOS_WBT: 755fb44023eSBart Van Assche return "wbt"; 756fb44023eSBart Van Assche case RQ_QOS_LATENCY: 757fb44023eSBart Van Assche return "latency"; 758fb44023eSBart Van Assche case RQ_QOS_COST: 759fb44023eSBart Van Assche return "cost"; 760fb44023eSBart Van Assche } 761fb44023eSBart Van Assche return "unknown"; 762fb44023eSBart Van Assche } 763fb44023eSBart Van Assche 764cc56694fSMing Lei void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos) 765cc56694fSMing Lei { 766ba91c849SChristoph Hellwig lockdep_assert_held(&rqos->disk->queue->debugfs_mutex); 7675cf9c91bSChristoph Hellwig 768ba91c849SChristoph Hellwig if (!rqos->disk->queue->debugfs_dir) 7695cf9c91bSChristoph Hellwig return; 770cc56694fSMing Lei debugfs_remove_recursive(rqos->debugfs_dir); 771cc56694fSMing Lei rqos->debugfs_dir = NULL; 772cc56694fSMing Lei } 773cc56694fSMing Lei 7746cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_rqos(struct rq_qos *rqos) 775cc56694fSMing Lei { 776ba91c849SChristoph Hellwig struct request_queue *q = rqos->disk->queue; 777cc56694fSMing Lei const char *dir_name = rq_qos_id_to_name(rqos->id); 778cc56694fSMing Lei 7795cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 7805cf9c91bSChristoph Hellwig 781cc56694fSMing Lei if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs) 7826cfc0081SGreg Kroah-Hartman return; 783cc56694fSMing Lei 7846cfc0081SGreg Kroah-Hartman if (!q->rqos_debugfs_dir) 785cc56694fSMing Lei q->rqos_debugfs_dir = debugfs_create_dir("rqos", 786cc56694fSMing Lei q->debugfs_dir); 787cc56694fSMing Lei 788ba91c849SChristoph Hellwig rqos->debugfs_dir = debugfs_create_dir(dir_name, q->rqos_debugfs_dir); 7896cfc0081SGreg Kroah-Hartman debugfs_create_files(rqos->debugfs_dir, rqos, rqos->ops->debugfs_attrs); 790cc56694fSMing Lei } 791cc56694fSMing Lei 7926cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_sched_hctx(struct request_queue *q, 793d332ce09SOmar Sandoval struct blk_mq_hw_ctx *hctx) 794d332ce09SOmar Sandoval { 795d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 796d332ce09SOmar Sandoval 7975cf9c91bSChristoph Hellwig lockdep_assert_held(&q->debugfs_mutex); 7985cf9c91bSChristoph Hellwig 7991e91e28eSSaravanan D /* 8001e91e28eSSaravanan D * If the parent debugfs directory has not been created yet, return; 8011e91e28eSSaravanan D * We will be called again later on with appropriate parent debugfs 8021e91e28eSSaravanan D * directory from blk_register_queue() 8031e91e28eSSaravanan D */ 8041e91e28eSSaravanan D if (!hctx->debugfs_dir) 8051e91e28eSSaravanan D return; 8061e91e28eSSaravanan D 807d332ce09SOmar Sandoval if (!e->hctx_debugfs_attrs) 8086cfc0081SGreg Kroah-Hartman return; 809d332ce09SOmar Sandoval 810d332ce09SOmar Sandoval hctx->sched_debugfs_dir = debugfs_create_dir("sched", 811d332ce09SOmar Sandoval hctx->debugfs_dir); 8126cfc0081SGreg Kroah-Hartman debugfs_create_files(hctx->sched_debugfs_dir, hctx, 8136cfc0081SGreg Kroah-Hartman e->hctx_debugfs_attrs); 814d332ce09SOmar Sandoval } 815d332ce09SOmar Sandoval 816d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx) 817d332ce09SOmar Sandoval { 8185cf9c91bSChristoph Hellwig lockdep_assert_held(&hctx->queue->debugfs_mutex); 8195cf9c91bSChristoph Hellwig 8205cf9c91bSChristoph Hellwig if (!hctx->queue->debugfs_dir) 8215cf9c91bSChristoph Hellwig return; 822d332ce09SOmar Sandoval debugfs_remove_recursive(hctx->sched_debugfs_dir); 823d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 824d332ce09SOmar Sandoval } 825