107e4feadSOmar Sandoval /* 207e4feadSOmar Sandoval * Copyright (C) 2017 Facebook 307e4feadSOmar Sandoval * 407e4feadSOmar Sandoval * This program is free software; you can redistribute it and/or 507e4feadSOmar Sandoval * modify it under the terms of the GNU General Public 607e4feadSOmar Sandoval * License v2 as published by the Free Software Foundation. 707e4feadSOmar Sandoval * 807e4feadSOmar Sandoval * This program is distributed in the hope that it will be useful, 907e4feadSOmar Sandoval * but WITHOUT ANY WARRANTY; without even the implied warranty of 1007e4feadSOmar Sandoval * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1107e4feadSOmar Sandoval * General Public License for more details. 1207e4feadSOmar Sandoval * 1307e4feadSOmar Sandoval * You should have received a copy of the GNU General Public License 1407e4feadSOmar Sandoval * along with this program. If not, see <https://www.gnu.org/licenses/>. 1507e4feadSOmar Sandoval */ 1607e4feadSOmar Sandoval 1707e4feadSOmar Sandoval #include <linux/kernel.h> 1807e4feadSOmar Sandoval #include <linux/blkdev.h> 1907e4feadSOmar Sandoval #include <linux/debugfs.h> 2007e4feadSOmar Sandoval 2107e4feadSOmar Sandoval #include <linux/blk-mq.h> 2218fbda91SOmar Sandoval #include "blk.h" 2307e4feadSOmar Sandoval #include "blk-mq.h" 24d173a251SOmar Sandoval #include "blk-mq-debugfs.h" 25d96b37c0SOmar Sandoval #include "blk-mq-tag.h" 2607e4feadSOmar Sandoval 2791d68905SBart Van Assche static int blk_flags_show(struct seq_file *m, const unsigned long flags, 2891d68905SBart Van Assche const char *const *flag_name, int flag_name_count) 2991d68905SBart Van Assche { 3091d68905SBart Van Assche bool sep = false; 3191d68905SBart Van Assche int i; 3291d68905SBart Van Assche 3391d68905SBart Van Assche for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) { 3491d68905SBart Van Assche if (!(flags & BIT(i))) 3591d68905SBart Van Assche continue; 3691d68905SBart Van Assche if (sep) 37bec03d6bSOmar Sandoval seq_puts(m, "|"); 3891d68905SBart Van Assche sep = true; 3991d68905SBart Van Assche if (i < flag_name_count && flag_name[i]) 4091d68905SBart Van Assche seq_puts(m, flag_name[i]); 4191d68905SBart Van Assche else 4291d68905SBart Van Assche seq_printf(m, "%d", i); 4391d68905SBart Van Assche } 4491d68905SBart Van Assche return 0; 4591d68905SBart Van Assche } 4691d68905SBart Van Assche 471a435111SOmar Sandoval #define QUEUE_FLAG_NAME(name) [QUEUE_FLAG_##name] = #name 4891d68905SBart Van Assche static const char *const blk_queue_flag_name[] = { 491a435111SOmar Sandoval QUEUE_FLAG_NAME(QUEUED), 501a435111SOmar Sandoval QUEUE_FLAG_NAME(STOPPED), 511a435111SOmar Sandoval QUEUE_FLAG_NAME(SYNCFULL), 521a435111SOmar Sandoval QUEUE_FLAG_NAME(ASYNCFULL), 531a435111SOmar Sandoval QUEUE_FLAG_NAME(DYING), 541a435111SOmar Sandoval QUEUE_FLAG_NAME(BYPASS), 551a435111SOmar Sandoval QUEUE_FLAG_NAME(BIDI), 561a435111SOmar Sandoval QUEUE_FLAG_NAME(NOMERGES), 571a435111SOmar Sandoval QUEUE_FLAG_NAME(SAME_COMP), 581a435111SOmar Sandoval QUEUE_FLAG_NAME(FAIL_IO), 591a435111SOmar Sandoval QUEUE_FLAG_NAME(STACKABLE), 601a435111SOmar Sandoval QUEUE_FLAG_NAME(NONROT), 611a435111SOmar Sandoval QUEUE_FLAG_NAME(IO_STAT), 621a435111SOmar Sandoval QUEUE_FLAG_NAME(DISCARD), 631a435111SOmar Sandoval QUEUE_FLAG_NAME(NOXMERGES), 641a435111SOmar Sandoval QUEUE_FLAG_NAME(ADD_RANDOM), 651a435111SOmar Sandoval QUEUE_FLAG_NAME(SECERASE), 661a435111SOmar Sandoval QUEUE_FLAG_NAME(SAME_FORCE), 671a435111SOmar Sandoval QUEUE_FLAG_NAME(DEAD), 681a435111SOmar Sandoval QUEUE_FLAG_NAME(INIT_DONE), 691a435111SOmar Sandoval QUEUE_FLAG_NAME(NO_SG_MERGE), 701a435111SOmar Sandoval QUEUE_FLAG_NAME(POLL), 711a435111SOmar Sandoval QUEUE_FLAG_NAME(WC), 721a435111SOmar Sandoval QUEUE_FLAG_NAME(FUA), 731a435111SOmar Sandoval QUEUE_FLAG_NAME(FLUSH_NQ), 741a435111SOmar Sandoval QUEUE_FLAG_NAME(DAX), 751a435111SOmar Sandoval QUEUE_FLAG_NAME(STATS), 761a435111SOmar Sandoval QUEUE_FLAG_NAME(POLL_STATS), 771a435111SOmar Sandoval QUEUE_FLAG_NAME(REGISTERED), 7891d68905SBart Van Assche }; 791a435111SOmar Sandoval #undef QUEUE_FLAG_NAME 8091d68905SBart Van Assche 81f57de23aSOmar Sandoval static int queue_state_show(void *data, struct seq_file *m) 8291d68905SBart Van Assche { 83f57de23aSOmar Sandoval struct request_queue *q = data; 8491d68905SBart Van Assche 8591d68905SBart Van Assche blk_flags_show(m, q->queue_flags, blk_queue_flag_name, 8691d68905SBart Van Assche ARRAY_SIZE(blk_queue_flag_name)); 87fd07dc81SBart Van Assche seq_puts(m, "\n"); 8891d68905SBart Van Assche return 0; 8991d68905SBart Van Assche } 9091d68905SBart Van Assche 91f57de23aSOmar Sandoval static ssize_t queue_state_write(void *data, const char __user *buf, 92c7e4145aSOmar Sandoval size_t count, loff_t *ppos) 9391d68905SBart Van Assche { 94f57de23aSOmar Sandoval struct request_queue *q = data; 9571b90511SOmar Sandoval char opbuf[16] = { }, *op; 9691d68905SBart Van Assche 9718d4d7d0SBart Van Assche /* 9818d4d7d0SBart Van Assche * The "state" attribute is removed after blk_cleanup_queue() has called 9918d4d7d0SBart Van Assche * blk_mq_free_queue(). Return if QUEUE_FLAG_DEAD has been set to avoid 10018d4d7d0SBart Van Assche * triggering a use-after-free. 10118d4d7d0SBart Van Assche */ 10218d4d7d0SBart Van Assche if (blk_queue_dead(q)) 10318d4d7d0SBart Van Assche return -ENOENT; 10418d4d7d0SBart Van Assche 10571b90511SOmar Sandoval if (count >= sizeof(opbuf)) { 106c7e4145aSOmar Sandoval pr_err("%s: operation too long\n", __func__); 107c7e4145aSOmar Sandoval goto inval; 108c7e4145aSOmar Sandoval } 109c7e4145aSOmar Sandoval 11071b90511SOmar Sandoval if (copy_from_user(opbuf, buf, count)) 11191d68905SBart Van Assche return -EFAULT; 11271b90511SOmar Sandoval op = strstrip(opbuf); 11391d68905SBart Van Assche if (strcmp(op, "run") == 0) { 11491d68905SBart Van Assche blk_mq_run_hw_queues(q, true); 11591d68905SBart Van Assche } else if (strcmp(op, "start") == 0) { 11691d68905SBart Van Assche blk_mq_start_stopped_hw_queues(q, true); 11791d68905SBart Van Assche } else { 118c7e4145aSOmar Sandoval pr_err("%s: unsupported operation '%s'\n", __func__, op); 119c7e4145aSOmar Sandoval inval: 120c7e4145aSOmar Sandoval pr_err("%s: use either 'run' or 'start'\n", __func__); 12191d68905SBart Van Assche return -EINVAL; 12291d68905SBart Van Assche } 123c7e4145aSOmar Sandoval return count; 12491d68905SBart Van Assche } 12591d68905SBart Van Assche 12634dbad5dSOmar Sandoval static void print_stat(struct seq_file *m, struct blk_rq_stat *stat) 12734dbad5dSOmar Sandoval { 12834dbad5dSOmar Sandoval if (stat->nr_samples) { 12934dbad5dSOmar Sandoval seq_printf(m, "samples=%d, mean=%lld, min=%llu, max=%llu", 13034dbad5dSOmar Sandoval stat->nr_samples, stat->mean, stat->min, stat->max); 13134dbad5dSOmar Sandoval } else { 13234dbad5dSOmar Sandoval seq_puts(m, "samples=0"); 13334dbad5dSOmar Sandoval } 13434dbad5dSOmar Sandoval } 13534dbad5dSOmar Sandoval 136f57de23aSOmar Sandoval static int queue_poll_stat_show(void *data, struct seq_file *m) 13734dbad5dSOmar Sandoval { 138f57de23aSOmar Sandoval struct request_queue *q = data; 1390206319fSStephen Bates int bucket; 14034dbad5dSOmar Sandoval 1410206319fSStephen Bates for (bucket = 0; bucket < BLK_MQ_POLL_STATS_BKTS/2; bucket++) { 1420206319fSStephen Bates seq_printf(m, "read (%d Bytes): ", 1 << (9+bucket)); 1430206319fSStephen Bates print_stat(m, &q->poll_stat[2*bucket]); 14434dbad5dSOmar Sandoval seq_puts(m, "\n"); 14534dbad5dSOmar Sandoval 1460206319fSStephen Bates seq_printf(m, "write (%d Bytes): ", 1 << (9+bucket)); 1470206319fSStephen Bates print_stat(m, &q->poll_stat[2*bucket+1]); 14834dbad5dSOmar Sandoval seq_puts(m, "\n"); 1490206319fSStephen Bates } 15034dbad5dSOmar Sandoval return 0; 15134dbad5dSOmar Sandoval } 15234dbad5dSOmar Sandoval 1531a435111SOmar Sandoval #define HCTX_STATE_NAME(name) [BLK_MQ_S_##name] = #name 154f5c0b091SBart Van Assche static const char *const hctx_state_name[] = { 1551a435111SOmar Sandoval HCTX_STATE_NAME(STOPPED), 1561a435111SOmar Sandoval HCTX_STATE_NAME(TAG_ACTIVE), 1571a435111SOmar Sandoval HCTX_STATE_NAME(SCHED_RESTART), 1581a435111SOmar Sandoval HCTX_STATE_NAME(TAG_WAITING), 1591a435111SOmar Sandoval HCTX_STATE_NAME(START_ON_RUN), 160f5c0b091SBart Van Assche }; 1611a435111SOmar Sandoval #undef HCTX_STATE_NAME 1621a435111SOmar Sandoval 163f57de23aSOmar Sandoval static int hctx_state_show(void *data, struct seq_file *m) 1649abb2ad2SOmar Sandoval { 165f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 1669abb2ad2SOmar Sandoval 167f5c0b091SBart Van Assche blk_flags_show(m, hctx->state, hctx_state_name, 168f5c0b091SBart Van Assche ARRAY_SIZE(hctx_state_name)); 169fd07dc81SBart Van Assche seq_puts(m, "\n"); 1709abb2ad2SOmar Sandoval return 0; 1719abb2ad2SOmar Sandoval } 1729abb2ad2SOmar Sandoval 1731a435111SOmar Sandoval #define BLK_TAG_ALLOC_NAME(name) [BLK_TAG_ALLOC_##name] = #name 174f5c0b091SBart Van Assche static const char *const alloc_policy_name[] = { 1751a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(FIFO), 1761a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(RR), 177f5c0b091SBart Van Assche }; 1781a435111SOmar Sandoval #undef BLK_TAG_ALLOC_NAME 179f5c0b091SBart Van Assche 1801a435111SOmar Sandoval #define HCTX_FLAG_NAME(name) [ilog2(BLK_MQ_F_##name)] = #name 181f5c0b091SBart Van Assche static const char *const hctx_flag_name[] = { 1821a435111SOmar Sandoval HCTX_FLAG_NAME(SHOULD_MERGE), 1831a435111SOmar Sandoval HCTX_FLAG_NAME(TAG_SHARED), 1841a435111SOmar Sandoval HCTX_FLAG_NAME(SG_MERGE), 1851a435111SOmar Sandoval HCTX_FLAG_NAME(BLOCKING), 1861a435111SOmar Sandoval HCTX_FLAG_NAME(NO_SCHED), 187f5c0b091SBart Van Assche }; 1881a435111SOmar Sandoval #undef HCTX_FLAG_NAME 189f5c0b091SBart Van Assche 190f57de23aSOmar Sandoval static int hctx_flags_show(void *data, struct seq_file *m) 1919abb2ad2SOmar Sandoval { 192f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 193f5c0b091SBart Van Assche const int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(hctx->flags); 1949abb2ad2SOmar Sandoval 195f5c0b091SBart Van Assche seq_puts(m, "alloc_policy="); 196f5c0b091SBart Van Assche if (alloc_policy < ARRAY_SIZE(alloc_policy_name) && 197f5c0b091SBart Van Assche alloc_policy_name[alloc_policy]) 198f5c0b091SBart Van Assche seq_puts(m, alloc_policy_name[alloc_policy]); 199f5c0b091SBart Van Assche else 200f5c0b091SBart Van Assche seq_printf(m, "%d", alloc_policy); 201f5c0b091SBart Van Assche seq_puts(m, " "); 202f5c0b091SBart Van Assche blk_flags_show(m, 203f5c0b091SBart Van Assche hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy), 204f5c0b091SBart Van Assche hctx_flag_name, ARRAY_SIZE(hctx_flag_name)); 205fd07dc81SBart Van Assche seq_puts(m, "\n"); 2069abb2ad2SOmar Sandoval return 0; 2079abb2ad2SOmar Sandoval } 2089abb2ad2SOmar Sandoval 2091a435111SOmar Sandoval #define REQ_OP_NAME(name) [REQ_OP_##name] = #name 2108658dca8SBart Van Assche static const char *const op_name[] = { 2111a435111SOmar Sandoval REQ_OP_NAME(READ), 2121a435111SOmar Sandoval REQ_OP_NAME(WRITE), 2131a435111SOmar Sandoval REQ_OP_NAME(FLUSH), 2141a435111SOmar Sandoval REQ_OP_NAME(DISCARD), 2151a435111SOmar Sandoval REQ_OP_NAME(ZONE_REPORT), 2161a435111SOmar Sandoval REQ_OP_NAME(SECURE_ERASE), 2171a435111SOmar Sandoval REQ_OP_NAME(ZONE_RESET), 2181a435111SOmar Sandoval REQ_OP_NAME(WRITE_SAME), 2191a435111SOmar Sandoval REQ_OP_NAME(WRITE_ZEROES), 2201a435111SOmar Sandoval REQ_OP_NAME(SCSI_IN), 2211a435111SOmar Sandoval REQ_OP_NAME(SCSI_OUT), 2221a435111SOmar Sandoval REQ_OP_NAME(DRV_IN), 2231a435111SOmar Sandoval REQ_OP_NAME(DRV_OUT), 2248658dca8SBart Van Assche }; 2251a435111SOmar Sandoval #undef REQ_OP_NAME 2268658dca8SBart Van Assche 2271a435111SOmar Sandoval #define CMD_FLAG_NAME(name) [__REQ_##name] = #name 2288658dca8SBart Van Assche static const char *const cmd_flag_name[] = { 2291a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DEV), 2301a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_TRANSPORT), 2311a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DRIVER), 2321a435111SOmar Sandoval CMD_FLAG_NAME(SYNC), 2331a435111SOmar Sandoval CMD_FLAG_NAME(META), 2341a435111SOmar Sandoval CMD_FLAG_NAME(PRIO), 2351a435111SOmar Sandoval CMD_FLAG_NAME(NOMERGE), 2361a435111SOmar Sandoval CMD_FLAG_NAME(IDLE), 2371a435111SOmar Sandoval CMD_FLAG_NAME(INTEGRITY), 2381a435111SOmar Sandoval CMD_FLAG_NAME(FUA), 2391a435111SOmar Sandoval CMD_FLAG_NAME(PREFLUSH), 2401a435111SOmar Sandoval CMD_FLAG_NAME(RAHEAD), 2411a435111SOmar Sandoval CMD_FLAG_NAME(BACKGROUND), 2421a435111SOmar Sandoval CMD_FLAG_NAME(NOUNMAP), 2438658dca8SBart Van Assche }; 2441a435111SOmar Sandoval #undef CMD_FLAG_NAME 2458658dca8SBart Van Assche 2461a435111SOmar Sandoval #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name 2478658dca8SBart Van Assche static const char *const rqf_name[] = { 2481a435111SOmar Sandoval RQF_NAME(SORTED), 2491a435111SOmar Sandoval RQF_NAME(STARTED), 2501a435111SOmar Sandoval RQF_NAME(QUEUED), 2511a435111SOmar Sandoval RQF_NAME(SOFTBARRIER), 2521a435111SOmar Sandoval RQF_NAME(FLUSH_SEQ), 2531a435111SOmar Sandoval RQF_NAME(MIXED_MERGE), 2541a435111SOmar Sandoval RQF_NAME(MQ_INFLIGHT), 2551a435111SOmar Sandoval RQF_NAME(DONTPREP), 2561a435111SOmar Sandoval RQF_NAME(PREEMPT), 2571a435111SOmar Sandoval RQF_NAME(COPY_USER), 2581a435111SOmar Sandoval RQF_NAME(FAILED), 2591a435111SOmar Sandoval RQF_NAME(QUIET), 2601a435111SOmar Sandoval RQF_NAME(ELVPRIV), 2611a435111SOmar Sandoval RQF_NAME(IO_STAT), 2621a435111SOmar Sandoval RQF_NAME(ALLOCED), 2631a435111SOmar Sandoval RQF_NAME(PM), 2641a435111SOmar Sandoval RQF_NAME(HASHED), 2651a435111SOmar Sandoval RQF_NAME(STATS), 2661a435111SOmar Sandoval RQF_NAME(SPECIAL_PAYLOAD), 2678658dca8SBart Van Assche }; 2681a435111SOmar Sandoval #undef RQF_NAME 2698658dca8SBart Van Assche 270*c0cb1c6dSBart Van Assche #define RQAF_NAME(name) [REQ_ATOM_##name] = #name 271*c0cb1c6dSBart Van Assche static const char *const rqaf_name[] = { 272*c0cb1c6dSBart Van Assche RQAF_NAME(COMPLETE), 273*c0cb1c6dSBart Van Assche RQAF_NAME(STARTED), 274*c0cb1c6dSBart Van Assche RQAF_NAME(POLL_SLEPT), 275*c0cb1c6dSBart Van Assche }; 276*c0cb1c6dSBart Van Assche #undef RQAF_NAME 277*c0cb1c6dSBart 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; 2818658dca8SBart Van Assche const unsigned int op = rq->cmd_flags & REQ_OP_MASK; 282950cd7e9SOmar Sandoval 2838658dca8SBart Van Assche seq_printf(m, "%p {.op=", rq); 2848658dca8SBart Van Assche if (op < ARRAY_SIZE(op_name) && op_name[op]) 2858658dca8SBart Van Assche seq_printf(m, "%s", op_name[op]); 2868658dca8SBart Van Assche else 2878658dca8SBart Van Assche seq_printf(m, "%d", op); 2888658dca8SBart Van Assche seq_puts(m, ", .cmd_flags="); 2898658dca8SBart Van Assche blk_flags_show(m, rq->cmd_flags & ~REQ_OP_MASK, cmd_flag_name, 2908658dca8SBart Van Assche ARRAY_SIZE(cmd_flag_name)); 2918658dca8SBart Van Assche seq_puts(m, ", .rq_flags="); 2928658dca8SBart Van Assche blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name, 2938658dca8SBart Van Assche ARRAY_SIZE(rqf_name)); 294*c0cb1c6dSBart Van Assche seq_puts(m, ", .atomic_flags="); 295*c0cb1c6dSBart Van Assche blk_flags_show(m, rq->atomic_flags, rqaf_name, ARRAY_SIZE(rqaf_name)); 2962836ee4bSBart Van Assche seq_printf(m, ", .tag=%d, .internal_tag=%d", rq->tag, 2978658dca8SBart Van Assche rq->internal_tag); 2982836ee4bSBart Van Assche if (mq_ops->show_rq) 2992836ee4bSBart Van Assche mq_ops->show_rq(m, rq); 3002836ee4bSBart Van Assche seq_puts(m, "}\n"); 301950cd7e9SOmar Sandoval return 0; 302950cd7e9SOmar Sandoval } 303daaadb3eSOmar Sandoval EXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show); 304daaadb3eSOmar Sandoval 305daaadb3eSOmar Sandoval int blk_mq_debugfs_rq_show(struct seq_file *m, void *v) 306daaadb3eSOmar Sandoval { 307daaadb3eSOmar Sandoval return __blk_mq_debugfs_rq_show(m, list_entry_rq(v)); 308daaadb3eSOmar Sandoval } 30916b738f6SOmar Sandoval EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show); 310950cd7e9SOmar Sandoval 311950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos) 312f3bcb0e6SBart Van Assche __acquires(&hctx->lock) 313950cd7e9SOmar Sandoval { 314950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 315950cd7e9SOmar Sandoval 316950cd7e9SOmar Sandoval spin_lock(&hctx->lock); 317950cd7e9SOmar Sandoval return seq_list_start(&hctx->dispatch, *pos); 318950cd7e9SOmar Sandoval } 319950cd7e9SOmar Sandoval 320950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos) 321950cd7e9SOmar Sandoval { 322950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 323950cd7e9SOmar Sandoval 324950cd7e9SOmar Sandoval return seq_list_next(v, &hctx->dispatch, pos); 325950cd7e9SOmar Sandoval } 326950cd7e9SOmar Sandoval 327950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v) 328f3bcb0e6SBart Van Assche __releases(&hctx->lock) 329950cd7e9SOmar Sandoval { 330950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 331950cd7e9SOmar Sandoval 332950cd7e9SOmar Sandoval spin_unlock(&hctx->lock); 333950cd7e9SOmar Sandoval } 334950cd7e9SOmar Sandoval 335950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = { 336950cd7e9SOmar Sandoval .start = hctx_dispatch_start, 337950cd7e9SOmar Sandoval .next = hctx_dispatch_next, 338950cd7e9SOmar Sandoval .stop = hctx_dispatch_stop, 339950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 340950cd7e9SOmar Sandoval }; 341950cd7e9SOmar Sandoval 342f57de23aSOmar Sandoval static int hctx_ctx_map_show(void *data, struct seq_file *m) 343950cd7e9SOmar Sandoval { 344f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 3450bfa5288SOmar Sandoval 3460bfa5288SOmar Sandoval sbitmap_bitmap_show(&hctx->ctx_map, m); 3470bfa5288SOmar Sandoval return 0; 3480bfa5288SOmar Sandoval } 3490bfa5288SOmar Sandoval 350d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m, 351d96b37c0SOmar Sandoval struct blk_mq_tags *tags) 352d96b37c0SOmar Sandoval { 353d96b37c0SOmar Sandoval seq_printf(m, "nr_tags=%u\n", tags->nr_tags); 354d96b37c0SOmar Sandoval seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags); 355d96b37c0SOmar Sandoval seq_printf(m, "active_queues=%d\n", 356d96b37c0SOmar Sandoval atomic_read(&tags->active_queues)); 357d96b37c0SOmar Sandoval 358d96b37c0SOmar Sandoval seq_puts(m, "\nbitmap_tags:\n"); 359d96b37c0SOmar Sandoval sbitmap_queue_show(&tags->bitmap_tags, m); 360d96b37c0SOmar Sandoval 361d96b37c0SOmar Sandoval if (tags->nr_reserved_tags) { 362d96b37c0SOmar Sandoval seq_puts(m, "\nbreserved_tags:\n"); 363d96b37c0SOmar Sandoval sbitmap_queue_show(&tags->breserved_tags, m); 364d96b37c0SOmar Sandoval } 365d96b37c0SOmar Sandoval } 366d96b37c0SOmar Sandoval 367f57de23aSOmar Sandoval static int hctx_tags_show(void *data, struct seq_file *m) 368d96b37c0SOmar Sandoval { 369f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 370d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 3718c0f14eaSBart Van Assche int res; 372d96b37c0SOmar Sandoval 3738c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 3748c0f14eaSBart Van Assche if (res) 3758c0f14eaSBart Van Assche goto out; 376d96b37c0SOmar Sandoval if (hctx->tags) 377d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->tags); 378d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 379d96b37c0SOmar Sandoval 3808c0f14eaSBart Van Assche out: 3818c0f14eaSBart Van Assche return res; 382d96b37c0SOmar Sandoval } 383d96b37c0SOmar Sandoval 384f57de23aSOmar Sandoval static int hctx_tags_bitmap_show(void *data, struct seq_file *m) 385d96b37c0SOmar Sandoval { 386f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 387d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 3888c0f14eaSBart Van Assche int res; 389d7e3621aSOmar Sandoval 3908c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 3918c0f14eaSBart Van Assche if (res) 3928c0f14eaSBart Van Assche goto out; 393d7e3621aSOmar Sandoval if (hctx->tags) 394d7e3621aSOmar Sandoval sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m); 395d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 3968c0f14eaSBart Van Assche 3978c0f14eaSBart Van Assche out: 3988c0f14eaSBart Van Assche return res; 399d7e3621aSOmar Sandoval } 400d7e3621aSOmar Sandoval 401f57de23aSOmar Sandoval static int hctx_sched_tags_show(void *data, struct seq_file *m) 402d7e3621aSOmar Sandoval { 403f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 404d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 4058c0f14eaSBart Van Assche int res; 406d96b37c0SOmar Sandoval 4078c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4088c0f14eaSBart Van Assche if (res) 4098c0f14eaSBart Van Assche goto out; 410d96b37c0SOmar Sandoval if (hctx->sched_tags) 411d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->sched_tags); 412d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 413d96b37c0SOmar Sandoval 4148c0f14eaSBart Van Assche out: 4158c0f14eaSBart Van Assche return res; 416d96b37c0SOmar Sandoval } 417d96b37c0SOmar Sandoval 418f57de23aSOmar Sandoval static int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m) 419d96b37c0SOmar Sandoval { 420f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 421d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 4228c0f14eaSBart Van Assche int res; 423d7e3621aSOmar Sandoval 4248c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4258c0f14eaSBart Van Assche if (res) 4268c0f14eaSBart Van Assche goto out; 427d7e3621aSOmar Sandoval if (hctx->sched_tags) 428d7e3621aSOmar Sandoval sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m); 429d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 4308c0f14eaSBart Van Assche 4318c0f14eaSBart Van Assche out: 4328c0f14eaSBart Van Assche return res; 433d7e3621aSOmar Sandoval } 434d7e3621aSOmar Sandoval 435f57de23aSOmar Sandoval static int hctx_io_poll_show(void *data, struct seq_file *m) 436d7e3621aSOmar Sandoval { 437f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 438be215473SOmar Sandoval 439be215473SOmar Sandoval seq_printf(m, "considered=%lu\n", hctx->poll_considered); 440be215473SOmar Sandoval seq_printf(m, "invoked=%lu\n", hctx->poll_invoked); 441be215473SOmar Sandoval seq_printf(m, "success=%lu\n", hctx->poll_success); 442be215473SOmar Sandoval return 0; 443be215473SOmar Sandoval } 444be215473SOmar Sandoval 445f57de23aSOmar Sandoval static ssize_t hctx_io_poll_write(void *data, const char __user *buf, 446be215473SOmar Sandoval size_t count, loff_t *ppos) 447be215473SOmar Sandoval { 448f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 449be215473SOmar Sandoval 450be215473SOmar Sandoval hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0; 451be215473SOmar Sandoval return count; 452be215473SOmar Sandoval } 453be215473SOmar Sandoval 454f57de23aSOmar Sandoval static int hctx_dispatched_show(void *data, struct seq_file *m) 455be215473SOmar Sandoval { 456f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 457be215473SOmar Sandoval int i; 458be215473SOmar Sandoval 459be215473SOmar Sandoval seq_printf(m, "%8u\t%lu\n", 0U, hctx->dispatched[0]); 460be215473SOmar Sandoval 461be215473SOmar Sandoval for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) { 462be215473SOmar Sandoval unsigned int d = 1U << (i - 1); 463be215473SOmar Sandoval 464be215473SOmar Sandoval seq_printf(m, "%8u\t%lu\n", d, hctx->dispatched[i]); 465be215473SOmar Sandoval } 466be215473SOmar Sandoval 467be215473SOmar Sandoval seq_printf(m, "%8u+\t%lu\n", 1U << (i - 1), hctx->dispatched[i]); 468be215473SOmar Sandoval return 0; 469be215473SOmar Sandoval } 470be215473SOmar Sandoval 471f57de23aSOmar Sandoval static ssize_t hctx_dispatched_write(void *data, const char __user *buf, 472be215473SOmar Sandoval size_t count, loff_t *ppos) 473be215473SOmar Sandoval { 474f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 475be215473SOmar Sandoval int i; 476be215473SOmar Sandoval 477be215473SOmar Sandoval for (i = 0; i < BLK_MQ_MAX_DISPATCH_ORDER; i++) 478be215473SOmar Sandoval hctx->dispatched[i] = 0; 479be215473SOmar Sandoval return count; 480be215473SOmar Sandoval } 481be215473SOmar Sandoval 482f57de23aSOmar Sandoval static int hctx_queued_show(void *data, struct seq_file *m) 4834a46f05eSOmar Sandoval { 484f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 4854a46f05eSOmar Sandoval 4864a46f05eSOmar Sandoval seq_printf(m, "%lu\n", hctx->queued); 4874a46f05eSOmar Sandoval return 0; 4884a46f05eSOmar Sandoval } 4894a46f05eSOmar Sandoval 490f57de23aSOmar Sandoval static ssize_t hctx_queued_write(void *data, const char __user *buf, 4914a46f05eSOmar Sandoval size_t count, loff_t *ppos) 4924a46f05eSOmar Sandoval { 493f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 4944a46f05eSOmar Sandoval 4954a46f05eSOmar Sandoval hctx->queued = 0; 4964a46f05eSOmar Sandoval return count; 4974a46f05eSOmar Sandoval } 4984a46f05eSOmar Sandoval 499f57de23aSOmar Sandoval static int hctx_run_show(void *data, struct seq_file *m) 5004a46f05eSOmar Sandoval { 501f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5024a46f05eSOmar Sandoval 5034a46f05eSOmar Sandoval seq_printf(m, "%lu\n", hctx->run); 5044a46f05eSOmar Sandoval return 0; 5054a46f05eSOmar Sandoval } 5064a46f05eSOmar Sandoval 507f57de23aSOmar Sandoval static ssize_t hctx_run_write(void *data, const char __user *buf, size_t count, 508f57de23aSOmar Sandoval loff_t *ppos) 5094a46f05eSOmar Sandoval { 510f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5114a46f05eSOmar Sandoval 5124a46f05eSOmar Sandoval hctx->run = 0; 5134a46f05eSOmar Sandoval return count; 5144a46f05eSOmar Sandoval } 5154a46f05eSOmar Sandoval 516f57de23aSOmar Sandoval static int hctx_active_show(void *data, struct seq_file *m) 5174a46f05eSOmar Sandoval { 518f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5194a46f05eSOmar Sandoval 5204a46f05eSOmar Sandoval seq_printf(m, "%d\n", atomic_read(&hctx->nr_active)); 5214a46f05eSOmar Sandoval return 0; 5224a46f05eSOmar Sandoval } 5234a46f05eSOmar Sandoval 524950cd7e9SOmar Sandoval static void *ctx_rq_list_start(struct seq_file *m, loff_t *pos) 525f3bcb0e6SBart Van Assche __acquires(&ctx->lock) 526950cd7e9SOmar Sandoval { 527950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 528950cd7e9SOmar Sandoval 529950cd7e9SOmar Sandoval spin_lock(&ctx->lock); 530950cd7e9SOmar Sandoval return seq_list_start(&ctx->rq_list, *pos); 531950cd7e9SOmar Sandoval } 532950cd7e9SOmar Sandoval 533950cd7e9SOmar Sandoval static void *ctx_rq_list_next(struct seq_file *m, void *v, loff_t *pos) 534950cd7e9SOmar Sandoval { 535950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 536950cd7e9SOmar Sandoval 537950cd7e9SOmar Sandoval return seq_list_next(v, &ctx->rq_list, pos); 538950cd7e9SOmar Sandoval } 539950cd7e9SOmar Sandoval 540950cd7e9SOmar Sandoval static void ctx_rq_list_stop(struct seq_file *m, void *v) 541f3bcb0e6SBart Van Assche __releases(&ctx->lock) 542950cd7e9SOmar Sandoval { 543950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 544950cd7e9SOmar Sandoval 545950cd7e9SOmar Sandoval spin_unlock(&ctx->lock); 546950cd7e9SOmar Sandoval } 547950cd7e9SOmar Sandoval 548950cd7e9SOmar Sandoval static const struct seq_operations ctx_rq_list_seq_ops = { 549950cd7e9SOmar Sandoval .start = ctx_rq_list_start, 550950cd7e9SOmar Sandoval .next = ctx_rq_list_next, 551950cd7e9SOmar Sandoval .stop = ctx_rq_list_stop, 552950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 553950cd7e9SOmar Sandoval }; 554f57de23aSOmar Sandoval static int ctx_dispatched_show(void *data, struct seq_file *m) 555950cd7e9SOmar Sandoval { 556f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 5574a46f05eSOmar Sandoval 5584a46f05eSOmar Sandoval seq_printf(m, "%lu %lu\n", ctx->rq_dispatched[1], ctx->rq_dispatched[0]); 5594a46f05eSOmar Sandoval return 0; 5604a46f05eSOmar Sandoval } 5614a46f05eSOmar Sandoval 562f57de23aSOmar Sandoval static ssize_t ctx_dispatched_write(void *data, const char __user *buf, 5634a46f05eSOmar Sandoval size_t count, loff_t *ppos) 5644a46f05eSOmar Sandoval { 565f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 5664a46f05eSOmar Sandoval 5674a46f05eSOmar Sandoval ctx->rq_dispatched[0] = ctx->rq_dispatched[1] = 0; 5684a46f05eSOmar Sandoval return count; 5694a46f05eSOmar Sandoval } 5704a46f05eSOmar Sandoval 571f57de23aSOmar Sandoval static int ctx_merged_show(void *data, struct seq_file *m) 5724a46f05eSOmar Sandoval { 573f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 5744a46f05eSOmar Sandoval 5754a46f05eSOmar Sandoval seq_printf(m, "%lu\n", ctx->rq_merged); 5764a46f05eSOmar Sandoval return 0; 5774a46f05eSOmar Sandoval } 5784a46f05eSOmar Sandoval 579f57de23aSOmar Sandoval static ssize_t ctx_merged_write(void *data, const char __user *buf, 5804a46f05eSOmar Sandoval size_t count, loff_t *ppos) 5814a46f05eSOmar Sandoval { 582f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 5834a46f05eSOmar Sandoval 5844a46f05eSOmar Sandoval ctx->rq_merged = 0; 5854a46f05eSOmar Sandoval return count; 5864a46f05eSOmar Sandoval } 5874a46f05eSOmar Sandoval 588f57de23aSOmar Sandoval static int ctx_completed_show(void *data, struct seq_file *m) 5894a46f05eSOmar Sandoval { 590f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 5914a46f05eSOmar Sandoval 5924a46f05eSOmar Sandoval seq_printf(m, "%lu %lu\n", ctx->rq_completed[1], ctx->rq_completed[0]); 5934a46f05eSOmar Sandoval return 0; 5944a46f05eSOmar Sandoval } 5954a46f05eSOmar Sandoval 596f57de23aSOmar Sandoval static ssize_t ctx_completed_write(void *data, const char __user *buf, 5974a46f05eSOmar Sandoval size_t count, loff_t *ppos) 5984a46f05eSOmar Sandoval { 599f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6004a46f05eSOmar Sandoval 6014a46f05eSOmar Sandoval ctx->rq_completed[0] = ctx->rq_completed[1] = 0; 6024a46f05eSOmar Sandoval return count; 6034a46f05eSOmar Sandoval } 6044a46f05eSOmar Sandoval 605f57de23aSOmar Sandoval static int blk_mq_debugfs_show(struct seq_file *m, void *v) 606f57de23aSOmar Sandoval { 607f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 608f57de23aSOmar Sandoval void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private; 609f57de23aSOmar Sandoval 610f57de23aSOmar Sandoval return attr->show(data, m); 611f57de23aSOmar Sandoval } 612f57de23aSOmar Sandoval 613f57de23aSOmar Sandoval static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf, 614f57de23aSOmar Sandoval size_t count, loff_t *ppos) 615f57de23aSOmar Sandoval { 616f57de23aSOmar Sandoval struct seq_file *m = file->private_data; 617f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 618f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 619f57de23aSOmar Sandoval 620f57de23aSOmar Sandoval if (!attr->write) 621f57de23aSOmar Sandoval return -EPERM; 622f57de23aSOmar Sandoval 623f57de23aSOmar Sandoval return attr->write(data, buf, count, ppos); 624f57de23aSOmar Sandoval } 625f57de23aSOmar Sandoval 626f57de23aSOmar Sandoval static int blk_mq_debugfs_open(struct inode *inode, struct file *file) 627f57de23aSOmar Sandoval { 628f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 629f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 630f57de23aSOmar Sandoval struct seq_file *m; 631f57de23aSOmar Sandoval int ret; 632f57de23aSOmar Sandoval 633f57de23aSOmar Sandoval if (attr->seq_ops) { 634f57de23aSOmar Sandoval ret = seq_open(file, attr->seq_ops); 635f57de23aSOmar Sandoval if (!ret) { 636f57de23aSOmar Sandoval m = file->private_data; 637f57de23aSOmar Sandoval m->private = data; 638f57de23aSOmar Sandoval } 639f57de23aSOmar Sandoval return ret; 640f57de23aSOmar Sandoval } 641f57de23aSOmar Sandoval 642f57de23aSOmar Sandoval if (WARN_ON_ONCE(!attr->show)) 643f57de23aSOmar Sandoval return -EPERM; 644f57de23aSOmar Sandoval 645f57de23aSOmar Sandoval return single_open(file, blk_mq_debugfs_show, inode->i_private); 646f57de23aSOmar Sandoval } 647f57de23aSOmar Sandoval 648f57de23aSOmar Sandoval static int blk_mq_debugfs_release(struct inode *inode, struct file *file) 649f57de23aSOmar Sandoval { 650f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 651f57de23aSOmar Sandoval 652f57de23aSOmar Sandoval if (attr->show) 653f57de23aSOmar Sandoval return single_release(inode, file); 654f57de23aSOmar Sandoval else 655f57de23aSOmar Sandoval return seq_release(inode, file); 656f57de23aSOmar Sandoval } 657f57de23aSOmar Sandoval 658f57de23aSOmar Sandoval const struct file_operations blk_mq_debugfs_fops = { 659f57de23aSOmar Sandoval .open = blk_mq_debugfs_open, 6604a46f05eSOmar Sandoval .read = seq_read, 661f57de23aSOmar Sandoval .write = blk_mq_debugfs_write, 6624a46f05eSOmar Sandoval .llseek = seq_lseek, 663f57de23aSOmar Sandoval .release = blk_mq_debugfs_release, 6644a46f05eSOmar Sandoval }; 6654a46f05eSOmar Sandoval 66634dbad5dSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = { 667f57de23aSOmar Sandoval {"poll_stat", 0400, queue_poll_stat_show}, 668f57de23aSOmar Sandoval {"state", 0600, queue_state_show, queue_state_write}, 66934dbad5dSOmar Sandoval {}, 67034dbad5dSOmar Sandoval }; 67134dbad5dSOmar Sandoval 67207e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { 673f57de23aSOmar Sandoval {"state", 0400, hctx_state_show}, 674f57de23aSOmar Sandoval {"flags", 0400, hctx_flags_show}, 675f57de23aSOmar Sandoval {"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops}, 676f57de23aSOmar Sandoval {"ctx_map", 0400, hctx_ctx_map_show}, 677f57de23aSOmar Sandoval {"tags", 0400, hctx_tags_show}, 678f57de23aSOmar Sandoval {"tags_bitmap", 0400, hctx_tags_bitmap_show}, 679f57de23aSOmar Sandoval {"sched_tags", 0400, hctx_sched_tags_show}, 680f57de23aSOmar Sandoval {"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show}, 681f57de23aSOmar Sandoval {"io_poll", 0600, hctx_io_poll_show, hctx_io_poll_write}, 682f57de23aSOmar Sandoval {"dispatched", 0600, hctx_dispatched_show, hctx_dispatched_write}, 683f57de23aSOmar Sandoval {"queued", 0600, hctx_queued_show, hctx_queued_write}, 684f57de23aSOmar Sandoval {"run", 0600, hctx_run_show, hctx_run_write}, 685f57de23aSOmar Sandoval {"active", 0400, hctx_active_show}, 68672f2f8f6SBart Van Assche {}, 68707e4feadSOmar Sandoval }; 68807e4feadSOmar Sandoval 68907e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = { 690f57de23aSOmar Sandoval {"rq_list", 0400, .seq_ops = &ctx_rq_list_seq_ops}, 691f57de23aSOmar Sandoval {"dispatched", 0600, ctx_dispatched_show, ctx_dispatched_write}, 692f57de23aSOmar Sandoval {"merged", 0600, ctx_merged_show, ctx_merged_write}, 693f57de23aSOmar Sandoval {"completed", 0600, ctx_completed_show, ctx_completed_write}, 69472f2f8f6SBart Van Assche {}, 69507e4feadSOmar Sandoval }; 69607e4feadSOmar Sandoval 69772f2f8f6SBart Van Assche static bool debugfs_create_files(struct dentry *parent, void *data, 69872f2f8f6SBart Van Assche const struct blk_mq_debugfs_attr *attr) 69972f2f8f6SBart Van Assche { 700f57de23aSOmar Sandoval d_inode(parent)->i_private = data; 701f57de23aSOmar Sandoval 70272f2f8f6SBart Van Assche for (; attr->name; attr++) { 70372f2f8f6SBart Van Assche if (!debugfs_create_file(attr->name, attr->mode, parent, 704f57de23aSOmar Sandoval (void *)attr, &blk_mq_debugfs_fops)) 70572f2f8f6SBart Van Assche return false; 70672f2f8f6SBart Van Assche } 70772f2f8f6SBart Van Assche return true; 70872f2f8f6SBart Van Assche } 70972f2f8f6SBart Van Assche 7109c1051aaSOmar Sandoval int blk_mq_debugfs_register(struct request_queue *q) 7119c1051aaSOmar Sandoval { 7129c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 7139c1051aaSOmar Sandoval int i; 7149c1051aaSOmar Sandoval 7159c1051aaSOmar Sandoval if (!blk_debugfs_root) 7169c1051aaSOmar Sandoval return -ENOENT; 7179c1051aaSOmar Sandoval 7189c1051aaSOmar Sandoval q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent), 7199c1051aaSOmar Sandoval blk_debugfs_root); 7209c1051aaSOmar Sandoval if (!q->debugfs_dir) 7219c1051aaSOmar Sandoval return -ENOMEM; 7229c1051aaSOmar Sandoval 7239c1051aaSOmar Sandoval if (!debugfs_create_files(q->debugfs_dir, q, 7249c1051aaSOmar Sandoval blk_mq_debugfs_queue_attrs)) 7259c1051aaSOmar Sandoval goto err; 7269c1051aaSOmar Sandoval 7279c1051aaSOmar Sandoval /* 7289c1051aaSOmar Sandoval * blk_mq_init_hctx() attempted to do this already, but q->debugfs_dir 7299c1051aaSOmar Sandoval * didn't exist yet (because we don't know what to name the directory 7309c1051aaSOmar Sandoval * until the queue is registered to a gendisk). 7319c1051aaSOmar Sandoval */ 7329c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) { 7339c1051aaSOmar Sandoval if (!hctx->debugfs_dir && blk_mq_debugfs_register_hctx(q, hctx)) 7349c1051aaSOmar Sandoval goto err; 735d332ce09SOmar Sandoval if (q->elevator && !hctx->sched_debugfs_dir && 736d332ce09SOmar Sandoval blk_mq_debugfs_register_sched_hctx(q, hctx)) 737d332ce09SOmar Sandoval goto err; 7389c1051aaSOmar Sandoval } 7399c1051aaSOmar Sandoval 7409c1051aaSOmar Sandoval return 0; 7419c1051aaSOmar Sandoval 7429c1051aaSOmar Sandoval err: 7439c1051aaSOmar Sandoval blk_mq_debugfs_unregister(q); 7449c1051aaSOmar Sandoval return -ENOMEM; 7459c1051aaSOmar Sandoval } 7469c1051aaSOmar Sandoval 7479c1051aaSOmar Sandoval void blk_mq_debugfs_unregister(struct request_queue *q) 7489c1051aaSOmar Sandoval { 7499c1051aaSOmar Sandoval debugfs_remove_recursive(q->debugfs_dir); 750d332ce09SOmar Sandoval q->sched_debugfs_dir = NULL; 7519c1051aaSOmar Sandoval q->debugfs_dir = NULL; 7529c1051aaSOmar Sandoval } 7539c1051aaSOmar Sandoval 7549c1051aaSOmar Sandoval static int blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx, 7559c1051aaSOmar Sandoval struct blk_mq_ctx *ctx) 75607e4feadSOmar Sandoval { 75707e4feadSOmar Sandoval struct dentry *ctx_dir; 75807e4feadSOmar Sandoval char name[20]; 75907e4feadSOmar Sandoval 76007e4feadSOmar Sandoval snprintf(name, sizeof(name), "cpu%u", ctx->cpu); 7619c1051aaSOmar Sandoval ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir); 76207e4feadSOmar Sandoval if (!ctx_dir) 76307e4feadSOmar Sandoval return -ENOMEM; 76407e4feadSOmar Sandoval 76572f2f8f6SBart Van Assche if (!debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs)) 76607e4feadSOmar Sandoval return -ENOMEM; 76707e4feadSOmar Sandoval 76807e4feadSOmar Sandoval return 0; 76907e4feadSOmar Sandoval } 77007e4feadSOmar Sandoval 7719c1051aaSOmar Sandoval int blk_mq_debugfs_register_hctx(struct request_queue *q, 77207e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx) 77307e4feadSOmar Sandoval { 77407e4feadSOmar Sandoval struct blk_mq_ctx *ctx; 77507e4feadSOmar Sandoval char name[20]; 77607e4feadSOmar Sandoval int i; 77707e4feadSOmar Sandoval 77807e4feadSOmar Sandoval if (!q->debugfs_dir) 77907e4feadSOmar Sandoval return -ENOENT; 78007e4feadSOmar Sandoval 7819c1051aaSOmar Sandoval snprintf(name, sizeof(name), "hctx%u", hctx->queue_num); 7829c1051aaSOmar Sandoval hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir); 7839c1051aaSOmar Sandoval if (!hctx->debugfs_dir) 7849c1051aaSOmar Sandoval return -ENOMEM; 7859c1051aaSOmar Sandoval 7869c1051aaSOmar Sandoval if (!debugfs_create_files(hctx->debugfs_dir, hctx, 7879c1051aaSOmar Sandoval blk_mq_debugfs_hctx_attrs)) 78807e4feadSOmar Sandoval goto err; 78907e4feadSOmar Sandoval 7909c1051aaSOmar Sandoval hctx_for_each_ctx(hctx, ctx, i) { 7919c1051aaSOmar Sandoval if (blk_mq_debugfs_register_ctx(hctx, ctx)) 79207e4feadSOmar Sandoval goto err; 79307e4feadSOmar Sandoval } 79407e4feadSOmar Sandoval 79507e4feadSOmar Sandoval return 0; 79607e4feadSOmar Sandoval 79707e4feadSOmar Sandoval err: 7989c1051aaSOmar Sandoval blk_mq_debugfs_unregister_hctx(hctx); 79907e4feadSOmar Sandoval return -ENOMEM; 80007e4feadSOmar Sandoval } 80107e4feadSOmar Sandoval 8029c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx) 80307e4feadSOmar Sandoval { 8049c1051aaSOmar Sandoval debugfs_remove_recursive(hctx->debugfs_dir); 805d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 8069c1051aaSOmar Sandoval hctx->debugfs_dir = NULL; 8079c1051aaSOmar Sandoval } 8089c1051aaSOmar Sandoval 8099c1051aaSOmar Sandoval int blk_mq_debugfs_register_hctxs(struct request_queue *q) 8109c1051aaSOmar Sandoval { 8119c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 8129c1051aaSOmar Sandoval int i; 8139c1051aaSOmar Sandoval 8149c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) { 8159c1051aaSOmar Sandoval if (blk_mq_debugfs_register_hctx(q, hctx)) 8169c1051aaSOmar Sandoval return -ENOMEM; 8179c1051aaSOmar Sandoval } 8189c1051aaSOmar Sandoval 8199c1051aaSOmar Sandoval return 0; 8209c1051aaSOmar Sandoval } 8219c1051aaSOmar Sandoval 8229c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q) 8239c1051aaSOmar Sandoval { 8249c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 8259c1051aaSOmar Sandoval int i; 8269c1051aaSOmar Sandoval 8279c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) 8289c1051aaSOmar Sandoval blk_mq_debugfs_unregister_hctx(hctx); 82907e4feadSOmar Sandoval } 830d332ce09SOmar Sandoval 831d332ce09SOmar Sandoval int blk_mq_debugfs_register_sched(struct request_queue *q) 832d332ce09SOmar Sandoval { 833d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 834d332ce09SOmar Sandoval 835d332ce09SOmar Sandoval if (!q->debugfs_dir) 836d332ce09SOmar Sandoval return -ENOENT; 837d332ce09SOmar Sandoval 838d332ce09SOmar Sandoval if (!e->queue_debugfs_attrs) 839d332ce09SOmar Sandoval return 0; 840d332ce09SOmar Sandoval 841d332ce09SOmar Sandoval q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir); 842d332ce09SOmar Sandoval if (!q->sched_debugfs_dir) 843d332ce09SOmar Sandoval return -ENOMEM; 844d332ce09SOmar Sandoval 845d332ce09SOmar Sandoval if (!debugfs_create_files(q->sched_debugfs_dir, q, 846d332ce09SOmar Sandoval e->queue_debugfs_attrs)) 847d332ce09SOmar Sandoval goto err; 848d332ce09SOmar Sandoval 849d332ce09SOmar Sandoval return 0; 850d332ce09SOmar Sandoval 851d332ce09SOmar Sandoval err: 852d332ce09SOmar Sandoval blk_mq_debugfs_unregister_sched(q); 853d332ce09SOmar Sandoval return -ENOMEM; 854d332ce09SOmar Sandoval } 855d332ce09SOmar Sandoval 856d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched(struct request_queue *q) 857d332ce09SOmar Sandoval { 858d332ce09SOmar Sandoval debugfs_remove_recursive(q->sched_debugfs_dir); 859d332ce09SOmar Sandoval q->sched_debugfs_dir = NULL; 860d332ce09SOmar Sandoval } 861d332ce09SOmar Sandoval 862d332ce09SOmar Sandoval int blk_mq_debugfs_register_sched_hctx(struct request_queue *q, 863d332ce09SOmar Sandoval struct blk_mq_hw_ctx *hctx) 864d332ce09SOmar Sandoval { 865d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 866d332ce09SOmar Sandoval 867d332ce09SOmar Sandoval if (!hctx->debugfs_dir) 868d332ce09SOmar Sandoval return -ENOENT; 869d332ce09SOmar Sandoval 870d332ce09SOmar Sandoval if (!e->hctx_debugfs_attrs) 871d332ce09SOmar Sandoval return 0; 872d332ce09SOmar Sandoval 873d332ce09SOmar Sandoval hctx->sched_debugfs_dir = debugfs_create_dir("sched", 874d332ce09SOmar Sandoval hctx->debugfs_dir); 875d332ce09SOmar Sandoval if (!hctx->sched_debugfs_dir) 876d332ce09SOmar Sandoval return -ENOMEM; 877d332ce09SOmar Sandoval 878d332ce09SOmar Sandoval if (!debugfs_create_files(hctx->sched_debugfs_dir, hctx, 879d332ce09SOmar Sandoval e->hctx_debugfs_attrs)) 880d332ce09SOmar Sandoval return -ENOMEM; 881d332ce09SOmar Sandoval 882d332ce09SOmar Sandoval return 0; 883d332ce09SOmar Sandoval } 884d332ce09SOmar Sandoval 885d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx) 886d332ce09SOmar Sandoval { 887d332ce09SOmar Sandoval debugfs_remove_recursive(hctx->sched_debugfs_dir); 888d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 889d332ce09SOmar Sandoval } 890