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); 117edea55abSBart Van Assche } else if (strcmp(op, "kick") == 0) { 118edea55abSBart Van Assche blk_mq_kick_requeue_list(q); 11991d68905SBart Van Assche } else { 120c7e4145aSOmar Sandoval pr_err("%s: unsupported operation '%s'\n", __func__, op); 121c7e4145aSOmar Sandoval inval: 122edea55abSBart Van Assche pr_err("%s: use 'run', 'start' or 'kick'\n", __func__); 12391d68905SBart Van Assche return -EINVAL; 12491d68905SBart Van Assche } 125c7e4145aSOmar Sandoval return count; 12691d68905SBart Van Assche } 12791d68905SBart Van Assche 12834dbad5dSOmar Sandoval static void print_stat(struct seq_file *m, struct blk_rq_stat *stat) 12934dbad5dSOmar Sandoval { 13034dbad5dSOmar Sandoval if (stat->nr_samples) { 13134dbad5dSOmar Sandoval seq_printf(m, "samples=%d, mean=%lld, min=%llu, max=%llu", 13234dbad5dSOmar Sandoval stat->nr_samples, stat->mean, stat->min, stat->max); 13334dbad5dSOmar Sandoval } else { 13434dbad5dSOmar Sandoval seq_puts(m, "samples=0"); 13534dbad5dSOmar Sandoval } 13634dbad5dSOmar Sandoval } 13734dbad5dSOmar Sandoval 138*f793dfd3SJens Axboe static int queue_write_hint_show(void *data, struct seq_file *m) 139*f793dfd3SJens Axboe { 140*f793dfd3SJens Axboe struct request_queue *q = data; 141*f793dfd3SJens Axboe int i; 142*f793dfd3SJens Axboe 143*f793dfd3SJens Axboe for (i = 0; i < BLK_MAX_WRITE_HINTS; i++) 144*f793dfd3SJens Axboe seq_printf(m, "hint%d: %llu\n", i, q->write_hints[i]); 145*f793dfd3SJens Axboe 146*f793dfd3SJens Axboe return 0; 147*f793dfd3SJens Axboe } 148*f793dfd3SJens Axboe 149*f793dfd3SJens Axboe static ssize_t queue_write_hint_store(void *data, const char __user *buf, 150*f793dfd3SJens Axboe size_t count, loff_t *ppos) 151*f793dfd3SJens Axboe { 152*f793dfd3SJens Axboe struct request_queue *q = data; 153*f793dfd3SJens Axboe int i; 154*f793dfd3SJens Axboe 155*f793dfd3SJens Axboe for (i = 0; i < BLK_MAX_WRITE_HINTS; i++) 156*f793dfd3SJens Axboe q->write_hints[i] = 0; 157*f793dfd3SJens Axboe 158*f793dfd3SJens Axboe return count; 159*f793dfd3SJens Axboe } 160*f793dfd3SJens Axboe 161f57de23aSOmar Sandoval static int queue_poll_stat_show(void *data, struct seq_file *m) 16234dbad5dSOmar Sandoval { 163f57de23aSOmar Sandoval struct request_queue *q = data; 1640206319fSStephen Bates int bucket; 16534dbad5dSOmar Sandoval 1660206319fSStephen Bates for (bucket = 0; bucket < BLK_MQ_POLL_STATS_BKTS/2; bucket++) { 1670206319fSStephen Bates seq_printf(m, "read (%d Bytes): ", 1 << (9+bucket)); 1680206319fSStephen Bates print_stat(m, &q->poll_stat[2*bucket]); 16934dbad5dSOmar Sandoval seq_puts(m, "\n"); 17034dbad5dSOmar Sandoval 1710206319fSStephen Bates seq_printf(m, "write (%d Bytes): ", 1 << (9+bucket)); 1720206319fSStephen Bates print_stat(m, &q->poll_stat[2*bucket+1]); 17334dbad5dSOmar Sandoval seq_puts(m, "\n"); 1740206319fSStephen Bates } 17534dbad5dSOmar Sandoval return 0; 17634dbad5dSOmar Sandoval } 17734dbad5dSOmar Sandoval 1781a435111SOmar Sandoval #define HCTX_STATE_NAME(name) [BLK_MQ_S_##name] = #name 179f5c0b091SBart Van Assche static const char *const hctx_state_name[] = { 1801a435111SOmar Sandoval HCTX_STATE_NAME(STOPPED), 1811a435111SOmar Sandoval HCTX_STATE_NAME(TAG_ACTIVE), 1821a435111SOmar Sandoval HCTX_STATE_NAME(SCHED_RESTART), 1831a435111SOmar Sandoval HCTX_STATE_NAME(TAG_WAITING), 1841a435111SOmar Sandoval HCTX_STATE_NAME(START_ON_RUN), 185f5c0b091SBart Van Assche }; 1861a435111SOmar Sandoval #undef HCTX_STATE_NAME 1871a435111SOmar Sandoval 188f57de23aSOmar Sandoval static int hctx_state_show(void *data, struct seq_file *m) 1899abb2ad2SOmar Sandoval { 190f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 1919abb2ad2SOmar Sandoval 192f5c0b091SBart Van Assche blk_flags_show(m, hctx->state, hctx_state_name, 193f5c0b091SBart Van Assche ARRAY_SIZE(hctx_state_name)); 194fd07dc81SBart Van Assche seq_puts(m, "\n"); 1959abb2ad2SOmar Sandoval return 0; 1969abb2ad2SOmar Sandoval } 1979abb2ad2SOmar Sandoval 1981a435111SOmar Sandoval #define BLK_TAG_ALLOC_NAME(name) [BLK_TAG_ALLOC_##name] = #name 199f5c0b091SBart Van Assche static const char *const alloc_policy_name[] = { 2001a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(FIFO), 2011a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(RR), 202f5c0b091SBart Van Assche }; 2031a435111SOmar Sandoval #undef BLK_TAG_ALLOC_NAME 204f5c0b091SBart Van Assche 2051a435111SOmar Sandoval #define HCTX_FLAG_NAME(name) [ilog2(BLK_MQ_F_##name)] = #name 206f5c0b091SBart Van Assche static const char *const hctx_flag_name[] = { 2071a435111SOmar Sandoval HCTX_FLAG_NAME(SHOULD_MERGE), 2081a435111SOmar Sandoval HCTX_FLAG_NAME(TAG_SHARED), 2091a435111SOmar Sandoval HCTX_FLAG_NAME(SG_MERGE), 2101a435111SOmar Sandoval HCTX_FLAG_NAME(BLOCKING), 2111a435111SOmar Sandoval HCTX_FLAG_NAME(NO_SCHED), 212f5c0b091SBart Van Assche }; 2131a435111SOmar Sandoval #undef HCTX_FLAG_NAME 214f5c0b091SBart Van Assche 215f57de23aSOmar Sandoval static int hctx_flags_show(void *data, struct seq_file *m) 2169abb2ad2SOmar Sandoval { 217f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 218f5c0b091SBart Van Assche const int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(hctx->flags); 2199abb2ad2SOmar Sandoval 220f5c0b091SBart Van Assche seq_puts(m, "alloc_policy="); 221f5c0b091SBart Van Assche if (alloc_policy < ARRAY_SIZE(alloc_policy_name) && 222f5c0b091SBart Van Assche alloc_policy_name[alloc_policy]) 223f5c0b091SBart Van Assche seq_puts(m, alloc_policy_name[alloc_policy]); 224f5c0b091SBart Van Assche else 225f5c0b091SBart Van Assche seq_printf(m, "%d", alloc_policy); 226f5c0b091SBart Van Assche seq_puts(m, " "); 227f5c0b091SBart Van Assche blk_flags_show(m, 228f5c0b091SBart Van Assche hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy), 229f5c0b091SBart Van Assche hctx_flag_name, ARRAY_SIZE(hctx_flag_name)); 230fd07dc81SBart Van Assche seq_puts(m, "\n"); 2319abb2ad2SOmar Sandoval return 0; 2329abb2ad2SOmar Sandoval } 2339abb2ad2SOmar Sandoval 2341a435111SOmar Sandoval #define REQ_OP_NAME(name) [REQ_OP_##name] = #name 2358658dca8SBart Van Assche static const char *const op_name[] = { 2361a435111SOmar Sandoval REQ_OP_NAME(READ), 2371a435111SOmar Sandoval REQ_OP_NAME(WRITE), 2381a435111SOmar Sandoval REQ_OP_NAME(FLUSH), 2391a435111SOmar Sandoval REQ_OP_NAME(DISCARD), 2401a435111SOmar Sandoval REQ_OP_NAME(ZONE_REPORT), 2411a435111SOmar Sandoval REQ_OP_NAME(SECURE_ERASE), 2421a435111SOmar Sandoval REQ_OP_NAME(ZONE_RESET), 2431a435111SOmar Sandoval REQ_OP_NAME(WRITE_SAME), 2441a435111SOmar Sandoval REQ_OP_NAME(WRITE_ZEROES), 2451a435111SOmar Sandoval REQ_OP_NAME(SCSI_IN), 2461a435111SOmar Sandoval REQ_OP_NAME(SCSI_OUT), 2471a435111SOmar Sandoval REQ_OP_NAME(DRV_IN), 2481a435111SOmar Sandoval REQ_OP_NAME(DRV_OUT), 2498658dca8SBart Van Assche }; 2501a435111SOmar Sandoval #undef REQ_OP_NAME 2518658dca8SBart Van Assche 2521a435111SOmar Sandoval #define CMD_FLAG_NAME(name) [__REQ_##name] = #name 2538658dca8SBart Van Assche static const char *const cmd_flag_name[] = { 2541a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DEV), 2551a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_TRANSPORT), 2561a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DRIVER), 2571a435111SOmar Sandoval CMD_FLAG_NAME(SYNC), 2581a435111SOmar Sandoval CMD_FLAG_NAME(META), 2591a435111SOmar Sandoval CMD_FLAG_NAME(PRIO), 2601a435111SOmar Sandoval CMD_FLAG_NAME(NOMERGE), 2611a435111SOmar Sandoval CMD_FLAG_NAME(IDLE), 2621a435111SOmar Sandoval CMD_FLAG_NAME(INTEGRITY), 2631a435111SOmar Sandoval CMD_FLAG_NAME(FUA), 2641a435111SOmar Sandoval CMD_FLAG_NAME(PREFLUSH), 2651a435111SOmar Sandoval CMD_FLAG_NAME(RAHEAD), 2661a435111SOmar Sandoval CMD_FLAG_NAME(BACKGROUND), 2671a435111SOmar Sandoval CMD_FLAG_NAME(NOUNMAP), 2688658dca8SBart Van Assche }; 2691a435111SOmar Sandoval #undef CMD_FLAG_NAME 2708658dca8SBart Van Assche 2711a435111SOmar Sandoval #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name 2728658dca8SBart Van Assche static const char *const rqf_name[] = { 2731a435111SOmar Sandoval RQF_NAME(SORTED), 2741a435111SOmar Sandoval RQF_NAME(STARTED), 2751a435111SOmar Sandoval RQF_NAME(QUEUED), 2761a435111SOmar Sandoval RQF_NAME(SOFTBARRIER), 2771a435111SOmar Sandoval RQF_NAME(FLUSH_SEQ), 2781a435111SOmar Sandoval RQF_NAME(MIXED_MERGE), 2791a435111SOmar Sandoval RQF_NAME(MQ_INFLIGHT), 2801a435111SOmar Sandoval RQF_NAME(DONTPREP), 2811a435111SOmar Sandoval RQF_NAME(PREEMPT), 2821a435111SOmar Sandoval RQF_NAME(COPY_USER), 2831a435111SOmar Sandoval RQF_NAME(FAILED), 2841a435111SOmar Sandoval RQF_NAME(QUIET), 2851a435111SOmar Sandoval RQF_NAME(ELVPRIV), 2861a435111SOmar Sandoval RQF_NAME(IO_STAT), 2871a435111SOmar Sandoval RQF_NAME(ALLOCED), 2881a435111SOmar Sandoval RQF_NAME(PM), 2891a435111SOmar Sandoval RQF_NAME(HASHED), 2901a435111SOmar Sandoval RQF_NAME(STATS), 2911a435111SOmar Sandoval RQF_NAME(SPECIAL_PAYLOAD), 2928658dca8SBart Van Assche }; 2931a435111SOmar Sandoval #undef RQF_NAME 2948658dca8SBart Van Assche 295c0cb1c6dSBart Van Assche #define RQAF_NAME(name) [REQ_ATOM_##name] = #name 296c0cb1c6dSBart Van Assche static const char *const rqaf_name[] = { 297c0cb1c6dSBart Van Assche RQAF_NAME(COMPLETE), 298c0cb1c6dSBart Van Assche RQAF_NAME(STARTED), 299c0cb1c6dSBart Van Assche RQAF_NAME(POLL_SLEPT), 300c0cb1c6dSBart Van Assche }; 301c0cb1c6dSBart Van Assche #undef RQAF_NAME 302c0cb1c6dSBart Van Assche 303daaadb3eSOmar Sandoval int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq) 304950cd7e9SOmar Sandoval { 3052836ee4bSBart Van Assche const struct blk_mq_ops *const mq_ops = rq->q->mq_ops; 3068658dca8SBart Van Assche const unsigned int op = rq->cmd_flags & REQ_OP_MASK; 307950cd7e9SOmar Sandoval 3088658dca8SBart Van Assche seq_printf(m, "%p {.op=", rq); 3098658dca8SBart Van Assche if (op < ARRAY_SIZE(op_name) && op_name[op]) 3108658dca8SBart Van Assche seq_printf(m, "%s", op_name[op]); 3118658dca8SBart Van Assche else 3128658dca8SBart Van Assche seq_printf(m, "%d", op); 3138658dca8SBart Van Assche seq_puts(m, ", .cmd_flags="); 3148658dca8SBart Van Assche blk_flags_show(m, rq->cmd_flags & ~REQ_OP_MASK, cmd_flag_name, 3158658dca8SBart Van Assche ARRAY_SIZE(cmd_flag_name)); 3168658dca8SBart Van Assche seq_puts(m, ", .rq_flags="); 3178658dca8SBart Van Assche blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name, 3188658dca8SBart Van Assche ARRAY_SIZE(rqf_name)); 319c0cb1c6dSBart Van Assche seq_puts(m, ", .atomic_flags="); 320c0cb1c6dSBart Van Assche blk_flags_show(m, rq->atomic_flags, rqaf_name, ARRAY_SIZE(rqaf_name)); 3212836ee4bSBart Van Assche seq_printf(m, ", .tag=%d, .internal_tag=%d", rq->tag, 3228658dca8SBart Van Assche rq->internal_tag); 3232836ee4bSBart Van Assche if (mq_ops->show_rq) 3242836ee4bSBart Van Assche mq_ops->show_rq(m, rq); 3252836ee4bSBart Van Assche seq_puts(m, "}\n"); 326950cd7e9SOmar Sandoval return 0; 327950cd7e9SOmar Sandoval } 328daaadb3eSOmar Sandoval EXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show); 329daaadb3eSOmar Sandoval 330daaadb3eSOmar Sandoval int blk_mq_debugfs_rq_show(struct seq_file *m, void *v) 331daaadb3eSOmar Sandoval { 332daaadb3eSOmar Sandoval return __blk_mq_debugfs_rq_show(m, list_entry_rq(v)); 333daaadb3eSOmar Sandoval } 33416b738f6SOmar Sandoval EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show); 335950cd7e9SOmar Sandoval 3368ef1a191SBart Van Assche static void *queue_requeue_list_start(struct seq_file *m, loff_t *pos) 3378ef1a191SBart Van Assche __acquires(&q->requeue_lock) 3388ef1a191SBart Van Assche { 3398ef1a191SBart Van Assche struct request_queue *q = m->private; 3408ef1a191SBart Van Assche 3418ef1a191SBart Van Assche spin_lock_irq(&q->requeue_lock); 3428ef1a191SBart Van Assche return seq_list_start(&q->requeue_list, *pos); 3438ef1a191SBart Van Assche } 3448ef1a191SBart Van Assche 3458ef1a191SBart Van Assche static void *queue_requeue_list_next(struct seq_file *m, void *v, loff_t *pos) 3468ef1a191SBart Van Assche { 3478ef1a191SBart Van Assche struct request_queue *q = m->private; 3488ef1a191SBart Van Assche 3498ef1a191SBart Van Assche return seq_list_next(v, &q->requeue_list, pos); 3508ef1a191SBart Van Assche } 3518ef1a191SBart Van Assche 3528ef1a191SBart Van Assche static void queue_requeue_list_stop(struct seq_file *m, void *v) 3538ef1a191SBart Van Assche __releases(&q->requeue_lock) 3548ef1a191SBart Van Assche { 3558ef1a191SBart Van Assche struct request_queue *q = m->private; 3568ef1a191SBart Van Assche 3578ef1a191SBart Van Assche spin_unlock_irq(&q->requeue_lock); 3588ef1a191SBart Van Assche } 3598ef1a191SBart Van Assche 3608ef1a191SBart Van Assche static const struct seq_operations queue_requeue_list_seq_ops = { 3618ef1a191SBart Van Assche .start = queue_requeue_list_start, 3628ef1a191SBart Van Assche .next = queue_requeue_list_next, 3638ef1a191SBart Van Assche .stop = queue_requeue_list_stop, 3648ef1a191SBart Van Assche .show = blk_mq_debugfs_rq_show, 3658ef1a191SBart Van Assche }; 3668ef1a191SBart Van Assche 367950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos) 368f3bcb0e6SBart Van Assche __acquires(&hctx->lock) 369950cd7e9SOmar Sandoval { 370950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 371950cd7e9SOmar Sandoval 372950cd7e9SOmar Sandoval spin_lock(&hctx->lock); 373950cd7e9SOmar Sandoval return seq_list_start(&hctx->dispatch, *pos); 374950cd7e9SOmar Sandoval } 375950cd7e9SOmar Sandoval 376950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos) 377950cd7e9SOmar Sandoval { 378950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 379950cd7e9SOmar Sandoval 380950cd7e9SOmar Sandoval return seq_list_next(v, &hctx->dispatch, pos); 381950cd7e9SOmar Sandoval } 382950cd7e9SOmar Sandoval 383950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v) 384f3bcb0e6SBart Van Assche __releases(&hctx->lock) 385950cd7e9SOmar Sandoval { 386950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 387950cd7e9SOmar Sandoval 388950cd7e9SOmar Sandoval spin_unlock(&hctx->lock); 389950cd7e9SOmar Sandoval } 390950cd7e9SOmar Sandoval 391950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = { 392950cd7e9SOmar Sandoval .start = hctx_dispatch_start, 393950cd7e9SOmar Sandoval .next = hctx_dispatch_next, 394950cd7e9SOmar Sandoval .stop = hctx_dispatch_stop, 395950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 396950cd7e9SOmar Sandoval }; 397950cd7e9SOmar Sandoval 3982720bab5SBart Van Assche struct show_busy_params { 3992720bab5SBart Van Assche struct seq_file *m; 4002720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx; 4012720bab5SBart Van Assche }; 4022720bab5SBart Van Assche 4032720bab5SBart Van Assche /* 4042720bab5SBart Van Assche * Note: the state of a request may change while this function is in progress, 4052720bab5SBart Van Assche * e.g. due to a concurrent blk_mq_finish_request() call. 4062720bab5SBart Van Assche */ 4072720bab5SBart Van Assche static void hctx_show_busy_rq(struct request *rq, void *data, bool reserved) 4082720bab5SBart Van Assche { 4092720bab5SBart Van Assche const struct show_busy_params *params = data; 4102720bab5SBart Van Assche 4112720bab5SBart Van Assche if (blk_mq_map_queue(rq->q, rq->mq_ctx->cpu) == params->hctx && 4122720bab5SBart Van Assche test_bit(REQ_ATOM_STARTED, &rq->atomic_flags)) 4132720bab5SBart Van Assche __blk_mq_debugfs_rq_show(params->m, 4142720bab5SBart Van Assche list_entry_rq(&rq->queuelist)); 4152720bab5SBart Van Assche } 4162720bab5SBart Van Assche 4172720bab5SBart Van Assche static int hctx_busy_show(void *data, struct seq_file *m) 4182720bab5SBart Van Assche { 4192720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx = data; 4202720bab5SBart Van Assche struct show_busy_params params = { .m = m, .hctx = hctx }; 4212720bab5SBart Van Assche 4222720bab5SBart Van Assche blk_mq_tagset_busy_iter(hctx->queue->tag_set, hctx_show_busy_rq, 4232720bab5SBart Van Assche ¶ms); 4242720bab5SBart Van Assche 4252720bab5SBart Van Assche return 0; 4262720bab5SBart Van Assche } 4272720bab5SBart Van Assche 428f57de23aSOmar Sandoval static int hctx_ctx_map_show(void *data, struct seq_file *m) 429950cd7e9SOmar Sandoval { 430f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 4310bfa5288SOmar Sandoval 4320bfa5288SOmar Sandoval sbitmap_bitmap_show(&hctx->ctx_map, m); 4330bfa5288SOmar Sandoval return 0; 4340bfa5288SOmar Sandoval } 4350bfa5288SOmar Sandoval 436d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m, 437d96b37c0SOmar Sandoval struct blk_mq_tags *tags) 438d96b37c0SOmar Sandoval { 439d96b37c0SOmar Sandoval seq_printf(m, "nr_tags=%u\n", tags->nr_tags); 440d96b37c0SOmar Sandoval seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags); 441d96b37c0SOmar Sandoval seq_printf(m, "active_queues=%d\n", 442d96b37c0SOmar Sandoval atomic_read(&tags->active_queues)); 443d96b37c0SOmar Sandoval 444d96b37c0SOmar Sandoval seq_puts(m, "\nbitmap_tags:\n"); 445d96b37c0SOmar Sandoval sbitmap_queue_show(&tags->bitmap_tags, m); 446d96b37c0SOmar Sandoval 447d96b37c0SOmar Sandoval if (tags->nr_reserved_tags) { 448d96b37c0SOmar Sandoval seq_puts(m, "\nbreserved_tags:\n"); 449d96b37c0SOmar Sandoval sbitmap_queue_show(&tags->breserved_tags, m); 450d96b37c0SOmar Sandoval } 451d96b37c0SOmar Sandoval } 452d96b37c0SOmar Sandoval 453f57de23aSOmar Sandoval static int hctx_tags_show(void *data, struct seq_file *m) 454d96b37c0SOmar Sandoval { 455f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 456d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 4578c0f14eaSBart Van Assche int res; 458d96b37c0SOmar Sandoval 4598c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4608c0f14eaSBart Van Assche if (res) 4618c0f14eaSBart Van Assche goto out; 462d96b37c0SOmar Sandoval if (hctx->tags) 463d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->tags); 464d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 465d96b37c0SOmar Sandoval 4668c0f14eaSBart Van Assche out: 4678c0f14eaSBart Van Assche return res; 468d96b37c0SOmar Sandoval } 469d96b37c0SOmar Sandoval 470f57de23aSOmar Sandoval static int hctx_tags_bitmap_show(void *data, struct seq_file *m) 471d96b37c0SOmar Sandoval { 472f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 473d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 4748c0f14eaSBart Van Assche int res; 475d7e3621aSOmar Sandoval 4768c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4778c0f14eaSBart Van Assche if (res) 4788c0f14eaSBart Van Assche goto out; 479d7e3621aSOmar Sandoval if (hctx->tags) 480d7e3621aSOmar Sandoval sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m); 481d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 4828c0f14eaSBart Van Assche 4838c0f14eaSBart Van Assche out: 4848c0f14eaSBart Van Assche return res; 485d7e3621aSOmar Sandoval } 486d7e3621aSOmar Sandoval 487f57de23aSOmar Sandoval static int hctx_sched_tags_show(void *data, struct seq_file *m) 488d7e3621aSOmar Sandoval { 489f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 490d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 4918c0f14eaSBart Van Assche int res; 492d96b37c0SOmar Sandoval 4938c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4948c0f14eaSBart Van Assche if (res) 4958c0f14eaSBart Van Assche goto out; 496d96b37c0SOmar Sandoval if (hctx->sched_tags) 497d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->sched_tags); 498d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 499d96b37c0SOmar Sandoval 5008c0f14eaSBart Van Assche out: 5018c0f14eaSBart Van Assche return res; 502d96b37c0SOmar Sandoval } 503d96b37c0SOmar Sandoval 504f57de23aSOmar Sandoval static int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m) 505d96b37c0SOmar Sandoval { 506f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 507d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 5088c0f14eaSBart Van Assche int res; 509d7e3621aSOmar Sandoval 5108c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 5118c0f14eaSBart Van Assche if (res) 5128c0f14eaSBart Van Assche goto out; 513d7e3621aSOmar Sandoval if (hctx->sched_tags) 514d7e3621aSOmar Sandoval sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m); 515d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 5168c0f14eaSBart Van Assche 5178c0f14eaSBart Van Assche out: 5188c0f14eaSBart Van Assche return res; 519d7e3621aSOmar Sandoval } 520d7e3621aSOmar Sandoval 521f57de23aSOmar Sandoval static int hctx_io_poll_show(void *data, struct seq_file *m) 522d7e3621aSOmar Sandoval { 523f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 524be215473SOmar Sandoval 525be215473SOmar Sandoval seq_printf(m, "considered=%lu\n", hctx->poll_considered); 526be215473SOmar Sandoval seq_printf(m, "invoked=%lu\n", hctx->poll_invoked); 527be215473SOmar Sandoval seq_printf(m, "success=%lu\n", hctx->poll_success); 528be215473SOmar Sandoval return 0; 529be215473SOmar Sandoval } 530be215473SOmar Sandoval 531f57de23aSOmar Sandoval static ssize_t hctx_io_poll_write(void *data, const char __user *buf, 532be215473SOmar Sandoval size_t count, loff_t *ppos) 533be215473SOmar Sandoval { 534f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 535be215473SOmar Sandoval 536be215473SOmar Sandoval hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0; 537be215473SOmar Sandoval return count; 538be215473SOmar Sandoval } 539be215473SOmar Sandoval 540f57de23aSOmar Sandoval static int hctx_dispatched_show(void *data, struct seq_file *m) 541be215473SOmar Sandoval { 542f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 543be215473SOmar Sandoval int i; 544be215473SOmar Sandoval 545be215473SOmar Sandoval seq_printf(m, "%8u\t%lu\n", 0U, hctx->dispatched[0]); 546be215473SOmar Sandoval 547be215473SOmar Sandoval for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) { 548be215473SOmar Sandoval unsigned int d = 1U << (i - 1); 549be215473SOmar Sandoval 550be215473SOmar Sandoval seq_printf(m, "%8u\t%lu\n", d, hctx->dispatched[i]); 551be215473SOmar Sandoval } 552be215473SOmar Sandoval 553be215473SOmar Sandoval seq_printf(m, "%8u+\t%lu\n", 1U << (i - 1), hctx->dispatched[i]); 554be215473SOmar Sandoval return 0; 555be215473SOmar Sandoval } 556be215473SOmar Sandoval 557f57de23aSOmar Sandoval static ssize_t hctx_dispatched_write(void *data, const char __user *buf, 558be215473SOmar Sandoval size_t count, loff_t *ppos) 559be215473SOmar Sandoval { 560f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 561be215473SOmar Sandoval int i; 562be215473SOmar Sandoval 563be215473SOmar Sandoval for (i = 0; i < BLK_MQ_MAX_DISPATCH_ORDER; i++) 564be215473SOmar Sandoval hctx->dispatched[i] = 0; 565be215473SOmar Sandoval return count; 566be215473SOmar Sandoval } 567be215473SOmar Sandoval 568f57de23aSOmar Sandoval static int hctx_queued_show(void *data, struct seq_file *m) 5694a46f05eSOmar Sandoval { 570f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5714a46f05eSOmar Sandoval 5724a46f05eSOmar Sandoval seq_printf(m, "%lu\n", hctx->queued); 5734a46f05eSOmar Sandoval return 0; 5744a46f05eSOmar Sandoval } 5754a46f05eSOmar Sandoval 576f57de23aSOmar Sandoval static ssize_t hctx_queued_write(void *data, const char __user *buf, 5774a46f05eSOmar Sandoval size_t count, loff_t *ppos) 5784a46f05eSOmar Sandoval { 579f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5804a46f05eSOmar Sandoval 5814a46f05eSOmar Sandoval hctx->queued = 0; 5824a46f05eSOmar Sandoval return count; 5834a46f05eSOmar Sandoval } 5844a46f05eSOmar Sandoval 585f57de23aSOmar Sandoval static int hctx_run_show(void *data, struct seq_file *m) 5864a46f05eSOmar Sandoval { 587f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5884a46f05eSOmar Sandoval 5894a46f05eSOmar Sandoval seq_printf(m, "%lu\n", hctx->run); 5904a46f05eSOmar Sandoval return 0; 5914a46f05eSOmar Sandoval } 5924a46f05eSOmar Sandoval 593f57de23aSOmar Sandoval static ssize_t hctx_run_write(void *data, const char __user *buf, size_t count, 594f57de23aSOmar Sandoval loff_t *ppos) 5954a46f05eSOmar Sandoval { 596f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5974a46f05eSOmar Sandoval 5984a46f05eSOmar Sandoval hctx->run = 0; 5994a46f05eSOmar Sandoval return count; 6004a46f05eSOmar Sandoval } 6014a46f05eSOmar Sandoval 602f57de23aSOmar Sandoval static int hctx_active_show(void *data, struct seq_file *m) 6034a46f05eSOmar Sandoval { 604f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 6054a46f05eSOmar Sandoval 6064a46f05eSOmar Sandoval seq_printf(m, "%d\n", atomic_read(&hctx->nr_active)); 6074a46f05eSOmar Sandoval return 0; 6084a46f05eSOmar Sandoval } 6094a46f05eSOmar Sandoval 610950cd7e9SOmar Sandoval static void *ctx_rq_list_start(struct seq_file *m, loff_t *pos) 611f3bcb0e6SBart Van Assche __acquires(&ctx->lock) 612950cd7e9SOmar Sandoval { 613950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 614950cd7e9SOmar Sandoval 615950cd7e9SOmar Sandoval spin_lock(&ctx->lock); 616950cd7e9SOmar Sandoval return seq_list_start(&ctx->rq_list, *pos); 617950cd7e9SOmar Sandoval } 618950cd7e9SOmar Sandoval 619950cd7e9SOmar Sandoval static void *ctx_rq_list_next(struct seq_file *m, void *v, loff_t *pos) 620950cd7e9SOmar Sandoval { 621950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 622950cd7e9SOmar Sandoval 623950cd7e9SOmar Sandoval return seq_list_next(v, &ctx->rq_list, pos); 624950cd7e9SOmar Sandoval } 625950cd7e9SOmar Sandoval 626950cd7e9SOmar Sandoval static void ctx_rq_list_stop(struct seq_file *m, void *v) 627f3bcb0e6SBart Van Assche __releases(&ctx->lock) 628950cd7e9SOmar Sandoval { 629950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 630950cd7e9SOmar Sandoval 631950cd7e9SOmar Sandoval spin_unlock(&ctx->lock); 632950cd7e9SOmar Sandoval } 633950cd7e9SOmar Sandoval 634950cd7e9SOmar Sandoval static const struct seq_operations ctx_rq_list_seq_ops = { 635950cd7e9SOmar Sandoval .start = ctx_rq_list_start, 636950cd7e9SOmar Sandoval .next = ctx_rq_list_next, 637950cd7e9SOmar Sandoval .stop = ctx_rq_list_stop, 638950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 639950cd7e9SOmar Sandoval }; 640f57de23aSOmar Sandoval static int ctx_dispatched_show(void *data, struct seq_file *m) 641950cd7e9SOmar Sandoval { 642f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6434a46f05eSOmar Sandoval 6444a46f05eSOmar Sandoval seq_printf(m, "%lu %lu\n", ctx->rq_dispatched[1], ctx->rq_dispatched[0]); 6454a46f05eSOmar Sandoval return 0; 6464a46f05eSOmar Sandoval } 6474a46f05eSOmar Sandoval 648f57de23aSOmar Sandoval static ssize_t ctx_dispatched_write(void *data, const char __user *buf, 6494a46f05eSOmar Sandoval size_t count, loff_t *ppos) 6504a46f05eSOmar Sandoval { 651f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6524a46f05eSOmar Sandoval 6534a46f05eSOmar Sandoval ctx->rq_dispatched[0] = ctx->rq_dispatched[1] = 0; 6544a46f05eSOmar Sandoval return count; 6554a46f05eSOmar Sandoval } 6564a46f05eSOmar Sandoval 657f57de23aSOmar Sandoval static int ctx_merged_show(void *data, struct seq_file *m) 6584a46f05eSOmar Sandoval { 659f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6604a46f05eSOmar Sandoval 6614a46f05eSOmar Sandoval seq_printf(m, "%lu\n", ctx->rq_merged); 6624a46f05eSOmar Sandoval return 0; 6634a46f05eSOmar Sandoval } 6644a46f05eSOmar Sandoval 665f57de23aSOmar Sandoval static ssize_t ctx_merged_write(void *data, const char __user *buf, 6664a46f05eSOmar Sandoval size_t count, loff_t *ppos) 6674a46f05eSOmar Sandoval { 668f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6694a46f05eSOmar Sandoval 6704a46f05eSOmar Sandoval ctx->rq_merged = 0; 6714a46f05eSOmar Sandoval return count; 6724a46f05eSOmar Sandoval } 6734a46f05eSOmar Sandoval 674f57de23aSOmar Sandoval static int ctx_completed_show(void *data, struct seq_file *m) 6754a46f05eSOmar Sandoval { 676f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6774a46f05eSOmar Sandoval 6784a46f05eSOmar Sandoval seq_printf(m, "%lu %lu\n", ctx->rq_completed[1], ctx->rq_completed[0]); 6794a46f05eSOmar Sandoval return 0; 6804a46f05eSOmar Sandoval } 6814a46f05eSOmar Sandoval 682f57de23aSOmar Sandoval static ssize_t ctx_completed_write(void *data, const char __user *buf, 6834a46f05eSOmar Sandoval size_t count, loff_t *ppos) 6844a46f05eSOmar Sandoval { 685f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6864a46f05eSOmar Sandoval 6874a46f05eSOmar Sandoval ctx->rq_completed[0] = ctx->rq_completed[1] = 0; 6884a46f05eSOmar Sandoval return count; 6894a46f05eSOmar Sandoval } 6904a46f05eSOmar Sandoval 691f57de23aSOmar Sandoval static int blk_mq_debugfs_show(struct seq_file *m, void *v) 692f57de23aSOmar Sandoval { 693f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 694f57de23aSOmar Sandoval void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private; 695f57de23aSOmar Sandoval 696f57de23aSOmar Sandoval return attr->show(data, m); 697f57de23aSOmar Sandoval } 698f57de23aSOmar Sandoval 699f57de23aSOmar Sandoval static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf, 700f57de23aSOmar Sandoval size_t count, loff_t *ppos) 701f57de23aSOmar Sandoval { 702f57de23aSOmar Sandoval struct seq_file *m = file->private_data; 703f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 704f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 705f57de23aSOmar Sandoval 706f57de23aSOmar Sandoval if (!attr->write) 707f57de23aSOmar Sandoval return -EPERM; 708f57de23aSOmar Sandoval 709f57de23aSOmar Sandoval return attr->write(data, buf, count, ppos); 710f57de23aSOmar Sandoval } 711f57de23aSOmar Sandoval 712f57de23aSOmar Sandoval static int blk_mq_debugfs_open(struct inode *inode, struct file *file) 713f57de23aSOmar Sandoval { 714f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 715f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 716f57de23aSOmar Sandoval struct seq_file *m; 717f57de23aSOmar Sandoval int ret; 718f57de23aSOmar Sandoval 719f57de23aSOmar Sandoval if (attr->seq_ops) { 720f57de23aSOmar Sandoval ret = seq_open(file, attr->seq_ops); 721f57de23aSOmar Sandoval if (!ret) { 722f57de23aSOmar Sandoval m = file->private_data; 723f57de23aSOmar Sandoval m->private = data; 724f57de23aSOmar Sandoval } 725f57de23aSOmar Sandoval return ret; 726f57de23aSOmar Sandoval } 727f57de23aSOmar Sandoval 728f57de23aSOmar Sandoval if (WARN_ON_ONCE(!attr->show)) 729f57de23aSOmar Sandoval return -EPERM; 730f57de23aSOmar Sandoval 731f57de23aSOmar Sandoval return single_open(file, blk_mq_debugfs_show, inode->i_private); 732f57de23aSOmar Sandoval } 733f57de23aSOmar Sandoval 734f57de23aSOmar Sandoval static int blk_mq_debugfs_release(struct inode *inode, struct file *file) 735f57de23aSOmar Sandoval { 736f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 737f57de23aSOmar Sandoval 738f57de23aSOmar Sandoval if (attr->show) 739f57de23aSOmar Sandoval return single_release(inode, file); 740f57de23aSOmar Sandoval else 741f57de23aSOmar Sandoval return seq_release(inode, file); 742f57de23aSOmar Sandoval } 743f57de23aSOmar Sandoval 744f57de23aSOmar Sandoval const struct file_operations blk_mq_debugfs_fops = { 745f57de23aSOmar Sandoval .open = blk_mq_debugfs_open, 7464a46f05eSOmar Sandoval .read = seq_read, 747f57de23aSOmar Sandoval .write = blk_mq_debugfs_write, 7484a46f05eSOmar Sandoval .llseek = seq_lseek, 749f57de23aSOmar Sandoval .release = blk_mq_debugfs_release, 7504a46f05eSOmar Sandoval }; 7514a46f05eSOmar Sandoval 75234dbad5dSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = { 753f57de23aSOmar Sandoval {"poll_stat", 0400, queue_poll_stat_show}, 7548ef1a191SBart Van Assche {"requeue_list", 0400, .seq_ops = &queue_requeue_list_seq_ops}, 755f57de23aSOmar Sandoval {"state", 0600, queue_state_show, queue_state_write}, 756*f793dfd3SJens Axboe {"write_hints", 0600, queue_write_hint_show, queue_write_hint_store}, 75734dbad5dSOmar Sandoval {}, 75834dbad5dSOmar Sandoval }; 75934dbad5dSOmar Sandoval 76007e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { 761f57de23aSOmar Sandoval {"state", 0400, hctx_state_show}, 762f57de23aSOmar Sandoval {"flags", 0400, hctx_flags_show}, 763f57de23aSOmar Sandoval {"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops}, 7642720bab5SBart Van Assche {"busy", 0400, hctx_busy_show}, 765f57de23aSOmar Sandoval {"ctx_map", 0400, hctx_ctx_map_show}, 766f57de23aSOmar Sandoval {"tags", 0400, hctx_tags_show}, 767f57de23aSOmar Sandoval {"tags_bitmap", 0400, hctx_tags_bitmap_show}, 768f57de23aSOmar Sandoval {"sched_tags", 0400, hctx_sched_tags_show}, 769f57de23aSOmar Sandoval {"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show}, 770f57de23aSOmar Sandoval {"io_poll", 0600, hctx_io_poll_show, hctx_io_poll_write}, 771f57de23aSOmar Sandoval {"dispatched", 0600, hctx_dispatched_show, hctx_dispatched_write}, 772f57de23aSOmar Sandoval {"queued", 0600, hctx_queued_show, hctx_queued_write}, 773f57de23aSOmar Sandoval {"run", 0600, hctx_run_show, hctx_run_write}, 774f57de23aSOmar Sandoval {"active", 0400, hctx_active_show}, 77572f2f8f6SBart Van Assche {}, 77607e4feadSOmar Sandoval }; 77707e4feadSOmar Sandoval 77807e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = { 779f57de23aSOmar Sandoval {"rq_list", 0400, .seq_ops = &ctx_rq_list_seq_ops}, 780f57de23aSOmar Sandoval {"dispatched", 0600, ctx_dispatched_show, ctx_dispatched_write}, 781f57de23aSOmar Sandoval {"merged", 0600, ctx_merged_show, ctx_merged_write}, 782f57de23aSOmar Sandoval {"completed", 0600, ctx_completed_show, ctx_completed_write}, 78372f2f8f6SBart Van Assche {}, 78407e4feadSOmar Sandoval }; 78507e4feadSOmar Sandoval 78672f2f8f6SBart Van Assche static bool debugfs_create_files(struct dentry *parent, void *data, 78772f2f8f6SBart Van Assche const struct blk_mq_debugfs_attr *attr) 78872f2f8f6SBart Van Assche { 789f57de23aSOmar Sandoval d_inode(parent)->i_private = data; 790f57de23aSOmar Sandoval 79172f2f8f6SBart Van Assche for (; attr->name; attr++) { 79272f2f8f6SBart Van Assche if (!debugfs_create_file(attr->name, attr->mode, parent, 793f57de23aSOmar Sandoval (void *)attr, &blk_mq_debugfs_fops)) 79472f2f8f6SBart Van Assche return false; 79572f2f8f6SBart Van Assche } 79672f2f8f6SBart Van Assche return true; 79772f2f8f6SBart Van Assche } 79872f2f8f6SBart Van Assche 7999c1051aaSOmar Sandoval int blk_mq_debugfs_register(struct request_queue *q) 8009c1051aaSOmar Sandoval { 8019c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 8029c1051aaSOmar Sandoval int i; 8039c1051aaSOmar Sandoval 8049c1051aaSOmar Sandoval if (!blk_debugfs_root) 8059c1051aaSOmar Sandoval return -ENOENT; 8069c1051aaSOmar Sandoval 8079c1051aaSOmar Sandoval q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent), 8089c1051aaSOmar Sandoval blk_debugfs_root); 8099c1051aaSOmar Sandoval if (!q->debugfs_dir) 8109c1051aaSOmar Sandoval return -ENOMEM; 8119c1051aaSOmar Sandoval 8129c1051aaSOmar Sandoval if (!debugfs_create_files(q->debugfs_dir, q, 8139c1051aaSOmar Sandoval blk_mq_debugfs_queue_attrs)) 8149c1051aaSOmar Sandoval goto err; 8159c1051aaSOmar Sandoval 8169c1051aaSOmar Sandoval /* 8179c1051aaSOmar Sandoval * blk_mq_init_hctx() attempted to do this already, but q->debugfs_dir 8189c1051aaSOmar Sandoval * didn't exist yet (because we don't know what to name the directory 8199c1051aaSOmar Sandoval * until the queue is registered to a gendisk). 8209c1051aaSOmar Sandoval */ 8219c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) { 8229c1051aaSOmar Sandoval if (!hctx->debugfs_dir && blk_mq_debugfs_register_hctx(q, hctx)) 8239c1051aaSOmar Sandoval goto err; 824d332ce09SOmar Sandoval if (q->elevator && !hctx->sched_debugfs_dir && 825d332ce09SOmar Sandoval blk_mq_debugfs_register_sched_hctx(q, hctx)) 826d332ce09SOmar Sandoval goto err; 8279c1051aaSOmar Sandoval } 8289c1051aaSOmar Sandoval 8299c1051aaSOmar Sandoval return 0; 8309c1051aaSOmar Sandoval 8319c1051aaSOmar Sandoval err: 8329c1051aaSOmar Sandoval blk_mq_debugfs_unregister(q); 8339c1051aaSOmar Sandoval return -ENOMEM; 8349c1051aaSOmar Sandoval } 8359c1051aaSOmar Sandoval 8369c1051aaSOmar Sandoval void blk_mq_debugfs_unregister(struct request_queue *q) 8379c1051aaSOmar Sandoval { 8389c1051aaSOmar Sandoval debugfs_remove_recursive(q->debugfs_dir); 839d332ce09SOmar Sandoval q->sched_debugfs_dir = NULL; 8409c1051aaSOmar Sandoval q->debugfs_dir = NULL; 8419c1051aaSOmar Sandoval } 8429c1051aaSOmar Sandoval 8439c1051aaSOmar Sandoval static int blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx, 8449c1051aaSOmar Sandoval struct blk_mq_ctx *ctx) 84507e4feadSOmar Sandoval { 84607e4feadSOmar Sandoval struct dentry *ctx_dir; 84707e4feadSOmar Sandoval char name[20]; 84807e4feadSOmar Sandoval 84907e4feadSOmar Sandoval snprintf(name, sizeof(name), "cpu%u", ctx->cpu); 8509c1051aaSOmar Sandoval ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir); 85107e4feadSOmar Sandoval if (!ctx_dir) 85207e4feadSOmar Sandoval return -ENOMEM; 85307e4feadSOmar Sandoval 85472f2f8f6SBart Van Assche if (!debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs)) 85507e4feadSOmar Sandoval return -ENOMEM; 85607e4feadSOmar Sandoval 85707e4feadSOmar Sandoval return 0; 85807e4feadSOmar Sandoval } 85907e4feadSOmar Sandoval 8609c1051aaSOmar Sandoval int blk_mq_debugfs_register_hctx(struct request_queue *q, 86107e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx) 86207e4feadSOmar Sandoval { 86307e4feadSOmar Sandoval struct blk_mq_ctx *ctx; 86407e4feadSOmar Sandoval char name[20]; 86507e4feadSOmar Sandoval int i; 86607e4feadSOmar Sandoval 86707e4feadSOmar Sandoval if (!q->debugfs_dir) 86807e4feadSOmar Sandoval return -ENOENT; 86907e4feadSOmar Sandoval 8709c1051aaSOmar Sandoval snprintf(name, sizeof(name), "hctx%u", hctx->queue_num); 8719c1051aaSOmar Sandoval hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir); 8729c1051aaSOmar Sandoval if (!hctx->debugfs_dir) 8739c1051aaSOmar Sandoval return -ENOMEM; 8749c1051aaSOmar Sandoval 8759c1051aaSOmar Sandoval if (!debugfs_create_files(hctx->debugfs_dir, hctx, 8769c1051aaSOmar Sandoval blk_mq_debugfs_hctx_attrs)) 87707e4feadSOmar Sandoval goto err; 87807e4feadSOmar Sandoval 8799c1051aaSOmar Sandoval hctx_for_each_ctx(hctx, ctx, i) { 8809c1051aaSOmar Sandoval if (blk_mq_debugfs_register_ctx(hctx, ctx)) 88107e4feadSOmar Sandoval goto err; 88207e4feadSOmar Sandoval } 88307e4feadSOmar Sandoval 88407e4feadSOmar Sandoval return 0; 88507e4feadSOmar Sandoval 88607e4feadSOmar Sandoval err: 8879c1051aaSOmar Sandoval blk_mq_debugfs_unregister_hctx(hctx); 88807e4feadSOmar Sandoval return -ENOMEM; 88907e4feadSOmar Sandoval } 89007e4feadSOmar Sandoval 8919c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx) 89207e4feadSOmar Sandoval { 8939c1051aaSOmar Sandoval debugfs_remove_recursive(hctx->debugfs_dir); 894d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 8959c1051aaSOmar Sandoval hctx->debugfs_dir = NULL; 8969c1051aaSOmar Sandoval } 8979c1051aaSOmar Sandoval 8989c1051aaSOmar Sandoval int blk_mq_debugfs_register_hctxs(struct request_queue *q) 8999c1051aaSOmar Sandoval { 9009c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 9019c1051aaSOmar Sandoval int i; 9029c1051aaSOmar Sandoval 9039c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) { 9049c1051aaSOmar Sandoval if (blk_mq_debugfs_register_hctx(q, hctx)) 9059c1051aaSOmar Sandoval return -ENOMEM; 9069c1051aaSOmar Sandoval } 9079c1051aaSOmar Sandoval 9089c1051aaSOmar Sandoval return 0; 9099c1051aaSOmar Sandoval } 9109c1051aaSOmar Sandoval 9119c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q) 9129c1051aaSOmar Sandoval { 9139c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 9149c1051aaSOmar Sandoval int i; 9159c1051aaSOmar Sandoval 9169c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) 9179c1051aaSOmar Sandoval blk_mq_debugfs_unregister_hctx(hctx); 91807e4feadSOmar Sandoval } 919d332ce09SOmar Sandoval 920d332ce09SOmar Sandoval int blk_mq_debugfs_register_sched(struct request_queue *q) 921d332ce09SOmar Sandoval { 922d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 923d332ce09SOmar Sandoval 924d332ce09SOmar Sandoval if (!q->debugfs_dir) 925d332ce09SOmar Sandoval return -ENOENT; 926d332ce09SOmar Sandoval 927d332ce09SOmar Sandoval if (!e->queue_debugfs_attrs) 928d332ce09SOmar Sandoval return 0; 929d332ce09SOmar Sandoval 930d332ce09SOmar Sandoval q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir); 931d332ce09SOmar Sandoval if (!q->sched_debugfs_dir) 932d332ce09SOmar Sandoval return -ENOMEM; 933d332ce09SOmar Sandoval 934d332ce09SOmar Sandoval if (!debugfs_create_files(q->sched_debugfs_dir, q, 935d332ce09SOmar Sandoval e->queue_debugfs_attrs)) 936d332ce09SOmar Sandoval goto err; 937d332ce09SOmar Sandoval 938d332ce09SOmar Sandoval return 0; 939d332ce09SOmar Sandoval 940d332ce09SOmar Sandoval err: 941d332ce09SOmar Sandoval blk_mq_debugfs_unregister_sched(q); 942d332ce09SOmar Sandoval return -ENOMEM; 943d332ce09SOmar Sandoval } 944d332ce09SOmar Sandoval 945d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched(struct request_queue *q) 946d332ce09SOmar Sandoval { 947d332ce09SOmar Sandoval debugfs_remove_recursive(q->sched_debugfs_dir); 948d332ce09SOmar Sandoval q->sched_debugfs_dir = NULL; 949d332ce09SOmar Sandoval } 950d332ce09SOmar Sandoval 951d332ce09SOmar Sandoval int blk_mq_debugfs_register_sched_hctx(struct request_queue *q, 952d332ce09SOmar Sandoval struct blk_mq_hw_ctx *hctx) 953d332ce09SOmar Sandoval { 954d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 955d332ce09SOmar Sandoval 956d332ce09SOmar Sandoval if (!hctx->debugfs_dir) 957d332ce09SOmar Sandoval return -ENOENT; 958d332ce09SOmar Sandoval 959d332ce09SOmar Sandoval if (!e->hctx_debugfs_attrs) 960d332ce09SOmar Sandoval return 0; 961d332ce09SOmar Sandoval 962d332ce09SOmar Sandoval hctx->sched_debugfs_dir = debugfs_create_dir("sched", 963d332ce09SOmar Sandoval hctx->debugfs_dir); 964d332ce09SOmar Sandoval if (!hctx->sched_debugfs_dir) 965d332ce09SOmar Sandoval return -ENOMEM; 966d332ce09SOmar Sandoval 967d332ce09SOmar Sandoval if (!debugfs_create_files(hctx->sched_debugfs_dir, hctx, 968d332ce09SOmar Sandoval e->hctx_debugfs_attrs)) 969d332ce09SOmar Sandoval return -ENOMEM; 970d332ce09SOmar Sandoval 971d332ce09SOmar Sandoval return 0; 972d332ce09SOmar Sandoval } 973d332ce09SOmar Sandoval 974d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx) 975d332ce09SOmar Sandoval { 976d332ce09SOmar Sandoval debugfs_remove_recursive(hctx->sched_debugfs_dir); 977d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 978d332ce09SOmar Sandoval } 979