162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 Facebook 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/blkdev.h> 862306a36Sopenharmony_ci#include <linux/debugfs.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "blk.h" 1162306a36Sopenharmony_ci#include "blk-mq.h" 1262306a36Sopenharmony_ci#include "blk-mq-debugfs.h" 1362306a36Sopenharmony_ci#include "blk-mq-sched.h" 1462306a36Sopenharmony_ci#include "blk-rq-qos.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic int queue_poll_stat_show(void *data, struct seq_file *m) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci return 0; 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void *queue_requeue_list_start(struct seq_file *m, loff_t *pos) 2262306a36Sopenharmony_ci __acquires(&q->requeue_lock) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct request_queue *q = m->private; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci spin_lock_irq(&q->requeue_lock); 2762306a36Sopenharmony_ci return seq_list_start(&q->requeue_list, *pos); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic void *queue_requeue_list_next(struct seq_file *m, void *v, loff_t *pos) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct request_queue *q = m->private; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci return seq_list_next(v, &q->requeue_list, pos); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void queue_requeue_list_stop(struct seq_file *m, void *v) 3862306a36Sopenharmony_ci __releases(&q->requeue_lock) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct request_queue *q = m->private; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci spin_unlock_irq(&q->requeue_lock); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic const struct seq_operations queue_requeue_list_seq_ops = { 4662306a36Sopenharmony_ci .start = queue_requeue_list_start, 4762306a36Sopenharmony_ci .next = queue_requeue_list_next, 4862306a36Sopenharmony_ci .stop = queue_requeue_list_stop, 4962306a36Sopenharmony_ci .show = blk_mq_debugfs_rq_show, 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int blk_flags_show(struct seq_file *m, const unsigned long flags, 5362306a36Sopenharmony_ci const char *const *flag_name, int flag_name_count) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci bool sep = false; 5662306a36Sopenharmony_ci int i; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) { 5962306a36Sopenharmony_ci if (!(flags & BIT(i))) 6062306a36Sopenharmony_ci continue; 6162306a36Sopenharmony_ci if (sep) 6262306a36Sopenharmony_ci seq_puts(m, "|"); 6362306a36Sopenharmony_ci sep = true; 6462306a36Sopenharmony_ci if (i < flag_name_count && flag_name[i]) 6562306a36Sopenharmony_ci seq_puts(m, flag_name[i]); 6662306a36Sopenharmony_ci else 6762306a36Sopenharmony_ci seq_printf(m, "%d", i); 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int queue_pm_only_show(void *data, struct seq_file *m) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct request_queue *q = data; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci seq_printf(m, "%d\n", atomic_read(&q->pm_only)); 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define QUEUE_FLAG_NAME(name) [QUEUE_FLAG_##name] = #name 8162306a36Sopenharmony_cistatic const char *const blk_queue_flag_name[] = { 8262306a36Sopenharmony_ci QUEUE_FLAG_NAME(STOPPED), 8362306a36Sopenharmony_ci QUEUE_FLAG_NAME(DYING), 8462306a36Sopenharmony_ci QUEUE_FLAG_NAME(NOMERGES), 8562306a36Sopenharmony_ci QUEUE_FLAG_NAME(SAME_COMP), 8662306a36Sopenharmony_ci QUEUE_FLAG_NAME(FAIL_IO), 8762306a36Sopenharmony_ci QUEUE_FLAG_NAME(NONROT), 8862306a36Sopenharmony_ci QUEUE_FLAG_NAME(IO_STAT), 8962306a36Sopenharmony_ci QUEUE_FLAG_NAME(NOXMERGES), 9062306a36Sopenharmony_ci QUEUE_FLAG_NAME(ADD_RANDOM), 9162306a36Sopenharmony_ci QUEUE_FLAG_NAME(SYNCHRONOUS), 9262306a36Sopenharmony_ci QUEUE_FLAG_NAME(SAME_FORCE), 9362306a36Sopenharmony_ci QUEUE_FLAG_NAME(INIT_DONE), 9462306a36Sopenharmony_ci QUEUE_FLAG_NAME(STABLE_WRITES), 9562306a36Sopenharmony_ci QUEUE_FLAG_NAME(POLL), 9662306a36Sopenharmony_ci QUEUE_FLAG_NAME(WC), 9762306a36Sopenharmony_ci QUEUE_FLAG_NAME(FUA), 9862306a36Sopenharmony_ci QUEUE_FLAG_NAME(DAX), 9962306a36Sopenharmony_ci QUEUE_FLAG_NAME(STATS), 10062306a36Sopenharmony_ci QUEUE_FLAG_NAME(REGISTERED), 10162306a36Sopenharmony_ci QUEUE_FLAG_NAME(QUIESCED), 10262306a36Sopenharmony_ci QUEUE_FLAG_NAME(PCI_P2PDMA), 10362306a36Sopenharmony_ci QUEUE_FLAG_NAME(ZONE_RESETALL), 10462306a36Sopenharmony_ci QUEUE_FLAG_NAME(RQ_ALLOC_TIME), 10562306a36Sopenharmony_ci QUEUE_FLAG_NAME(HCTX_ACTIVE), 10662306a36Sopenharmony_ci QUEUE_FLAG_NAME(NOWAIT), 10762306a36Sopenharmony_ci QUEUE_FLAG_NAME(SQ_SCHED), 10862306a36Sopenharmony_ci QUEUE_FLAG_NAME(SKIP_TAGSET_QUIESCE), 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci#undef QUEUE_FLAG_NAME 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int queue_state_show(void *data, struct seq_file *m) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct request_queue *q = data; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci blk_flags_show(m, q->queue_flags, blk_queue_flag_name, 11762306a36Sopenharmony_ci ARRAY_SIZE(blk_queue_flag_name)); 11862306a36Sopenharmony_ci seq_puts(m, "\n"); 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic ssize_t queue_state_write(void *data, const char __user *buf, 12362306a36Sopenharmony_ci size_t count, loff_t *ppos) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct request_queue *q = data; 12662306a36Sopenharmony_ci char opbuf[16] = { }, *op; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* 12962306a36Sopenharmony_ci * The "state" attribute is removed when the queue is removed. Don't 13062306a36Sopenharmony_ci * allow setting the state on a dying queue to avoid a use-after-free. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci if (blk_queue_dying(q)) 13362306a36Sopenharmony_ci return -ENOENT; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (count >= sizeof(opbuf)) { 13662306a36Sopenharmony_ci pr_err("%s: operation too long\n", __func__); 13762306a36Sopenharmony_ci goto inval; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (copy_from_user(opbuf, buf, count)) 14162306a36Sopenharmony_ci return -EFAULT; 14262306a36Sopenharmony_ci op = strstrip(opbuf); 14362306a36Sopenharmony_ci if (strcmp(op, "run") == 0) { 14462306a36Sopenharmony_ci blk_mq_run_hw_queues(q, true); 14562306a36Sopenharmony_ci } else if (strcmp(op, "start") == 0) { 14662306a36Sopenharmony_ci blk_mq_start_stopped_hw_queues(q, true); 14762306a36Sopenharmony_ci } else if (strcmp(op, "kick") == 0) { 14862306a36Sopenharmony_ci blk_mq_kick_requeue_list(q); 14962306a36Sopenharmony_ci } else { 15062306a36Sopenharmony_ci pr_err("%s: unsupported operation '%s'\n", __func__, op); 15162306a36Sopenharmony_ciinval: 15262306a36Sopenharmony_ci pr_err("%s: use 'run', 'start' or 'kick'\n", __func__); 15362306a36Sopenharmony_ci return -EINVAL; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci return count; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = { 15962306a36Sopenharmony_ci { "poll_stat", 0400, queue_poll_stat_show }, 16062306a36Sopenharmony_ci { "requeue_list", 0400, .seq_ops = &queue_requeue_list_seq_ops }, 16162306a36Sopenharmony_ci { "pm_only", 0600, queue_pm_only_show, NULL }, 16262306a36Sopenharmony_ci { "state", 0600, queue_state_show, queue_state_write }, 16362306a36Sopenharmony_ci { "zone_wlock", 0400, queue_zone_wlock_show, NULL }, 16462306a36Sopenharmony_ci { }, 16562306a36Sopenharmony_ci}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci#define HCTX_STATE_NAME(name) [BLK_MQ_S_##name] = #name 16862306a36Sopenharmony_cistatic const char *const hctx_state_name[] = { 16962306a36Sopenharmony_ci HCTX_STATE_NAME(STOPPED), 17062306a36Sopenharmony_ci HCTX_STATE_NAME(TAG_ACTIVE), 17162306a36Sopenharmony_ci HCTX_STATE_NAME(SCHED_RESTART), 17262306a36Sopenharmony_ci HCTX_STATE_NAME(INACTIVE), 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci#undef HCTX_STATE_NAME 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic int hctx_state_show(void *data, struct seq_file *m) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci blk_flags_show(m, hctx->state, hctx_state_name, 18162306a36Sopenharmony_ci ARRAY_SIZE(hctx_state_name)); 18262306a36Sopenharmony_ci seq_puts(m, "\n"); 18362306a36Sopenharmony_ci return 0; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci#define BLK_TAG_ALLOC_NAME(name) [BLK_TAG_ALLOC_##name] = #name 18762306a36Sopenharmony_cistatic const char *const alloc_policy_name[] = { 18862306a36Sopenharmony_ci BLK_TAG_ALLOC_NAME(FIFO), 18962306a36Sopenharmony_ci BLK_TAG_ALLOC_NAME(RR), 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci#undef BLK_TAG_ALLOC_NAME 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci#define HCTX_FLAG_NAME(name) [ilog2(BLK_MQ_F_##name)] = #name 19462306a36Sopenharmony_cistatic const char *const hctx_flag_name[] = { 19562306a36Sopenharmony_ci HCTX_FLAG_NAME(SHOULD_MERGE), 19662306a36Sopenharmony_ci HCTX_FLAG_NAME(TAG_QUEUE_SHARED), 19762306a36Sopenharmony_ci HCTX_FLAG_NAME(BLOCKING), 19862306a36Sopenharmony_ci HCTX_FLAG_NAME(NO_SCHED), 19962306a36Sopenharmony_ci HCTX_FLAG_NAME(STACKING), 20062306a36Sopenharmony_ci HCTX_FLAG_NAME(TAG_HCTX_SHARED), 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci#undef HCTX_FLAG_NAME 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int hctx_flags_show(void *data, struct seq_file *m) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 20762306a36Sopenharmony_ci const int alloc_policy = BLK_MQ_FLAG_TO_ALLOC_POLICY(hctx->flags); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci seq_puts(m, "alloc_policy="); 21062306a36Sopenharmony_ci if (alloc_policy < ARRAY_SIZE(alloc_policy_name) && 21162306a36Sopenharmony_ci alloc_policy_name[alloc_policy]) 21262306a36Sopenharmony_ci seq_puts(m, alloc_policy_name[alloc_policy]); 21362306a36Sopenharmony_ci else 21462306a36Sopenharmony_ci seq_printf(m, "%d", alloc_policy); 21562306a36Sopenharmony_ci seq_puts(m, " "); 21662306a36Sopenharmony_ci blk_flags_show(m, 21762306a36Sopenharmony_ci hctx->flags ^ BLK_ALLOC_POLICY_TO_MQ_FLAG(alloc_policy), 21862306a36Sopenharmony_ci hctx_flag_name, ARRAY_SIZE(hctx_flag_name)); 21962306a36Sopenharmony_ci seq_puts(m, "\n"); 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci#define CMD_FLAG_NAME(name) [__REQ_##name] = #name 22462306a36Sopenharmony_cistatic const char *const cmd_flag_name[] = { 22562306a36Sopenharmony_ci CMD_FLAG_NAME(FAILFAST_DEV), 22662306a36Sopenharmony_ci CMD_FLAG_NAME(FAILFAST_TRANSPORT), 22762306a36Sopenharmony_ci CMD_FLAG_NAME(FAILFAST_DRIVER), 22862306a36Sopenharmony_ci CMD_FLAG_NAME(SYNC), 22962306a36Sopenharmony_ci CMD_FLAG_NAME(META), 23062306a36Sopenharmony_ci CMD_FLAG_NAME(PRIO), 23162306a36Sopenharmony_ci CMD_FLAG_NAME(NOMERGE), 23262306a36Sopenharmony_ci CMD_FLAG_NAME(IDLE), 23362306a36Sopenharmony_ci CMD_FLAG_NAME(INTEGRITY), 23462306a36Sopenharmony_ci CMD_FLAG_NAME(FUA), 23562306a36Sopenharmony_ci CMD_FLAG_NAME(PREFLUSH), 23662306a36Sopenharmony_ci CMD_FLAG_NAME(RAHEAD), 23762306a36Sopenharmony_ci CMD_FLAG_NAME(BACKGROUND), 23862306a36Sopenharmony_ci CMD_FLAG_NAME(NOWAIT), 23962306a36Sopenharmony_ci CMD_FLAG_NAME(NOUNMAP), 24062306a36Sopenharmony_ci CMD_FLAG_NAME(POLLED), 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci#undef CMD_FLAG_NAME 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci#define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name 24562306a36Sopenharmony_cistatic const char *const rqf_name[] = { 24662306a36Sopenharmony_ci RQF_NAME(STARTED), 24762306a36Sopenharmony_ci RQF_NAME(FLUSH_SEQ), 24862306a36Sopenharmony_ci RQF_NAME(MIXED_MERGE), 24962306a36Sopenharmony_ci RQF_NAME(MQ_INFLIGHT), 25062306a36Sopenharmony_ci RQF_NAME(DONTPREP), 25162306a36Sopenharmony_ci RQF_NAME(SCHED_TAGS), 25262306a36Sopenharmony_ci RQF_NAME(USE_SCHED), 25362306a36Sopenharmony_ci RQF_NAME(FAILED), 25462306a36Sopenharmony_ci RQF_NAME(QUIET), 25562306a36Sopenharmony_ci RQF_NAME(IO_STAT), 25662306a36Sopenharmony_ci RQF_NAME(PM), 25762306a36Sopenharmony_ci RQF_NAME(HASHED), 25862306a36Sopenharmony_ci RQF_NAME(STATS), 25962306a36Sopenharmony_ci RQF_NAME(SPECIAL_PAYLOAD), 26062306a36Sopenharmony_ci RQF_NAME(ZONE_WRITE_LOCKED), 26162306a36Sopenharmony_ci RQF_NAME(TIMED_OUT), 26262306a36Sopenharmony_ci RQF_NAME(RESV), 26362306a36Sopenharmony_ci}; 26462306a36Sopenharmony_ci#undef RQF_NAME 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic const char *const blk_mq_rq_state_name_array[] = { 26762306a36Sopenharmony_ci [MQ_RQ_IDLE] = "idle", 26862306a36Sopenharmony_ci [MQ_RQ_IN_FLIGHT] = "in_flight", 26962306a36Sopenharmony_ci [MQ_RQ_COMPLETE] = "complete", 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic const char *blk_mq_rq_state_name(enum mq_rq_state rq_state) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci if (WARN_ON_ONCE((unsigned int)rq_state >= 27562306a36Sopenharmony_ci ARRAY_SIZE(blk_mq_rq_state_name_array))) 27662306a36Sopenharmony_ci return "(?)"; 27762306a36Sopenharmony_ci return blk_mq_rq_state_name_array[rq_state]; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ciint __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci const struct blk_mq_ops *const mq_ops = rq->q->mq_ops; 28362306a36Sopenharmony_ci const enum req_op op = req_op(rq); 28462306a36Sopenharmony_ci const char *op_str = blk_op_str(op); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci seq_printf(m, "%p {.op=", rq); 28762306a36Sopenharmony_ci if (strcmp(op_str, "UNKNOWN") == 0) 28862306a36Sopenharmony_ci seq_printf(m, "%u", op); 28962306a36Sopenharmony_ci else 29062306a36Sopenharmony_ci seq_printf(m, "%s", op_str); 29162306a36Sopenharmony_ci seq_puts(m, ", .cmd_flags="); 29262306a36Sopenharmony_ci blk_flags_show(m, (__force unsigned int)(rq->cmd_flags & ~REQ_OP_MASK), 29362306a36Sopenharmony_ci cmd_flag_name, ARRAY_SIZE(cmd_flag_name)); 29462306a36Sopenharmony_ci seq_puts(m, ", .rq_flags="); 29562306a36Sopenharmony_ci blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name, 29662306a36Sopenharmony_ci ARRAY_SIZE(rqf_name)); 29762306a36Sopenharmony_ci seq_printf(m, ", .state=%s", blk_mq_rq_state_name(blk_mq_rq_state(rq))); 29862306a36Sopenharmony_ci seq_printf(m, ", .tag=%d, .internal_tag=%d", rq->tag, 29962306a36Sopenharmony_ci rq->internal_tag); 30062306a36Sopenharmony_ci if (mq_ops->show_rq) 30162306a36Sopenharmony_ci mq_ops->show_rq(m, rq); 30262306a36Sopenharmony_ci seq_puts(m, "}\n"); 30362306a36Sopenharmony_ci return 0; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__blk_mq_debugfs_rq_show); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciint blk_mq_debugfs_rq_show(struct seq_file *m, void *v) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci return __blk_mq_debugfs_rq_show(m, list_entry_rq(v)); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic void *hctx_dispatch_start(struct seq_file *m, loff_t *pos) 31462306a36Sopenharmony_ci __acquires(&hctx->lock) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = m->private; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci spin_lock(&hctx->lock); 31962306a36Sopenharmony_ci return seq_list_start(&hctx->dispatch, *pos); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = m->private; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return seq_list_next(v, &hctx->dispatch, pos); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic void hctx_dispatch_stop(struct seq_file *m, void *v) 33062306a36Sopenharmony_ci __releases(&hctx->lock) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = m->private; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci spin_unlock(&hctx->lock); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic const struct seq_operations hctx_dispatch_seq_ops = { 33862306a36Sopenharmony_ci .start = hctx_dispatch_start, 33962306a36Sopenharmony_ci .next = hctx_dispatch_next, 34062306a36Sopenharmony_ci .stop = hctx_dispatch_stop, 34162306a36Sopenharmony_ci .show = blk_mq_debugfs_rq_show, 34262306a36Sopenharmony_ci}; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistruct show_busy_params { 34562306a36Sopenharmony_ci struct seq_file *m; 34662306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx; 34762306a36Sopenharmony_ci}; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* 35062306a36Sopenharmony_ci * Note: the state of a request may change while this function is in progress, 35162306a36Sopenharmony_ci * e.g. due to a concurrent blk_mq_finish_request() call. Returns true to 35262306a36Sopenharmony_ci * keep iterating requests. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_cistatic bool hctx_show_busy_rq(struct request *rq, void *data) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci const struct show_busy_params *params = data; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (rq->mq_hctx == params->hctx) 35962306a36Sopenharmony_ci __blk_mq_debugfs_rq_show(params->m, rq); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return true; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic int hctx_busy_show(void *data, struct seq_file *m) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 36762306a36Sopenharmony_ci struct show_busy_params params = { .m = m, .hctx = hctx }; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci blk_mq_tagset_busy_iter(hctx->queue->tag_set, hctx_show_busy_rq, 37062306a36Sopenharmony_ci ¶ms); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic const char *const hctx_types[] = { 37662306a36Sopenharmony_ci [HCTX_TYPE_DEFAULT] = "default", 37762306a36Sopenharmony_ci [HCTX_TYPE_READ] = "read", 37862306a36Sopenharmony_ci [HCTX_TYPE_POLL] = "poll", 37962306a36Sopenharmony_ci}; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int hctx_type_show(void *data, struct seq_file *m) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(hctx_types) != HCTX_MAX_TYPES); 38662306a36Sopenharmony_ci seq_printf(m, "%s\n", hctx_types[hctx->type]); 38762306a36Sopenharmony_ci return 0; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic int hctx_ctx_map_show(void *data, struct seq_file *m) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci sbitmap_bitmap_show(&hctx->ctx_map, m); 39562306a36Sopenharmony_ci return 0; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic void blk_mq_debugfs_tags_show(struct seq_file *m, 39962306a36Sopenharmony_ci struct blk_mq_tags *tags) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci seq_printf(m, "nr_tags=%u\n", tags->nr_tags); 40262306a36Sopenharmony_ci seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags); 40362306a36Sopenharmony_ci seq_printf(m, "active_queues=%d\n", 40462306a36Sopenharmony_ci READ_ONCE(tags->active_queues)); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci seq_puts(m, "\nbitmap_tags:\n"); 40762306a36Sopenharmony_ci sbitmap_queue_show(&tags->bitmap_tags, m); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (tags->nr_reserved_tags) { 41062306a36Sopenharmony_ci seq_puts(m, "\nbreserved_tags:\n"); 41162306a36Sopenharmony_ci sbitmap_queue_show(&tags->breserved_tags, m); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int hctx_tags_show(void *data, struct seq_file *m) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 41862306a36Sopenharmony_ci struct request_queue *q = hctx->queue; 41962306a36Sopenharmony_ci int res; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci res = mutex_lock_interruptible(&q->sysfs_lock); 42262306a36Sopenharmony_ci if (res) 42362306a36Sopenharmony_ci goto out; 42462306a36Sopenharmony_ci if (hctx->tags) 42562306a36Sopenharmony_ci blk_mq_debugfs_tags_show(m, hctx->tags); 42662306a36Sopenharmony_ci mutex_unlock(&q->sysfs_lock); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ciout: 42962306a36Sopenharmony_ci return res; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int hctx_tags_bitmap_show(void *data, struct seq_file *m) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 43562306a36Sopenharmony_ci struct request_queue *q = hctx->queue; 43662306a36Sopenharmony_ci int res; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci res = mutex_lock_interruptible(&q->sysfs_lock); 43962306a36Sopenharmony_ci if (res) 44062306a36Sopenharmony_ci goto out; 44162306a36Sopenharmony_ci if (hctx->tags) 44262306a36Sopenharmony_ci sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m); 44362306a36Sopenharmony_ci mutex_unlock(&q->sysfs_lock); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ciout: 44662306a36Sopenharmony_ci return res; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int hctx_sched_tags_show(void *data, struct seq_file *m) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 45262306a36Sopenharmony_ci struct request_queue *q = hctx->queue; 45362306a36Sopenharmony_ci int res; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci res = mutex_lock_interruptible(&q->sysfs_lock); 45662306a36Sopenharmony_ci if (res) 45762306a36Sopenharmony_ci goto out; 45862306a36Sopenharmony_ci if (hctx->sched_tags) 45962306a36Sopenharmony_ci blk_mq_debugfs_tags_show(m, hctx->sched_tags); 46062306a36Sopenharmony_ci mutex_unlock(&q->sysfs_lock); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ciout: 46362306a36Sopenharmony_ci return res; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic int hctx_sched_tags_bitmap_show(void *data, struct seq_file *m) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 46962306a36Sopenharmony_ci struct request_queue *q = hctx->queue; 47062306a36Sopenharmony_ci int res; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci res = mutex_lock_interruptible(&q->sysfs_lock); 47362306a36Sopenharmony_ci if (res) 47462306a36Sopenharmony_ci goto out; 47562306a36Sopenharmony_ci if (hctx->sched_tags) 47662306a36Sopenharmony_ci sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m); 47762306a36Sopenharmony_ci mutex_unlock(&q->sysfs_lock); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ciout: 48062306a36Sopenharmony_ci return res; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic int hctx_run_show(void *data, struct seq_file *m) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci seq_printf(m, "%lu\n", hctx->run); 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic ssize_t hctx_run_write(void *data, const char __user *buf, size_t count, 49262306a36Sopenharmony_ci loff_t *ppos) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci hctx->run = 0; 49762306a36Sopenharmony_ci return count; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int hctx_active_show(void *data, struct seq_file *m) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci seq_printf(m, "%d\n", __blk_mq_active_requests(hctx)); 50562306a36Sopenharmony_ci return 0; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int hctx_dispatch_busy_show(void *data, struct seq_file *m) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx = data; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci seq_printf(m, "%u\n", hctx->dispatch_busy); 51362306a36Sopenharmony_ci return 0; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci#define CTX_RQ_SEQ_OPS(name, type) \ 51762306a36Sopenharmony_cistatic void *ctx_##name##_rq_list_start(struct seq_file *m, loff_t *pos) \ 51862306a36Sopenharmony_ci __acquires(&ctx->lock) \ 51962306a36Sopenharmony_ci{ \ 52062306a36Sopenharmony_ci struct blk_mq_ctx *ctx = m->private; \ 52162306a36Sopenharmony_ci \ 52262306a36Sopenharmony_ci spin_lock(&ctx->lock); \ 52362306a36Sopenharmony_ci return seq_list_start(&ctx->rq_lists[type], *pos); \ 52462306a36Sopenharmony_ci} \ 52562306a36Sopenharmony_ci \ 52662306a36Sopenharmony_cistatic void *ctx_##name##_rq_list_next(struct seq_file *m, void *v, \ 52762306a36Sopenharmony_ci loff_t *pos) \ 52862306a36Sopenharmony_ci{ \ 52962306a36Sopenharmony_ci struct blk_mq_ctx *ctx = m->private; \ 53062306a36Sopenharmony_ci \ 53162306a36Sopenharmony_ci return seq_list_next(v, &ctx->rq_lists[type], pos); \ 53262306a36Sopenharmony_ci} \ 53362306a36Sopenharmony_ci \ 53462306a36Sopenharmony_cistatic void ctx_##name##_rq_list_stop(struct seq_file *m, void *v) \ 53562306a36Sopenharmony_ci __releases(&ctx->lock) \ 53662306a36Sopenharmony_ci{ \ 53762306a36Sopenharmony_ci struct blk_mq_ctx *ctx = m->private; \ 53862306a36Sopenharmony_ci \ 53962306a36Sopenharmony_ci spin_unlock(&ctx->lock); \ 54062306a36Sopenharmony_ci} \ 54162306a36Sopenharmony_ci \ 54262306a36Sopenharmony_cistatic const struct seq_operations ctx_##name##_rq_list_seq_ops = { \ 54362306a36Sopenharmony_ci .start = ctx_##name##_rq_list_start, \ 54462306a36Sopenharmony_ci .next = ctx_##name##_rq_list_next, \ 54562306a36Sopenharmony_ci .stop = ctx_##name##_rq_list_stop, \ 54662306a36Sopenharmony_ci .show = blk_mq_debugfs_rq_show, \ 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ciCTX_RQ_SEQ_OPS(default, HCTX_TYPE_DEFAULT); 55062306a36Sopenharmony_ciCTX_RQ_SEQ_OPS(read, HCTX_TYPE_READ); 55162306a36Sopenharmony_ciCTX_RQ_SEQ_OPS(poll, HCTX_TYPE_POLL); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic int blk_mq_debugfs_show(struct seq_file *m, void *v) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci const struct blk_mq_debugfs_attr *attr = m->private; 55662306a36Sopenharmony_ci void *data = d_inode(m->file->f_path.dentry->d_parent)->i_private; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci return attr->show(data, m); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf, 56262306a36Sopenharmony_ci size_t count, loff_t *ppos) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct seq_file *m = file->private_data; 56562306a36Sopenharmony_ci const struct blk_mq_debugfs_attr *attr = m->private; 56662306a36Sopenharmony_ci void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* 56962306a36Sopenharmony_ci * Attributes that only implement .seq_ops are read-only and 'attr' is 57062306a36Sopenharmony_ci * the same with 'data' in this case. 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci if (attr == data || !attr->write) 57362306a36Sopenharmony_ci return -EPERM; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return attr->write(data, buf, count, ppos); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic int blk_mq_debugfs_open(struct inode *inode, struct file *file) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci const struct blk_mq_debugfs_attr *attr = inode->i_private; 58162306a36Sopenharmony_ci void *data = d_inode(file->f_path.dentry->d_parent)->i_private; 58262306a36Sopenharmony_ci struct seq_file *m; 58362306a36Sopenharmony_ci int ret; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (attr->seq_ops) { 58662306a36Sopenharmony_ci ret = seq_open(file, attr->seq_ops); 58762306a36Sopenharmony_ci if (!ret) { 58862306a36Sopenharmony_ci m = file->private_data; 58962306a36Sopenharmony_ci m->private = data; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci return ret; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (WARN_ON_ONCE(!attr->show)) 59562306a36Sopenharmony_ci return -EPERM; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return single_open(file, blk_mq_debugfs_show, inode->i_private); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic int blk_mq_debugfs_release(struct inode *inode, struct file *file) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci const struct blk_mq_debugfs_attr *attr = inode->i_private; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (attr->show) 60562306a36Sopenharmony_ci return single_release(inode, file); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return seq_release(inode, file); 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic const struct file_operations blk_mq_debugfs_fops = { 61162306a36Sopenharmony_ci .open = blk_mq_debugfs_open, 61262306a36Sopenharmony_ci .read = seq_read, 61362306a36Sopenharmony_ci .write = blk_mq_debugfs_write, 61462306a36Sopenharmony_ci .llseek = seq_lseek, 61562306a36Sopenharmony_ci .release = blk_mq_debugfs_release, 61662306a36Sopenharmony_ci}; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { 61962306a36Sopenharmony_ci {"state", 0400, hctx_state_show}, 62062306a36Sopenharmony_ci {"flags", 0400, hctx_flags_show}, 62162306a36Sopenharmony_ci {"dispatch", 0400, .seq_ops = &hctx_dispatch_seq_ops}, 62262306a36Sopenharmony_ci {"busy", 0400, hctx_busy_show}, 62362306a36Sopenharmony_ci {"ctx_map", 0400, hctx_ctx_map_show}, 62462306a36Sopenharmony_ci {"tags", 0400, hctx_tags_show}, 62562306a36Sopenharmony_ci {"tags_bitmap", 0400, hctx_tags_bitmap_show}, 62662306a36Sopenharmony_ci {"sched_tags", 0400, hctx_sched_tags_show}, 62762306a36Sopenharmony_ci {"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show}, 62862306a36Sopenharmony_ci {"run", 0600, hctx_run_show, hctx_run_write}, 62962306a36Sopenharmony_ci {"active", 0400, hctx_active_show}, 63062306a36Sopenharmony_ci {"dispatch_busy", 0400, hctx_dispatch_busy_show}, 63162306a36Sopenharmony_ci {"type", 0400, hctx_type_show}, 63262306a36Sopenharmony_ci {}, 63362306a36Sopenharmony_ci}; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = { 63662306a36Sopenharmony_ci {"default_rq_list", 0400, .seq_ops = &ctx_default_rq_list_seq_ops}, 63762306a36Sopenharmony_ci {"read_rq_list", 0400, .seq_ops = &ctx_read_rq_list_seq_ops}, 63862306a36Sopenharmony_ci {"poll_rq_list", 0400, .seq_ops = &ctx_poll_rq_list_seq_ops}, 63962306a36Sopenharmony_ci {}, 64062306a36Sopenharmony_ci}; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic void debugfs_create_files(struct dentry *parent, void *data, 64362306a36Sopenharmony_ci const struct blk_mq_debugfs_attr *attr) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci if (IS_ERR_OR_NULL(parent)) 64662306a36Sopenharmony_ci return; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci d_inode(parent)->i_private = data; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci for (; attr->name; attr++) 65162306a36Sopenharmony_ci debugfs_create_file(attr->name, attr->mode, parent, 65262306a36Sopenharmony_ci (void *)attr, &blk_mq_debugfs_fops); 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_civoid blk_mq_debugfs_register(struct request_queue *q) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx; 65862306a36Sopenharmony_ci unsigned long i; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* 66362306a36Sopenharmony_ci * blk_mq_init_sched() attempted to do this already, but q->debugfs_dir 66462306a36Sopenharmony_ci * didn't exist yet (because we don't know what to name the directory 66562306a36Sopenharmony_ci * until the queue is registered to a gendisk). 66662306a36Sopenharmony_ci */ 66762306a36Sopenharmony_ci if (q->elevator && !q->sched_debugfs_dir) 66862306a36Sopenharmony_ci blk_mq_debugfs_register_sched(q); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* Similarly, blk_mq_init_hctx() couldn't do this previously. */ 67162306a36Sopenharmony_ci queue_for_each_hw_ctx(q, hctx, i) { 67262306a36Sopenharmony_ci if (!hctx->debugfs_dir) 67362306a36Sopenharmony_ci blk_mq_debugfs_register_hctx(q, hctx); 67462306a36Sopenharmony_ci if (q->elevator && !hctx->sched_debugfs_dir) 67562306a36Sopenharmony_ci blk_mq_debugfs_register_sched_hctx(q, hctx); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci if (q->rq_qos) { 67962306a36Sopenharmony_ci struct rq_qos *rqos = q->rq_qos; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci while (rqos) { 68262306a36Sopenharmony_ci blk_mq_debugfs_register_rqos(rqos); 68362306a36Sopenharmony_ci rqos = rqos->next; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx, 68962306a36Sopenharmony_ci struct blk_mq_ctx *ctx) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct dentry *ctx_dir; 69262306a36Sopenharmony_ci char name[20]; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci snprintf(name, sizeof(name), "cpu%u", ctx->cpu); 69562306a36Sopenharmony_ci ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs); 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_civoid blk_mq_debugfs_register_hctx(struct request_queue *q, 70162306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci struct blk_mq_ctx *ctx; 70462306a36Sopenharmony_ci char name[20]; 70562306a36Sopenharmony_ci int i; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (!q->debugfs_dir) 70862306a36Sopenharmony_ci return; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci snprintf(name, sizeof(name), "hctx%u", hctx->queue_num); 71162306a36Sopenharmony_ci hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci debugfs_create_files(hctx->debugfs_dir, hctx, blk_mq_debugfs_hctx_attrs); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci hctx_for_each_ctx(hctx, ctx, i) 71662306a36Sopenharmony_ci blk_mq_debugfs_register_ctx(hctx, ctx); 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_civoid blk_mq_debugfs_unregister_hctx(struct blk_mq_hw_ctx *hctx) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci if (!hctx->queue->debugfs_dir) 72262306a36Sopenharmony_ci return; 72362306a36Sopenharmony_ci debugfs_remove_recursive(hctx->debugfs_dir); 72462306a36Sopenharmony_ci hctx->sched_debugfs_dir = NULL; 72562306a36Sopenharmony_ci hctx->debugfs_dir = NULL; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_civoid blk_mq_debugfs_register_hctxs(struct request_queue *q) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx; 73162306a36Sopenharmony_ci unsigned long i; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci queue_for_each_hw_ctx(q, hctx, i) 73462306a36Sopenharmony_ci blk_mq_debugfs_register_hctx(q, hctx); 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_civoid blk_mq_debugfs_unregister_hctxs(struct request_queue *q) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx; 74062306a36Sopenharmony_ci unsigned long i; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci queue_for_each_hw_ctx(q, hctx, i) 74362306a36Sopenharmony_ci blk_mq_debugfs_unregister_hctx(hctx); 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_civoid blk_mq_debugfs_register_sched(struct request_queue *q) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct elevator_type *e = q->elevator->type; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci lockdep_assert_held(&q->debugfs_mutex); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* 75362306a36Sopenharmony_ci * If the parent directory has not been created yet, return, we will be 75462306a36Sopenharmony_ci * called again later on and the directory/files will be created then. 75562306a36Sopenharmony_ci */ 75662306a36Sopenharmony_ci if (!q->debugfs_dir) 75762306a36Sopenharmony_ci return; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (!e->queue_debugfs_attrs) 76062306a36Sopenharmony_ci return; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci debugfs_create_files(q->sched_debugfs_dir, q, e->queue_debugfs_attrs); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_civoid blk_mq_debugfs_unregister_sched(struct request_queue *q) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci lockdep_assert_held(&q->debugfs_mutex); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci debugfs_remove_recursive(q->sched_debugfs_dir); 77262306a36Sopenharmony_ci q->sched_debugfs_dir = NULL; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistatic const char *rq_qos_id_to_name(enum rq_qos_id id) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci switch (id) { 77862306a36Sopenharmony_ci case RQ_QOS_WBT: 77962306a36Sopenharmony_ci return "wbt"; 78062306a36Sopenharmony_ci case RQ_QOS_LATENCY: 78162306a36Sopenharmony_ci return "latency"; 78262306a36Sopenharmony_ci case RQ_QOS_COST: 78362306a36Sopenharmony_ci return "cost"; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci return "unknown"; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_civoid blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci lockdep_assert_held(&rqos->disk->queue->debugfs_mutex); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (!rqos->disk->queue->debugfs_dir) 79362306a36Sopenharmony_ci return; 79462306a36Sopenharmony_ci debugfs_remove_recursive(rqos->debugfs_dir); 79562306a36Sopenharmony_ci rqos->debugfs_dir = NULL; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_civoid blk_mq_debugfs_register_rqos(struct rq_qos *rqos) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct request_queue *q = rqos->disk->queue; 80162306a36Sopenharmony_ci const char *dir_name = rq_qos_id_to_name(rqos->id); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci lockdep_assert_held(&q->debugfs_mutex); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs) 80662306a36Sopenharmony_ci return; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (!q->rqos_debugfs_dir) 80962306a36Sopenharmony_ci q->rqos_debugfs_dir = debugfs_create_dir("rqos", 81062306a36Sopenharmony_ci q->debugfs_dir); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci rqos->debugfs_dir = debugfs_create_dir(dir_name, q->rqos_debugfs_dir); 81362306a36Sopenharmony_ci debugfs_create_files(rqos->debugfs_dir, rqos, rqos->ops->debugfs_attrs); 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_civoid blk_mq_debugfs_register_sched_hctx(struct request_queue *q, 81762306a36Sopenharmony_ci struct blk_mq_hw_ctx *hctx) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci struct elevator_type *e = q->elevator->type; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci lockdep_assert_held(&q->debugfs_mutex); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* 82462306a36Sopenharmony_ci * If the parent debugfs directory has not been created yet, return; 82562306a36Sopenharmony_ci * We will be called again later on with appropriate parent debugfs 82662306a36Sopenharmony_ci * directory from blk_register_queue() 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_ci if (!hctx->debugfs_dir) 82962306a36Sopenharmony_ci return; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (!e->hctx_debugfs_attrs) 83262306a36Sopenharmony_ci return; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci hctx->sched_debugfs_dir = debugfs_create_dir("sched", 83562306a36Sopenharmony_ci hctx->debugfs_dir); 83662306a36Sopenharmony_ci debugfs_create_files(hctx->sched_debugfs_dir, hctx, 83762306a36Sopenharmony_ci e->hctx_debugfs_attrs); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_civoid blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci lockdep_assert_held(&hctx->queue->debugfs_mutex); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (!hctx->queue->debugfs_dir) 84562306a36Sopenharmony_ci return; 84662306a36Sopenharmony_ci debugfs_remove_recursive(hctx->sched_debugfs_dir); 84762306a36Sopenharmony_ci hctx->sched_debugfs_dir = NULL; 84862306a36Sopenharmony_ci} 849