18c16567dSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0 207e4feadSOmar Sandoval /* 307e4feadSOmar Sandoval * Copyright (C) 2017 Facebook 407e4feadSOmar Sandoval */ 507e4feadSOmar Sandoval 607e4feadSOmar Sandoval #include <linux/kernel.h> 707e4feadSOmar Sandoval #include <linux/blkdev.h> 807e4feadSOmar Sandoval #include <linux/debugfs.h> 907e4feadSOmar Sandoval 1007e4feadSOmar Sandoval #include <linux/blk-mq.h> 1118fbda91SOmar Sandoval #include "blk.h" 1207e4feadSOmar Sandoval #include "blk-mq.h" 13d173a251SOmar Sandoval #include "blk-mq-debugfs.h" 14d96b37c0SOmar Sandoval #include "blk-mq-tag.h" 15cc56694fSMing Lei #include "blk-rq-qos.h" 1607e4feadSOmar Sandoval 171209cb7fSBart Van Assche static void print_stat(struct seq_file *m, struct blk_rq_stat *stat) 181209cb7fSBart Van Assche { 191209cb7fSBart Van Assche if (stat->nr_samples) { 20315eb656SPavel Begunkov seq_printf(m, "samples=%d, mean=%llu, min=%llu, max=%llu", 211209cb7fSBart Van Assche stat->nr_samples, stat->mean, stat->min, stat->max); 221209cb7fSBart Van Assche } else { 231209cb7fSBart Van Assche seq_puts(m, "samples=0"); 241209cb7fSBart Van Assche } 251209cb7fSBart Van Assche } 261209cb7fSBart Van Assche 271209cb7fSBart Van Assche static int queue_poll_stat_show(void *data, struct seq_file *m) 281209cb7fSBart Van Assche { 291209cb7fSBart Van Assche struct request_queue *q = data; 301209cb7fSBart Van Assche int bucket; 311209cb7fSBart Van Assche 32243d9f78SChaitanya Kulkarni for (bucket = 0; bucket < (BLK_MQ_POLL_STATS_BKTS / 2); bucket++) { 331209cb7fSBart Van Assche seq_printf(m, "read (%d Bytes): ", 1 << (9 + bucket)); 341209cb7fSBart Van Assche print_stat(m, &q->poll_stat[2 * bucket]); 351209cb7fSBart Van Assche seq_puts(m, "\n"); 361209cb7fSBart Van Assche 371209cb7fSBart Van Assche seq_printf(m, "write (%d Bytes): ", 1 << (9 + bucket)); 381209cb7fSBart Van Assche print_stat(m, &q->poll_stat[2 * bucket + 1]); 391209cb7fSBart Van Assche seq_puts(m, "\n"); 401209cb7fSBart Van Assche } 411209cb7fSBart Van Assche return 0; 421209cb7fSBart Van Assche } 431209cb7fSBart Van Assche 441209cb7fSBart Van Assche static void *queue_requeue_list_start(struct seq_file *m, loff_t *pos) 451209cb7fSBart Van Assche __acquires(&q->requeue_lock) 461209cb7fSBart Van Assche { 471209cb7fSBart Van Assche struct request_queue *q = m->private; 481209cb7fSBart Van Assche 491209cb7fSBart Van Assche spin_lock_irq(&q->requeue_lock); 501209cb7fSBart Van Assche return seq_list_start(&q->requeue_list, *pos); 511209cb7fSBart Van Assche } 521209cb7fSBart Van Assche 531209cb7fSBart Van Assche static void *queue_requeue_list_next(struct seq_file *m, void *v, loff_t *pos) 541209cb7fSBart Van Assche { 551209cb7fSBart Van Assche struct request_queue *q = m->private; 561209cb7fSBart Van Assche 571209cb7fSBart Van Assche return seq_list_next(v, &q->requeue_list, pos); 581209cb7fSBart Van Assche } 591209cb7fSBart Van Assche 601209cb7fSBart Van Assche static void queue_requeue_list_stop(struct seq_file *m, void *v) 611209cb7fSBart Van Assche __releases(&q->requeue_lock) 621209cb7fSBart Van Assche { 631209cb7fSBart Van Assche struct request_queue *q = m->private; 641209cb7fSBart Van Assche 651209cb7fSBart Van Assche spin_unlock_irq(&q->requeue_lock); 661209cb7fSBart Van Assche } 671209cb7fSBart Van Assche 681209cb7fSBart Van Assche static const struct seq_operations queue_requeue_list_seq_ops = { 691209cb7fSBart Van Assche .start = queue_requeue_list_start, 701209cb7fSBart Van Assche .next = queue_requeue_list_next, 711209cb7fSBart Van Assche .stop = queue_requeue_list_stop, 721209cb7fSBart Van Assche .show = blk_mq_debugfs_rq_show, 731209cb7fSBart Van Assche }; 741209cb7fSBart Van Assche 7591d68905SBart Van Assche static int blk_flags_show(struct seq_file *m, const unsigned long flags, 7691d68905SBart Van Assche const char *const *flag_name, int flag_name_count) 7791d68905SBart Van Assche { 7891d68905SBart Van Assche bool sep = false; 7991d68905SBart Van Assche int i; 8091d68905SBart Van Assche 8191d68905SBart Van Assche for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) { 8291d68905SBart Van Assche if (!(flags & BIT(i))) 8391d68905SBart Van Assche continue; 8491d68905SBart Van Assche if (sep) 85bec03d6bSOmar Sandoval seq_puts(m, "|"); 8691d68905SBart Van Assche sep = true; 8791d68905SBart Van Assche if (i < flag_name_count && flag_name[i]) 8891d68905SBart Van Assche seq_puts(m, flag_name[i]); 8991d68905SBart Van Assche else 9091d68905SBart Van Assche seq_printf(m, "%d", i); 9191d68905SBart Van Assche } 9291d68905SBart Van Assche return 0; 9391d68905SBart Van Assche } 9491d68905SBart Van Assche 95cd84a62eSBart Van Assche static int queue_pm_only_show(void *data, struct seq_file *m) 96cd84a62eSBart Van Assche { 97cd84a62eSBart Van Assche struct request_queue *q = data; 98cd84a62eSBart Van Assche 99cd84a62eSBart Van Assche seq_printf(m, "%d\n", atomic_read(&q->pm_only)); 100cd84a62eSBart Van Assche return 0; 101cd84a62eSBart Van Assche } 102cd84a62eSBart Van Assche 1031a435111SOmar Sandoval #define QUEUE_FLAG_NAME(name) [QUEUE_FLAG_##name] = #name 10491d68905SBart Van Assche static const char *const blk_queue_flag_name[] = { 1051a435111SOmar Sandoval QUEUE_FLAG_NAME(STOPPED), 1061a435111SOmar Sandoval QUEUE_FLAG_NAME(DYING), 1071a435111SOmar Sandoval QUEUE_FLAG_NAME(NOMERGES), 1081a435111SOmar Sandoval QUEUE_FLAG_NAME(SAME_COMP), 1091a435111SOmar Sandoval QUEUE_FLAG_NAME(FAIL_IO), 1101a435111SOmar Sandoval QUEUE_FLAG_NAME(NONROT), 1111a435111SOmar Sandoval QUEUE_FLAG_NAME(IO_STAT), 1121a435111SOmar Sandoval QUEUE_FLAG_NAME(DISCARD), 1131a435111SOmar Sandoval QUEUE_FLAG_NAME(NOXMERGES), 1141a435111SOmar Sandoval QUEUE_FLAG_NAME(ADD_RANDOM), 1151a435111SOmar Sandoval QUEUE_FLAG_NAME(SECERASE), 1161a435111SOmar Sandoval QUEUE_FLAG_NAME(SAME_FORCE), 1171a435111SOmar Sandoval QUEUE_FLAG_NAME(DEAD), 1181a435111SOmar Sandoval QUEUE_FLAG_NAME(INIT_DONE), 1191cb039f3SChristoph Hellwig QUEUE_FLAG_NAME(STABLE_WRITES), 1201a435111SOmar Sandoval QUEUE_FLAG_NAME(POLL), 1211a435111SOmar Sandoval QUEUE_FLAG_NAME(WC), 1221a435111SOmar Sandoval QUEUE_FLAG_NAME(FUA), 1231a435111SOmar Sandoval QUEUE_FLAG_NAME(DAX), 1241a435111SOmar Sandoval QUEUE_FLAG_NAME(STATS), 1251a435111SOmar Sandoval QUEUE_FLAG_NAME(POLL_STATS), 1261a435111SOmar Sandoval QUEUE_FLAG_NAME(REGISTERED), 12722d53821SBart Van Assche QUEUE_FLAG_NAME(SCSI_PASSTHROUGH), 12822d53821SBart Van Assche QUEUE_FLAG_NAME(QUIESCED), 129bfe373f6SHou Tao QUEUE_FLAG_NAME(PCI_P2PDMA), 130bfe373f6SHou Tao QUEUE_FLAG_NAME(ZONE_RESETALL), 131bfe373f6SHou Tao QUEUE_FLAG_NAME(RQ_ALLOC_TIME), 132*1dbdd99bSJohannes Thumshirn QUEUE_FLAG_NAME(HCTX_ACTIVE), 133dc304326SAndres Freund QUEUE_FLAG_NAME(NOWAIT), 13491d68905SBart Van Assche }; 1351a435111SOmar Sandoval #undef QUEUE_FLAG_NAME 13691d68905SBart Van Assche 137f57de23aSOmar Sandoval static int queue_state_show(void *data, struct seq_file *m) 13891d68905SBart Van Assche { 139f57de23aSOmar Sandoval struct request_queue *q = data; 14091d68905SBart Van Assche 14191d68905SBart Van Assche blk_flags_show(m, q->queue_flags, blk_queue_flag_name, 14291d68905SBart Van Assche ARRAY_SIZE(blk_queue_flag_name)); 143fd07dc81SBart Van Assche seq_puts(m, "\n"); 14491d68905SBart Van Assche return 0; 14591d68905SBart Van Assche } 14691d68905SBart Van Assche 147f57de23aSOmar Sandoval static ssize_t queue_state_write(void *data, const char __user *buf, 148c7e4145aSOmar Sandoval size_t count, loff_t *ppos) 14991d68905SBart Van Assche { 150f57de23aSOmar Sandoval struct request_queue *q = data; 15171b90511SOmar Sandoval char opbuf[16] = { }, *op; 15291d68905SBart Van Assche 15318d4d7d0SBart Van Assche /* 15418d4d7d0SBart Van Assche * The "state" attribute is removed after blk_cleanup_queue() has called 15518d4d7d0SBart Van Assche * blk_mq_free_queue(). Return if QUEUE_FLAG_DEAD has been set to avoid 15618d4d7d0SBart Van Assche * triggering a use-after-free. 15718d4d7d0SBart Van Assche */ 15818d4d7d0SBart Van Assche if (blk_queue_dead(q)) 15918d4d7d0SBart Van Assche return -ENOENT; 16018d4d7d0SBart Van Assche 16171b90511SOmar Sandoval if (count >= sizeof(opbuf)) { 162c7e4145aSOmar Sandoval pr_err("%s: operation too long\n", __func__); 163c7e4145aSOmar Sandoval goto inval; 164c7e4145aSOmar Sandoval } 165c7e4145aSOmar Sandoval 16671b90511SOmar Sandoval if (copy_from_user(opbuf, buf, count)) 16791d68905SBart Van Assche return -EFAULT; 16871b90511SOmar Sandoval op = strstrip(opbuf); 16991d68905SBart Van Assche if (strcmp(op, "run") == 0) { 17091d68905SBart Van Assche blk_mq_run_hw_queues(q, true); 17191d68905SBart Van Assche } else if (strcmp(op, "start") == 0) { 17291d68905SBart Van Assche blk_mq_start_stopped_hw_queues(q, true); 173edea55abSBart Van Assche } else if (strcmp(op, "kick") == 0) { 174edea55abSBart Van Assche blk_mq_kick_requeue_list(q); 17591d68905SBart Van Assche } else { 176c7e4145aSOmar Sandoval pr_err("%s: unsupported operation '%s'\n", __func__, op); 177c7e4145aSOmar Sandoval inval: 178edea55abSBart Van Assche pr_err("%s: use 'run', 'start' or 'kick'\n", __func__); 17991d68905SBart Van Assche return -EINVAL; 18091d68905SBart Van Assche } 181c7e4145aSOmar Sandoval return count; 18291d68905SBart Van Assche } 18391d68905SBart Van Assche 184f793dfd3SJens Axboe static int queue_write_hint_show(void *data, struct seq_file *m) 185f793dfd3SJens Axboe { 186f793dfd3SJens Axboe struct request_queue *q = data; 187f793dfd3SJens Axboe int i; 188f793dfd3SJens Axboe 189f793dfd3SJens Axboe for (i = 0; i < BLK_MAX_WRITE_HINTS; i++) 190f793dfd3SJens Axboe seq_printf(m, "hint%d: %llu\n", i, q->write_hints[i]); 191f793dfd3SJens Axboe 192f793dfd3SJens Axboe return 0; 193f793dfd3SJens Axboe } 194f793dfd3SJens Axboe 195f793dfd3SJens Axboe static ssize_t queue_write_hint_store(void *data, const char __user *buf, 196f793dfd3SJens Axboe size_t count, loff_t *ppos) 197f793dfd3SJens Axboe { 198f793dfd3SJens Axboe struct request_queue *q = data; 199f793dfd3SJens Axboe int i; 200f793dfd3SJens Axboe 201f793dfd3SJens Axboe for (i = 0; i < BLK_MAX_WRITE_HINTS; i++) 202f793dfd3SJens Axboe q->write_hints[i] = 0; 203f793dfd3SJens Axboe 204f793dfd3SJens Axboe return count; 205f793dfd3SJens Axboe } 206f793dfd3SJens Axboe 2071209cb7fSBart Van Assche static const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = { 2081209cb7fSBart Van Assche { "poll_stat", 0400, queue_poll_stat_show }, 2091209cb7fSBart Van Assche { "requeue_list", 0400, .seq_ops = &queue_requeue_list_seq_ops }, 210cd84a62eSBart Van Assche { "pm_only", 0600, queue_pm_only_show, NULL }, 2111209cb7fSBart Van Assche { "state", 0600, queue_state_show, queue_state_write }, 2121209cb7fSBart Van Assche { "write_hints", 0600, queue_write_hint_show, queue_write_hint_store }, 21318bc4230SBart Van Assche { "zone_wlock", 0400, queue_zone_wlock_show, NULL }, 2141209cb7fSBart Van Assche { }, 2151209cb7fSBart Van Assche }; 21634dbad5dSOmar Sandoval 2171a435111SOmar Sandoval #define HCTX_STATE_NAME(name) [BLK_MQ_S_##name] = #name 218f5c0b091SBart Van Assche static const char *const hctx_state_name[] = { 2191a435111SOmar Sandoval HCTX_STATE_NAME(STOPPED), 2201a435111SOmar Sandoval HCTX_STATE_NAME(TAG_ACTIVE), 2211a435111SOmar Sandoval HCTX_STATE_NAME(SCHED_RESTART), 222bf0beec0SMing Lei HCTX_STATE_NAME(INACTIVE), 223f5c0b091SBart Van Assche }; 2241a435111SOmar Sandoval #undef HCTX_STATE_NAME 2251a435111SOmar Sandoval 226f57de23aSOmar Sandoval static int hctx_state_show(void *data, struct seq_file *m) 2279abb2ad2SOmar Sandoval { 228f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 2299abb2ad2SOmar Sandoval 230f5c0b091SBart Van Assche blk_flags_show(m, hctx->state, hctx_state_name, 231f5c0b091SBart Van Assche ARRAY_SIZE(hctx_state_name)); 232fd07dc81SBart Van Assche seq_puts(m, "\n"); 2339abb2ad2SOmar Sandoval return 0; 2349abb2ad2SOmar Sandoval } 2359abb2ad2SOmar Sandoval 2361a435111SOmar Sandoval #define BLK_TAG_ALLOC_NAME(name) [BLK_TAG_ALLOC_##name] = #name 237f5c0b091SBart Van Assche static const char *const alloc_policy_name[] = { 2381a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(FIFO), 2391a435111SOmar Sandoval BLK_TAG_ALLOC_NAME(RR), 240f5c0b091SBart Van Assche }; 2411a435111SOmar Sandoval #undef BLK_TAG_ALLOC_NAME 242f5c0b091SBart Van Assche 2431a435111SOmar Sandoval #define HCTX_FLAG_NAME(name) [ilog2(BLK_MQ_F_##name)] = #name 244f5c0b091SBart Van Assche static const char *const hctx_flag_name[] = { 2451a435111SOmar Sandoval HCTX_FLAG_NAME(SHOULD_MERGE), 24651db1c37SMing Lei HCTX_FLAG_NAME(TAG_QUEUE_SHARED), 2471a435111SOmar Sandoval HCTX_FLAG_NAME(BLOCKING), 2481a435111SOmar Sandoval HCTX_FLAG_NAME(NO_SCHED), 249bf0beec0SMing Lei HCTX_FLAG_NAME(STACKING), 25002f938e9SJohn Garry HCTX_FLAG_NAME(TAG_HCTX_SHARED), 251f5c0b091SBart Van Assche }; 2521a435111SOmar Sandoval #undef HCTX_FLAG_NAME 253f5c0b091SBart Van Assche 254f57de23aSOmar Sandoval static int hctx_flags_show(void *data, struct seq_file *m) 2559abb2ad2SOmar Sandoval { 256f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 257f5c0b091SBart Van Assche const int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(hctx->flags); 2589abb2ad2SOmar Sandoval 259f5c0b091SBart Van Assche seq_puts(m, "alloc_policy="); 260f5c0b091SBart Van Assche if (alloc_policy < ARRAY_SIZE(alloc_policy_name) && 261f5c0b091SBart Van Assche alloc_policy_name[alloc_policy]) 262f5c0b091SBart Van Assche seq_puts(m, alloc_policy_name[alloc_policy]); 263f5c0b091SBart Van Assche else 264f5c0b091SBart Van Assche seq_printf(m, "%d", alloc_policy); 265f5c0b091SBart Van Assche seq_puts(m, " "); 266f5c0b091SBart Van Assche blk_flags_show(m, 267f5c0b091SBart Van Assche hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy), 268f5c0b091SBart Van Assche hctx_flag_name, ARRAY_SIZE(hctx_flag_name)); 269fd07dc81SBart Van Assche seq_puts(m, "\n"); 2709abb2ad2SOmar Sandoval return 0; 2719abb2ad2SOmar Sandoval } 2729abb2ad2SOmar Sandoval 2731a435111SOmar Sandoval #define CMD_FLAG_NAME(name) [__REQ_##name] = #name 2748658dca8SBart Van Assche static const char *const cmd_flag_name[] = { 2751a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DEV), 2761a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_TRANSPORT), 2771a435111SOmar Sandoval CMD_FLAG_NAME(FAILFAST_DRIVER), 2781a435111SOmar Sandoval CMD_FLAG_NAME(SYNC), 2791a435111SOmar Sandoval CMD_FLAG_NAME(META), 2801a435111SOmar Sandoval CMD_FLAG_NAME(PRIO), 2811a435111SOmar Sandoval CMD_FLAG_NAME(NOMERGE), 2821a435111SOmar Sandoval CMD_FLAG_NAME(IDLE), 2831a435111SOmar Sandoval CMD_FLAG_NAME(INTEGRITY), 2841a435111SOmar Sandoval CMD_FLAG_NAME(FUA), 2851a435111SOmar Sandoval CMD_FLAG_NAME(PREFLUSH), 2861a435111SOmar Sandoval CMD_FLAG_NAME(RAHEAD), 2871a435111SOmar Sandoval CMD_FLAG_NAME(BACKGROUND), 28822d53821SBart Van Assche CMD_FLAG_NAME(NOWAIT), 2891c26010cSJianchao Wang CMD_FLAG_NAME(NOUNMAP), 2901c26010cSJianchao Wang CMD_FLAG_NAME(HIPRI), 2918658dca8SBart Van Assche }; 2921a435111SOmar Sandoval #undef CMD_FLAG_NAME 2938658dca8SBart Van Assche 2941a435111SOmar Sandoval #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name 2958658dca8SBart Van Assche static const char *const rqf_name[] = { 29685ba3effSJens Axboe RQF_NAME(STARTED), 2971a435111SOmar Sandoval RQF_NAME(SOFTBARRIER), 2981a435111SOmar Sandoval RQF_NAME(FLUSH_SEQ), 2991a435111SOmar Sandoval RQF_NAME(MIXED_MERGE), 3001a435111SOmar Sandoval RQF_NAME(MQ_INFLIGHT), 3011a435111SOmar Sandoval RQF_NAME(DONTPREP), 3021a435111SOmar Sandoval RQF_NAME(FAILED), 3031a435111SOmar Sandoval RQF_NAME(QUIET), 3041a435111SOmar Sandoval RQF_NAME(ELVPRIV), 3051a435111SOmar Sandoval RQF_NAME(IO_STAT), 3061a435111SOmar Sandoval RQF_NAME(PM), 3071a435111SOmar Sandoval RQF_NAME(HASHED), 3081a435111SOmar Sandoval RQF_NAME(STATS), 3091a435111SOmar Sandoval RQF_NAME(SPECIAL_PAYLOAD), 3105d75d3f2SJens Axboe RQF_NAME(ZONE_WRITE_LOCKED), 31176a86f9dSJens Axboe RQF_NAME(MQ_POLL_SLEPT), 3128658dca8SBart Van Assche }; 3131a435111SOmar Sandoval #undef RQF_NAME 3148658dca8SBart Van Assche 315ec6dcf63SBart Van Assche static const char *const blk_mq_rq_state_name_array[] = { 316ec6dcf63SBart Van Assche [MQ_RQ_IDLE] = "idle", 317ec6dcf63SBart Van Assche [MQ_RQ_IN_FLIGHT] = "in_flight", 318ec6dcf63SBart Van Assche [MQ_RQ_COMPLETE] = "complete", 319ec6dcf63SBart Van Assche }; 320ec6dcf63SBart Van Assche 321ec6dcf63SBart Van Assche static const char *blk_mq_rq_state_name(enum mq_rq_state rq_state) 322ec6dcf63SBart Van Assche { 323a1e79188SDan Carpenter if (WARN_ON_ONCE((unsigned int)rq_state >= 324ec6dcf63SBart Van Assche ARRAY_SIZE(blk_mq_rq_state_name_array))) 325ec6dcf63SBart Van Assche return "(?)"; 326ec6dcf63SBart Van Assche return blk_mq_rq_state_name_array[rq_state]; 327ec6dcf63SBart Van Assche } 328ec6dcf63SBart Van Assche 329daaadb3eSOmar Sandoval int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq) 330950cd7e9SOmar Sandoval { 3312836ee4bSBart Van Assche const struct blk_mq_ops *const mq_ops = rq->q->mq_ops; 332f9bc64a0SChaitanya Kulkarni const unsigned int op = req_op(rq); 333874c893bSChaitanya Kulkarni const char *op_str = blk_op_str(op); 334950cd7e9SOmar Sandoval 3358658dca8SBart Van Assche seq_printf(m, "%p {.op=", rq); 336874c893bSChaitanya Kulkarni if (strcmp(op_str, "UNKNOWN") == 0) 3373f6d385fSChaitanya Kulkarni seq_printf(m, "%u", op); 3388658dca8SBart Van Assche else 339874c893bSChaitanya Kulkarni seq_printf(m, "%s", op_str); 3408658dca8SBart Van Assche seq_puts(m, ", .cmd_flags="); 3418658dca8SBart Van Assche blk_flags_show(m, rq->cmd_flags & ~REQ_OP_MASK, cmd_flag_name, 3428658dca8SBart Van Assche ARRAY_SIZE(cmd_flag_name)); 3438658dca8SBart Van Assche seq_puts(m, ", .rq_flags="); 3448658dca8SBart Van Assche blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name, 3458658dca8SBart Van Assche ARRAY_SIZE(rqf_name)); 346ec6dcf63SBart Van Assche seq_printf(m, ", .state=%s", blk_mq_rq_state_name(blk_mq_rq_state(rq))); 3472836ee4bSBart Van Assche seq_printf(m, ", .tag=%d, .internal_tag=%d", rq->tag, 3488658dca8SBart Van Assche rq->internal_tag); 3492836ee4bSBart Van Assche if (mq_ops->show_rq) 3502836ee4bSBart Van Assche mq_ops->show_rq(m, rq); 3512836ee4bSBart Van Assche seq_puts(m, "}\n"); 352950cd7e9SOmar Sandoval return 0; 353950cd7e9SOmar Sandoval } 354daaadb3eSOmar Sandoval EXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show); 355daaadb3eSOmar Sandoval 356daaadb3eSOmar Sandoval int blk_mq_debugfs_rq_show(struct seq_file *m, void *v) 357daaadb3eSOmar Sandoval { 358daaadb3eSOmar Sandoval return __blk_mq_debugfs_rq_show(m, list_entry_rq(v)); 359daaadb3eSOmar Sandoval } 36016b738f6SOmar Sandoval EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show); 361950cd7e9SOmar Sandoval 362950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos) 363f3bcb0e6SBart Van Assche __acquires(&hctx->lock) 364950cd7e9SOmar Sandoval { 365950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 366950cd7e9SOmar Sandoval 367950cd7e9SOmar Sandoval spin_lock(&hctx->lock); 368950cd7e9SOmar Sandoval return seq_list_start(&hctx->dispatch, *pos); 369950cd7e9SOmar Sandoval } 370950cd7e9SOmar Sandoval 371950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos) 372950cd7e9SOmar Sandoval { 373950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 374950cd7e9SOmar Sandoval 375950cd7e9SOmar Sandoval return seq_list_next(v, &hctx->dispatch, pos); 376950cd7e9SOmar Sandoval } 377950cd7e9SOmar Sandoval 378950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v) 379f3bcb0e6SBart Van Assche __releases(&hctx->lock) 380950cd7e9SOmar Sandoval { 381950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 382950cd7e9SOmar Sandoval 383950cd7e9SOmar Sandoval spin_unlock(&hctx->lock); 384950cd7e9SOmar Sandoval } 385950cd7e9SOmar Sandoval 386950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = { 387950cd7e9SOmar Sandoval .start = hctx_dispatch_start, 388950cd7e9SOmar Sandoval .next = hctx_dispatch_next, 389950cd7e9SOmar Sandoval .stop = hctx_dispatch_stop, 390950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 391950cd7e9SOmar Sandoval }; 392950cd7e9SOmar Sandoval 3932720bab5SBart Van Assche struct show_busy_params { 3942720bab5SBart Van Assche struct seq_file *m; 3952720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx; 3962720bab5SBart Van Assche }; 3972720bab5SBart Van Assche 3982720bab5SBart Van Assche /* 3992720bab5SBart Van Assche * Note: the state of a request may change while this function is in progress, 4007baa8572SJens Axboe * e.g. due to a concurrent blk_mq_finish_request() call. Returns true to 4017baa8572SJens Axboe * keep iterating requests. 4022720bab5SBart Van Assche */ 4037baa8572SJens Axboe static bool hctx_show_busy_rq(struct request *rq, void *data, bool reserved) 4042720bab5SBart Van Assche { 4052720bab5SBart Van Assche const struct show_busy_params *params = data; 4062720bab5SBart Van Assche 407ea4f995eSJens Axboe if (rq->mq_hctx == params->hctx) 408b5fc1e8bSHou Tao __blk_mq_debugfs_rq_show(params->m, rq); 4097baa8572SJens Axboe 4107baa8572SJens Axboe return true; 4112720bab5SBart Van Assche } 4122720bab5SBart Van Assche 4132720bab5SBart Van Assche static int hctx_busy_show(void *data, struct seq_file *m) 4142720bab5SBart Van Assche { 4152720bab5SBart Van Assche struct blk_mq_hw_ctx *hctx = data; 4162720bab5SBart Van Assche struct show_busy_params params = { .m = m, .hctx = hctx }; 4172720bab5SBart Van Assche 4182720bab5SBart Van Assche blk_mq_tagset_busy_iter(hctx->queue->tag_set, hctx_show_busy_rq, 4192720bab5SBart Van Assche ¶ms); 4202720bab5SBart Van Assche 4212720bab5SBart Van Assche return 0; 4222720bab5SBart Van Assche } 4232720bab5SBart Van Assche 424346fc108SMing Lei static const char *const hctx_types[] = { 425346fc108SMing Lei [HCTX_TYPE_DEFAULT] = "default", 426346fc108SMing Lei [HCTX_TYPE_READ] = "read", 427346fc108SMing Lei [HCTX_TYPE_POLL] = "poll", 428346fc108SMing Lei }; 429346fc108SMing Lei 430346fc108SMing Lei static int hctx_type_show(void *data, struct seq_file *m) 431346fc108SMing Lei { 432346fc108SMing Lei struct blk_mq_hw_ctx *hctx = data; 433346fc108SMing Lei 434346fc108SMing Lei BUILD_BUG_ON(ARRAY_SIZE(hctx_types) != HCTX_MAX_TYPES); 435346fc108SMing Lei seq_printf(m, "%s\n", hctx_types[hctx->type]); 436346fc108SMing Lei return 0; 437346fc108SMing Lei } 438346fc108SMing Lei 439f57de23aSOmar Sandoval static int hctx_ctx_map_show(void *data, struct seq_file *m) 440950cd7e9SOmar Sandoval { 441f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 4420bfa5288SOmar Sandoval 4430bfa5288SOmar Sandoval sbitmap_bitmap_show(&hctx->ctx_map, m); 4440bfa5288SOmar Sandoval return 0; 4450bfa5288SOmar Sandoval } 4460bfa5288SOmar Sandoval 447d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m, 448d96b37c0SOmar Sandoval struct blk_mq_tags *tags) 449d96b37c0SOmar Sandoval { 450d96b37c0SOmar Sandoval seq_printf(m, "nr_tags=%u\n", tags->nr_tags); 451d96b37c0SOmar Sandoval seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags); 452d96b37c0SOmar Sandoval seq_printf(m, "active_queues=%d\n", 453d96b37c0SOmar Sandoval atomic_read(&tags->active_queues)); 454d96b37c0SOmar Sandoval 455d96b37c0SOmar Sandoval seq_puts(m, "\nbitmap_tags:\n"); 456222a5ae0SJohn Garry sbitmap_queue_show(tags->bitmap_tags, m); 457d96b37c0SOmar Sandoval 458d96b37c0SOmar Sandoval if (tags->nr_reserved_tags) { 459d96b37c0SOmar Sandoval seq_puts(m, "\nbreserved_tags:\n"); 460222a5ae0SJohn Garry sbitmap_queue_show(tags->breserved_tags, m); 461d96b37c0SOmar Sandoval } 462d96b37c0SOmar Sandoval } 463d96b37c0SOmar Sandoval 464f57de23aSOmar Sandoval static int hctx_tags_show(void *data, struct seq_file *m) 465d96b37c0SOmar Sandoval { 466f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 467d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 4688c0f14eaSBart Van Assche int res; 469d96b37c0SOmar Sandoval 4708c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4718c0f14eaSBart Van Assche if (res) 4728c0f14eaSBart Van Assche goto out; 473d96b37c0SOmar Sandoval if (hctx->tags) 474d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->tags); 475d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 476d96b37c0SOmar Sandoval 4778c0f14eaSBart Van Assche out: 4788c0f14eaSBart Van Assche return res; 479d96b37c0SOmar Sandoval } 480d96b37c0SOmar Sandoval 481f57de23aSOmar Sandoval static int hctx_tags_bitmap_show(void *data, struct seq_file *m) 482d96b37c0SOmar Sandoval { 483f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 484d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 4858c0f14eaSBart Van Assche int res; 486d7e3621aSOmar Sandoval 4878c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 4888c0f14eaSBart Van Assche if (res) 4898c0f14eaSBart Van Assche goto out; 490d7e3621aSOmar Sandoval if (hctx->tags) 491222a5ae0SJohn Garry sbitmap_bitmap_show(&hctx->tags->bitmap_tags->sb, m); 492d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 4938c0f14eaSBart Van Assche 4948c0f14eaSBart Van Assche out: 4958c0f14eaSBart Van Assche return res; 496d7e3621aSOmar Sandoval } 497d7e3621aSOmar Sandoval 498f57de23aSOmar Sandoval static int hctx_sched_tags_show(void *data, struct seq_file *m) 499d7e3621aSOmar Sandoval { 500f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 501d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 5028c0f14eaSBart Van Assche int res; 503d96b37c0SOmar Sandoval 5048c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 5058c0f14eaSBart Van Assche if (res) 5068c0f14eaSBart Van Assche goto out; 507d96b37c0SOmar Sandoval if (hctx->sched_tags) 508d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->sched_tags); 509d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 510d96b37c0SOmar Sandoval 5118c0f14eaSBart Van Assche out: 5128c0f14eaSBart Van Assche return res; 513d96b37c0SOmar Sandoval } 514d96b37c0SOmar Sandoval 515f57de23aSOmar Sandoval static int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m) 516d96b37c0SOmar Sandoval { 517f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 518d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 5198c0f14eaSBart Van Assche int res; 520d7e3621aSOmar Sandoval 5218c0f14eaSBart Van Assche res = mutex_lock_interruptible(&q->sysfs_lock); 5228c0f14eaSBart Van Assche if (res) 5238c0f14eaSBart Van Assche goto out; 524d7e3621aSOmar Sandoval if (hctx->sched_tags) 525222a5ae0SJohn Garry sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags->sb, m); 526d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 5278c0f14eaSBart Van Assche 5288c0f14eaSBart Van Assche out: 5298c0f14eaSBart Van Assche return res; 530d7e3621aSOmar Sandoval } 531d7e3621aSOmar Sandoval 532f57de23aSOmar Sandoval static int hctx_io_poll_show(void *data, struct seq_file *m) 533d7e3621aSOmar Sandoval { 534f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 535be215473SOmar Sandoval 536be215473SOmar Sandoval seq_printf(m, "considered=%lu\n", hctx->poll_considered); 537be215473SOmar Sandoval seq_printf(m, "invoked=%lu\n", hctx->poll_invoked); 538be215473SOmar Sandoval seq_printf(m, "success=%lu\n", hctx->poll_success); 539be215473SOmar Sandoval return 0; 540be215473SOmar Sandoval } 541be215473SOmar Sandoval 542f57de23aSOmar Sandoval static ssize_t hctx_io_poll_write(void *data, const char __user *buf, 543be215473SOmar Sandoval size_t count, loff_t *ppos) 544be215473SOmar Sandoval { 545f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 546be215473SOmar Sandoval 547be215473SOmar Sandoval hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0; 548be215473SOmar Sandoval return count; 549be215473SOmar Sandoval } 550be215473SOmar Sandoval 551f57de23aSOmar Sandoval static int hctx_dispatched_show(void *data, struct seq_file *m) 552be215473SOmar Sandoval { 553f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 554be215473SOmar Sandoval int i; 555be215473SOmar Sandoval 556be215473SOmar Sandoval seq_printf(m, "%8u\t%lu\n", 0U, hctx->dispatched[0]); 557be215473SOmar Sandoval 558be215473SOmar Sandoval for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) { 559be215473SOmar Sandoval unsigned int d = 1U << (i - 1); 560be215473SOmar Sandoval 561be215473SOmar Sandoval seq_printf(m, "%8u\t%lu\n", d, hctx->dispatched[i]); 562be215473SOmar Sandoval } 563be215473SOmar Sandoval 564be215473SOmar Sandoval seq_printf(m, "%8u+\t%lu\n", 1U << (i - 1), hctx->dispatched[i]); 565be215473SOmar Sandoval return 0; 566be215473SOmar Sandoval } 567be215473SOmar Sandoval 568f57de23aSOmar Sandoval static ssize_t hctx_dispatched_write(void *data, const char __user *buf, 569be215473SOmar Sandoval size_t count, loff_t *ppos) 570be215473SOmar Sandoval { 571f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 572be215473SOmar Sandoval int i; 573be215473SOmar Sandoval 574be215473SOmar Sandoval for (i = 0; i < BLK_MQ_MAX_DISPATCH_ORDER; i++) 575be215473SOmar Sandoval hctx->dispatched[i] = 0; 576be215473SOmar Sandoval return count; 577be215473SOmar Sandoval } 578be215473SOmar Sandoval 579f57de23aSOmar Sandoval static int hctx_queued_show(void *data, struct seq_file *m) 5804a46f05eSOmar Sandoval { 581f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5824a46f05eSOmar Sandoval 5834a46f05eSOmar Sandoval seq_printf(m, "%lu\n", hctx->queued); 5844a46f05eSOmar Sandoval return 0; 5854a46f05eSOmar Sandoval } 5864a46f05eSOmar Sandoval 587f57de23aSOmar Sandoval static ssize_t hctx_queued_write(void *data, const char __user *buf, 5884a46f05eSOmar Sandoval size_t count, loff_t *ppos) 5894a46f05eSOmar Sandoval { 590f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5914a46f05eSOmar Sandoval 5924a46f05eSOmar Sandoval hctx->queued = 0; 5934a46f05eSOmar Sandoval return count; 5944a46f05eSOmar Sandoval } 5954a46f05eSOmar Sandoval 596f57de23aSOmar Sandoval static int hctx_run_show(void *data, struct seq_file *m) 5974a46f05eSOmar Sandoval { 598f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 5994a46f05eSOmar Sandoval 6004a46f05eSOmar Sandoval seq_printf(m, "%lu\n", hctx->run); 6014a46f05eSOmar Sandoval return 0; 6024a46f05eSOmar Sandoval } 6034a46f05eSOmar Sandoval 604f57de23aSOmar Sandoval static ssize_t hctx_run_write(void *data, const char __user *buf, size_t count, 605f57de23aSOmar Sandoval loff_t *ppos) 6064a46f05eSOmar Sandoval { 607f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 6084a46f05eSOmar Sandoval 6094a46f05eSOmar Sandoval hctx->run = 0; 6104a46f05eSOmar Sandoval return count; 6114a46f05eSOmar Sandoval } 6124a46f05eSOmar Sandoval 613f57de23aSOmar Sandoval static int hctx_active_show(void *data, struct seq_file *m) 6144a46f05eSOmar Sandoval { 615f57de23aSOmar Sandoval struct blk_mq_hw_ctx *hctx = data; 6164a46f05eSOmar Sandoval 6174a46f05eSOmar Sandoval seq_printf(m, "%d\n", atomic_read(&hctx->nr_active)); 6184a46f05eSOmar Sandoval return 0; 6194a46f05eSOmar Sandoval } 6204a46f05eSOmar Sandoval 6216e768717SMing Lei static int hctx_dispatch_busy_show(void *data, struct seq_file *m) 6226e768717SMing Lei { 6236e768717SMing Lei struct blk_mq_hw_ctx *hctx = data; 6246e768717SMing Lei 6256e768717SMing Lei seq_printf(m, "%u\n", hctx->dispatch_busy); 6266e768717SMing Lei return 0; 6276e768717SMing Lei } 6286e768717SMing Lei 629c16d6b5aSMing Lei #define CTX_RQ_SEQ_OPS(name, type) \ 630c16d6b5aSMing Lei static void *ctx_##name##_rq_list_start(struct seq_file *m, loff_t *pos) \ 631c16d6b5aSMing Lei __acquires(&ctx->lock) \ 632c16d6b5aSMing Lei { \ 633c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 634c16d6b5aSMing Lei \ 635c16d6b5aSMing Lei spin_lock(&ctx->lock); \ 636c16d6b5aSMing Lei return seq_list_start(&ctx->rq_lists[type], *pos); \ 637c16d6b5aSMing Lei } \ 638c16d6b5aSMing Lei \ 639c16d6b5aSMing Lei static void *ctx_##name##_rq_list_next(struct seq_file *m, void *v, \ 640c16d6b5aSMing Lei loff_t *pos) \ 641c16d6b5aSMing Lei { \ 642c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 643c16d6b5aSMing Lei \ 644c16d6b5aSMing Lei return seq_list_next(v, &ctx->rq_lists[type], pos); \ 645c16d6b5aSMing Lei } \ 646c16d6b5aSMing Lei \ 647c16d6b5aSMing Lei static void ctx_##name##_rq_list_stop(struct seq_file *m, void *v) \ 648c16d6b5aSMing Lei __releases(&ctx->lock) \ 649c16d6b5aSMing Lei { \ 650c16d6b5aSMing Lei struct blk_mq_ctx *ctx = m->private; \ 651c16d6b5aSMing Lei \ 652c16d6b5aSMing Lei spin_unlock(&ctx->lock); \ 653c16d6b5aSMing Lei } \ 654c16d6b5aSMing Lei \ 655c16d6b5aSMing Lei static const struct seq_operations ctx_##name##_rq_list_seq_ops = { \ 656c16d6b5aSMing Lei .start = ctx_##name##_rq_list_start, \ 657c16d6b5aSMing Lei .next = ctx_##name##_rq_list_next, \ 658c16d6b5aSMing Lei .stop = ctx_##name##_rq_list_stop, \ 659c16d6b5aSMing Lei .show = blk_mq_debugfs_rq_show, \ 660950cd7e9SOmar Sandoval } 661950cd7e9SOmar Sandoval 662c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(default, HCTX_TYPE_DEFAULT); 663c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(read, HCTX_TYPE_READ); 664c16d6b5aSMing Lei CTX_RQ_SEQ_OPS(poll, HCTX_TYPE_POLL); 665950cd7e9SOmar Sandoval 666f57de23aSOmar Sandoval static int ctx_dispatched_show(void *data, struct seq_file *m) 667950cd7e9SOmar Sandoval { 668f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6694a46f05eSOmar Sandoval 6704a46f05eSOmar Sandoval seq_printf(m, "%lu %lu\n", ctx->rq_dispatched[1], ctx->rq_dispatched[0]); 6714a46f05eSOmar Sandoval return 0; 6724a46f05eSOmar Sandoval } 6734a46f05eSOmar Sandoval 674f57de23aSOmar Sandoval static ssize_t ctx_dispatched_write(void *data, const char __user *buf, 6754a46f05eSOmar Sandoval size_t count, loff_t *ppos) 6764a46f05eSOmar Sandoval { 677f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6784a46f05eSOmar Sandoval 6794a46f05eSOmar Sandoval ctx->rq_dispatched[0] = ctx->rq_dispatched[1] = 0; 6804a46f05eSOmar Sandoval return count; 6814a46f05eSOmar Sandoval } 6824a46f05eSOmar Sandoval 683f57de23aSOmar Sandoval static int ctx_merged_show(void *data, struct seq_file *m) 6844a46f05eSOmar Sandoval { 685f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6864a46f05eSOmar Sandoval 6874a46f05eSOmar Sandoval seq_printf(m, "%lu\n", ctx->rq_merged); 6884a46f05eSOmar Sandoval return 0; 6894a46f05eSOmar Sandoval } 6904a46f05eSOmar Sandoval 691f57de23aSOmar Sandoval static ssize_t ctx_merged_write(void *data, const char __user *buf, 6924a46f05eSOmar Sandoval size_t count, loff_t *ppos) 6934a46f05eSOmar Sandoval { 694f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 6954a46f05eSOmar Sandoval 6964a46f05eSOmar Sandoval ctx->rq_merged = 0; 6974a46f05eSOmar Sandoval return count; 6984a46f05eSOmar Sandoval } 6994a46f05eSOmar Sandoval 700f57de23aSOmar Sandoval static int ctx_completed_show(void *data, struct seq_file *m) 7014a46f05eSOmar Sandoval { 702f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 7034a46f05eSOmar Sandoval 7044a46f05eSOmar Sandoval seq_printf(m, "%lu %lu\n", ctx->rq_completed[1], ctx->rq_completed[0]); 7054a46f05eSOmar Sandoval return 0; 7064a46f05eSOmar Sandoval } 7074a46f05eSOmar Sandoval 708f57de23aSOmar Sandoval static ssize_t ctx_completed_write(void *data, const char __user *buf, 7094a46f05eSOmar Sandoval size_t count, loff_t *ppos) 7104a46f05eSOmar Sandoval { 711f57de23aSOmar Sandoval struct blk_mq_ctx *ctx = data; 7124a46f05eSOmar Sandoval 7134a46f05eSOmar Sandoval ctx->rq_completed[0] = ctx->rq_completed[1] = 0; 7144a46f05eSOmar Sandoval return count; 7154a46f05eSOmar Sandoval } 7164a46f05eSOmar Sandoval 717f57de23aSOmar Sandoval static int blk_mq_debugfs_show(struct seq_file *m, void *v) 718f57de23aSOmar Sandoval { 719f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 720f57de23aSOmar Sandoval void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private; 721f57de23aSOmar Sandoval 722f57de23aSOmar Sandoval return attr->show(data, m); 723f57de23aSOmar Sandoval } 724f57de23aSOmar Sandoval 725f57de23aSOmar Sandoval static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf, 726f57de23aSOmar Sandoval size_t count, loff_t *ppos) 727f57de23aSOmar Sandoval { 728f57de23aSOmar Sandoval struct seq_file *m = file->private_data; 729f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = m->private; 730f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 731f57de23aSOmar Sandoval 7326b136a24SEryu Guan /* 7336b136a24SEryu Guan * Attributes that only implement .seq_ops are read-only and 'attr' is 7346b136a24SEryu Guan * the same with 'data' in this case. 7356b136a24SEryu Guan */ 7366b136a24SEryu Guan if (attr == data || !attr->write) 737f57de23aSOmar Sandoval return -EPERM; 738f57de23aSOmar Sandoval 739f57de23aSOmar Sandoval return attr->write(data, buf, count, ppos); 740f57de23aSOmar Sandoval } 741f57de23aSOmar Sandoval 742f57de23aSOmar Sandoval static int blk_mq_debugfs_open(struct inode *inode, struct file *file) 743f57de23aSOmar Sandoval { 744f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 745f57de23aSOmar Sandoval void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 746f57de23aSOmar Sandoval struct seq_file *m; 747f57de23aSOmar Sandoval int ret; 748f57de23aSOmar Sandoval 749f57de23aSOmar Sandoval if (attr->seq_ops) { 750f57de23aSOmar Sandoval ret = seq_open(file, attr->seq_ops); 751f57de23aSOmar Sandoval if (!ret) { 752f57de23aSOmar Sandoval m = file->private_data; 753f57de23aSOmar Sandoval m->private = data; 754f57de23aSOmar Sandoval } 755f57de23aSOmar Sandoval return ret; 756f57de23aSOmar Sandoval } 757f57de23aSOmar Sandoval 758f57de23aSOmar Sandoval if (WARN_ON_ONCE(!attr->show)) 759f57de23aSOmar Sandoval return -EPERM; 760f57de23aSOmar Sandoval 761f57de23aSOmar Sandoval return single_open(file, blk_mq_debugfs_show, inode->i_private); 762f57de23aSOmar Sandoval } 763f57de23aSOmar Sandoval 764f57de23aSOmar Sandoval static int blk_mq_debugfs_release(struct inode *inode, struct file *file) 765f57de23aSOmar Sandoval { 766f57de23aSOmar Sandoval const struct blk_mq_debugfs_attr *attr = inode->i_private; 767f57de23aSOmar Sandoval 768f57de23aSOmar Sandoval if (attr->show) 769f57de23aSOmar Sandoval return single_release(inode, file); 770ee1e0359SChaitanya Kulkarni 771f57de23aSOmar Sandoval return seq_release(inode, file); 772f57de23aSOmar Sandoval } 773f57de23aSOmar Sandoval 774f8465933SBart Van Assche static const struct file_operations blk_mq_debugfs_fops = { 775f57de23aSOmar Sandoval .open = blk_mq_debugfs_open, 7764a46f05eSOmar Sandoval .read = seq_read, 777f57de23aSOmar Sandoval .write = blk_mq_debugfs_write, 7784a46f05eSOmar Sandoval .llseek = seq_lseek, 779f57de23aSOmar Sandoval .release = blk_mq_debugfs_release, 7804a46f05eSOmar Sandoval }; 7814a46f05eSOmar Sandoval 78207e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { 783f57de23aSOmar Sandoval {"state", 0400, hctx_state_show}, 784f57de23aSOmar Sandoval {"flags", 0400, hctx_flags_show}, 785f57de23aSOmar Sandoval {"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops}, 7862720bab5SBart Van Assche {"busy", 0400, hctx_busy_show}, 787f57de23aSOmar Sandoval {"ctx_map", 0400, hctx_ctx_map_show}, 788f57de23aSOmar Sandoval {"tags", 0400, hctx_tags_show}, 789f57de23aSOmar Sandoval {"tags_bitmap", 0400, hctx_tags_bitmap_show}, 790f57de23aSOmar Sandoval {"sched_tags", 0400, hctx_sched_tags_show}, 791f57de23aSOmar Sandoval {"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show}, 792f57de23aSOmar Sandoval {"io_poll", 0600, hctx_io_poll_show, hctx_io_poll_write}, 793f57de23aSOmar Sandoval {"dispatched", 0600, hctx_dispatched_show, hctx_dispatched_write}, 794f57de23aSOmar Sandoval {"queued", 0600, hctx_queued_show, hctx_queued_write}, 795f57de23aSOmar Sandoval {"run", 0600, hctx_run_show, hctx_run_write}, 796f57de23aSOmar Sandoval {"active", 0400, hctx_active_show}, 7976e768717SMing Lei {"dispatch_busy", 0400, hctx_dispatch_busy_show}, 798346fc108SMing Lei {"type", 0400, hctx_type_show}, 79972f2f8f6SBart Van Assche {}, 80007e4feadSOmar Sandoval }; 80107e4feadSOmar Sandoval 80207e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = { 803c16d6b5aSMing Lei {"default_rq_list", 0400, .seq_ops = &ctx_default_rq_list_seq_ops}, 804c16d6b5aSMing Lei {"read_rq_list", 0400, .seq_ops = &ctx_read_rq_list_seq_ops}, 805c16d6b5aSMing Lei {"poll_rq_list", 0400, .seq_ops = &ctx_poll_rq_list_seq_ops}, 806f57de23aSOmar Sandoval {"dispatched", 0600, ctx_dispatched_show, ctx_dispatched_write}, 807f57de23aSOmar Sandoval {"merged", 0600, ctx_merged_show, ctx_merged_write}, 808f57de23aSOmar Sandoval {"completed", 0600, ctx_completed_show, ctx_completed_write}, 80972f2f8f6SBart Van Assche {}, 81007e4feadSOmar Sandoval }; 81107e4feadSOmar Sandoval 8126cfc0081SGreg Kroah-Hartman static void debugfs_create_files(struct dentry *parent, void *data, 81372f2f8f6SBart Van Assche const struct blk_mq_debugfs_attr *attr) 81472f2f8f6SBart Van Assche { 81536991ca6SGreg Kroah-Hartman if (IS_ERR_OR_NULL(parent)) 8166cfc0081SGreg Kroah-Hartman return; 81736991ca6SGreg Kroah-Hartman 818f57de23aSOmar Sandoval d_inode(parent)->i_private = data; 819f57de23aSOmar Sandoval 8206cfc0081SGreg Kroah-Hartman for (; attr->name; attr++) 8216cfc0081SGreg Kroah-Hartman debugfs_create_file(attr->name, attr->mode, parent, 8226cfc0081SGreg Kroah-Hartman (void *)attr, &blk_mq_debugfs_fops); 82372f2f8f6SBart Van Assche } 82472f2f8f6SBart Van Assche 8256cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register(struct request_queue *q) 8269c1051aaSOmar Sandoval { 8279c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 8289c1051aaSOmar Sandoval int i; 8299c1051aaSOmar Sandoval 8306cfc0081SGreg Kroah-Hartman debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs); 8319c1051aaSOmar Sandoval 8329c1051aaSOmar Sandoval /* 83370e62f4bSOmar Sandoval * blk_mq_init_sched() attempted to do this already, but q->debugfs_dir 8349c1051aaSOmar Sandoval * didn't exist yet (because we don't know what to name the directory 8359c1051aaSOmar Sandoval * until the queue is registered to a gendisk). 8369c1051aaSOmar Sandoval */ 83770e62f4bSOmar Sandoval if (q->elevator && !q->sched_debugfs_dir) 83870e62f4bSOmar Sandoval blk_mq_debugfs_register_sched(q); 83970e62f4bSOmar Sandoval 84070e62f4bSOmar Sandoval /* Similarly, blk_mq_init_hctx() couldn't do this previously. */ 8419c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) { 8426cfc0081SGreg Kroah-Hartman if (!hctx->debugfs_dir) 8436cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_hctx(q, hctx); 8446cfc0081SGreg Kroah-Hartman if (q->elevator && !hctx->sched_debugfs_dir) 8456cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_sched_hctx(q, hctx); 8469c1051aaSOmar Sandoval } 8479c1051aaSOmar Sandoval 848cc56694fSMing Lei if (q->rq_qos) { 849cc56694fSMing Lei struct rq_qos *rqos = q->rq_qos; 850cc56694fSMing Lei 851cc56694fSMing Lei while (rqos) { 852cc56694fSMing Lei blk_mq_debugfs_register_rqos(rqos); 853cc56694fSMing Lei rqos = rqos->next; 854cc56694fSMing Lei } 855cc56694fSMing Lei } 8569c1051aaSOmar Sandoval } 8579c1051aaSOmar Sandoval 8589c1051aaSOmar Sandoval void blk_mq_debugfs_unregister(struct request_queue *q) 8599c1051aaSOmar Sandoval { 860d332ce09SOmar Sandoval q->sched_debugfs_dir = NULL; 8619c1051aaSOmar Sandoval } 8629c1051aaSOmar Sandoval 8636cfc0081SGreg Kroah-Hartman static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx, 8649c1051aaSOmar Sandoval struct blk_mq_ctx *ctx) 86507e4feadSOmar Sandoval { 86607e4feadSOmar Sandoval struct dentry *ctx_dir; 86707e4feadSOmar Sandoval char name[20]; 86807e4feadSOmar Sandoval 86907e4feadSOmar Sandoval snprintf(name, sizeof(name), "cpu%u", ctx->cpu); 8709c1051aaSOmar Sandoval ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir); 87107e4feadSOmar Sandoval 8726cfc0081SGreg Kroah-Hartman debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs); 87307e4feadSOmar Sandoval } 87407e4feadSOmar Sandoval 8756cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_hctx(struct request_queue *q, 87607e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx) 87707e4feadSOmar Sandoval { 87807e4feadSOmar Sandoval struct blk_mq_ctx *ctx; 87907e4feadSOmar Sandoval char name[20]; 88007e4feadSOmar Sandoval int i; 88107e4feadSOmar Sandoval 8829c1051aaSOmar Sandoval snprintf(name, sizeof(name), "hctx%u", hctx->queue_num); 8839c1051aaSOmar Sandoval hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir); 8849c1051aaSOmar Sandoval 8856cfc0081SGreg Kroah-Hartman debugfs_create_files(hctx->debugfs_dir, hctx, blk_mq_debugfs_hctx_attrs); 88607e4feadSOmar Sandoval 8876cfc0081SGreg Kroah-Hartman hctx_for_each_ctx(hctx, ctx, i) 8886cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_ctx(hctx, ctx); 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 8986cfc0081SGreg Kroah-Hartman void 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 9036cfc0081SGreg Kroah-Hartman queue_for_each_hw_ctx(q, hctx, i) 9046cfc0081SGreg Kroah-Hartman blk_mq_debugfs_register_hctx(q, hctx); 9059c1051aaSOmar Sandoval } 9069c1051aaSOmar Sandoval 9079c1051aaSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q) 9089c1051aaSOmar Sandoval { 9099c1051aaSOmar Sandoval struct blk_mq_hw_ctx *hctx; 9109c1051aaSOmar Sandoval int i; 9119c1051aaSOmar Sandoval 9129c1051aaSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) 9139c1051aaSOmar Sandoval blk_mq_debugfs_unregister_hctx(hctx); 91407e4feadSOmar Sandoval } 915d332ce09SOmar Sandoval 9166cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_sched(struct request_queue *q) 917d332ce09SOmar Sandoval { 918d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 919d332ce09SOmar Sandoval 9207e41c3c9SGreg Kroah-Hartman /* 9217e41c3c9SGreg Kroah-Hartman * If the parent directory has not been created yet, return, we will be 9227e41c3c9SGreg Kroah-Hartman * called again later on and the directory/files will be created then. 9237e41c3c9SGreg Kroah-Hartman */ 9247e41c3c9SGreg Kroah-Hartman if (!q->debugfs_dir) 9257e41c3c9SGreg Kroah-Hartman return; 9267e41c3c9SGreg Kroah-Hartman 927d332ce09SOmar Sandoval if (!e->queue_debugfs_attrs) 9286cfc0081SGreg Kroah-Hartman return; 929d332ce09SOmar Sandoval 930d332ce09SOmar Sandoval q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir); 931d332ce09SOmar Sandoval 9326cfc0081SGreg Kroah-Hartman debugfs_create_files(q->sched_debugfs_dir, q, e->queue_debugfs_attrs); 933d332ce09SOmar Sandoval } 934d332ce09SOmar Sandoval 935d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched(struct request_queue *q) 936d332ce09SOmar Sandoval { 937d332ce09SOmar Sandoval debugfs_remove_recursive(q->sched_debugfs_dir); 938d332ce09SOmar Sandoval q->sched_debugfs_dir = NULL; 939d332ce09SOmar Sandoval } 940d332ce09SOmar Sandoval 941fb44023eSBart Van Assche static const char *rq_qos_id_to_name(enum rq_qos_id id) 942fb44023eSBart Van Assche { 943fb44023eSBart Van Assche switch (id) { 944fb44023eSBart Van Assche case RQ_QOS_WBT: 945fb44023eSBart Van Assche return "wbt"; 946fb44023eSBart Van Assche case RQ_QOS_LATENCY: 947fb44023eSBart Van Assche return "latency"; 948fb44023eSBart Van Assche case RQ_QOS_COST: 949fb44023eSBart Van Assche return "cost"; 950556910e3SBart Van Assche case RQ_QOS_IOPRIO: 951556910e3SBart Van Assche return "ioprio"; 952fb44023eSBart Van Assche } 953fb44023eSBart Van Assche return "unknown"; 954fb44023eSBart Van Assche } 955fb44023eSBart Van Assche 956cc56694fSMing Lei void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos) 957cc56694fSMing Lei { 958cc56694fSMing Lei debugfs_remove_recursive(rqos->debugfs_dir); 959cc56694fSMing Lei rqos->debugfs_dir = NULL; 960cc56694fSMing Lei } 961cc56694fSMing Lei 9626cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_rqos(struct rq_qos *rqos) 963cc56694fSMing Lei { 964cc56694fSMing Lei struct request_queue *q = rqos->q; 965cc56694fSMing Lei const char *dir_name = rq_qos_id_to_name(rqos->id); 966cc56694fSMing Lei 967cc56694fSMing Lei if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs) 9686cfc0081SGreg Kroah-Hartman return; 969cc56694fSMing Lei 9706cfc0081SGreg Kroah-Hartman if (!q->rqos_debugfs_dir) 971cc56694fSMing Lei q->rqos_debugfs_dir = debugfs_create_dir("rqos", 972cc56694fSMing Lei q->debugfs_dir); 973cc56694fSMing Lei 974cc56694fSMing Lei rqos->debugfs_dir = debugfs_create_dir(dir_name, 975cc56694fSMing Lei rqos->q->rqos_debugfs_dir); 976cc56694fSMing Lei 9776cfc0081SGreg Kroah-Hartman debugfs_create_files(rqos->debugfs_dir, rqos, rqos->ops->debugfs_attrs); 978cc56694fSMing Lei } 979cc56694fSMing Lei 980cc56694fSMing Lei void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q) 981cc56694fSMing Lei { 982cc56694fSMing Lei debugfs_remove_recursive(q->rqos_debugfs_dir); 983cc56694fSMing Lei q->rqos_debugfs_dir = NULL; 984cc56694fSMing Lei } 985cc56694fSMing Lei 9866cfc0081SGreg Kroah-Hartman void blk_mq_debugfs_register_sched_hctx(struct request_queue *q, 987d332ce09SOmar Sandoval struct blk_mq_hw_ctx *hctx) 988d332ce09SOmar Sandoval { 989d332ce09SOmar Sandoval struct elevator_type *e = q->elevator->type; 990d332ce09SOmar Sandoval 9911e91e28eSSaravanan D /* 9921e91e28eSSaravanan D * If the parent debugfs directory has not been created yet, return; 9931e91e28eSSaravanan D * We will be called again later on with appropriate parent debugfs 9941e91e28eSSaravanan D * directory from blk_register_queue() 9951e91e28eSSaravanan D */ 9961e91e28eSSaravanan D if (!hctx->debugfs_dir) 9971e91e28eSSaravanan D return; 9981e91e28eSSaravanan D 999d332ce09SOmar Sandoval if (!e->hctx_debugfs_attrs) 10006cfc0081SGreg Kroah-Hartman return; 1001d332ce09SOmar Sandoval 1002d332ce09SOmar Sandoval hctx->sched_debugfs_dir = debugfs_create_dir("sched", 1003d332ce09SOmar Sandoval hctx->debugfs_dir); 10046cfc0081SGreg Kroah-Hartman debugfs_create_files(hctx->sched_debugfs_dir, hctx, 10056cfc0081SGreg Kroah-Hartman e->hctx_debugfs_attrs); 1006d332ce09SOmar Sandoval } 1007d332ce09SOmar Sandoval 1008d332ce09SOmar Sandoval void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx) 1009d332ce09SOmar Sandoval { 1010d332ce09SOmar Sandoval debugfs_remove_recursive(hctx->sched_debugfs_dir); 1011d332ce09SOmar Sandoval hctx->sched_debugfs_dir = NULL; 1012d332ce09SOmar Sandoval } 1013