107e4feadSOmar Sandoval /* 207e4feadSOmar Sandoval * Copyright (C) 2017 Facebook 307e4feadSOmar Sandoval * 407e4feadSOmar Sandoval * This program is free software; you can redistribute it and/or 507e4feadSOmar Sandoval * modify it under the terms of the GNU General Public 607e4feadSOmar Sandoval * License v2 as published by the Free Software Foundation. 707e4feadSOmar Sandoval * 807e4feadSOmar Sandoval * This program is distributed in the hope that it will be useful, 907e4feadSOmar Sandoval * but WITHOUT ANY WARRANTY; without even the implied warranty of 1007e4feadSOmar Sandoval * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1107e4feadSOmar Sandoval * General Public License for more details. 1207e4feadSOmar Sandoval * 1307e4feadSOmar Sandoval * You should have received a copy of the GNU General Public License 1407e4feadSOmar Sandoval * along with this program. If not, see <https://www.gnu.org/licenses/>. 1507e4feadSOmar Sandoval */ 1607e4feadSOmar Sandoval 1707e4feadSOmar Sandoval #include <linux/kernel.h> 1807e4feadSOmar Sandoval #include <linux/blkdev.h> 1907e4feadSOmar Sandoval #include <linux/debugfs.h> 2007e4feadSOmar Sandoval 2107e4feadSOmar Sandoval #include <linux/blk-mq.h> 2207e4feadSOmar Sandoval #include "blk-mq.h" 2307e4feadSOmar Sandoval 2407e4feadSOmar Sandoval struct blk_mq_debugfs_attr { 2507e4feadSOmar Sandoval const char *name; 2607e4feadSOmar Sandoval umode_t mode; 2707e4feadSOmar Sandoval const struct file_operations *fops; 2807e4feadSOmar Sandoval }; 2907e4feadSOmar Sandoval 3007e4feadSOmar Sandoval static struct dentry *block_debugfs_root; 3107e4feadSOmar Sandoval 32*950cd7e9SOmar Sandoval static int blk_mq_debugfs_seq_open(struct inode *inode, struct file *file, 33*950cd7e9SOmar Sandoval const struct seq_operations *ops) 34*950cd7e9SOmar Sandoval { 35*950cd7e9SOmar Sandoval struct seq_file *m; 36*950cd7e9SOmar Sandoval int ret; 37*950cd7e9SOmar Sandoval 38*950cd7e9SOmar Sandoval ret = seq_open(file, ops); 39*950cd7e9SOmar Sandoval if (!ret) { 40*950cd7e9SOmar Sandoval m = file->private_data; 41*950cd7e9SOmar Sandoval m->private = inode->i_private; 42*950cd7e9SOmar Sandoval } 43*950cd7e9SOmar Sandoval return ret; 44*950cd7e9SOmar Sandoval } 45*950cd7e9SOmar Sandoval 469abb2ad2SOmar Sandoval static int hctx_state_show(struct seq_file *m, void *v) 479abb2ad2SOmar Sandoval { 489abb2ad2SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 499abb2ad2SOmar Sandoval 509abb2ad2SOmar Sandoval seq_printf(m, "0x%lx\n", hctx->state); 519abb2ad2SOmar Sandoval return 0; 529abb2ad2SOmar Sandoval } 539abb2ad2SOmar Sandoval 549abb2ad2SOmar Sandoval static int hctx_state_open(struct inode *inode, struct file *file) 559abb2ad2SOmar Sandoval { 569abb2ad2SOmar Sandoval return single_open(file, hctx_state_show, inode->i_private); 579abb2ad2SOmar Sandoval } 589abb2ad2SOmar Sandoval 599abb2ad2SOmar Sandoval static const struct file_operations hctx_state_fops = { 609abb2ad2SOmar Sandoval .open = hctx_state_open, 619abb2ad2SOmar Sandoval .read = seq_read, 629abb2ad2SOmar Sandoval .llseek = seq_lseek, 639abb2ad2SOmar Sandoval .release = single_release, 649abb2ad2SOmar Sandoval }; 659abb2ad2SOmar Sandoval 669abb2ad2SOmar Sandoval static int hctx_flags_show(struct seq_file *m, void *v) 679abb2ad2SOmar Sandoval { 689abb2ad2SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 699abb2ad2SOmar Sandoval 709abb2ad2SOmar Sandoval seq_printf(m, "0x%lx\n", hctx->flags); 719abb2ad2SOmar Sandoval return 0; 729abb2ad2SOmar Sandoval } 739abb2ad2SOmar Sandoval 749abb2ad2SOmar Sandoval static int hctx_flags_open(struct inode *inode, struct file *file) 759abb2ad2SOmar Sandoval { 769abb2ad2SOmar Sandoval return single_open(file, hctx_flags_show, inode->i_private); 779abb2ad2SOmar Sandoval } 789abb2ad2SOmar Sandoval 799abb2ad2SOmar Sandoval static const struct file_operations hctx_flags_fops = { 809abb2ad2SOmar Sandoval .open = hctx_flags_open, 819abb2ad2SOmar Sandoval .read = seq_read, 829abb2ad2SOmar Sandoval .llseek = seq_lseek, 839abb2ad2SOmar Sandoval .release = single_release, 849abb2ad2SOmar Sandoval }; 859abb2ad2SOmar Sandoval 86*950cd7e9SOmar Sandoval static int blk_mq_debugfs_rq_show(struct seq_file *m, void *v) 87*950cd7e9SOmar Sandoval { 88*950cd7e9SOmar Sandoval struct request *rq = list_entry_rq(v); 89*950cd7e9SOmar Sandoval 90*950cd7e9SOmar Sandoval seq_printf(m, "%p\n", rq); 91*950cd7e9SOmar Sandoval return 0; 92*950cd7e9SOmar Sandoval } 93*950cd7e9SOmar Sandoval 94*950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos) 95*950cd7e9SOmar Sandoval { 96*950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 97*950cd7e9SOmar Sandoval 98*950cd7e9SOmar Sandoval spin_lock(&hctx->lock); 99*950cd7e9SOmar Sandoval return seq_list_start(&hctx->dispatch, *pos); 100*950cd7e9SOmar Sandoval } 101*950cd7e9SOmar Sandoval 102*950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos) 103*950cd7e9SOmar Sandoval { 104*950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 105*950cd7e9SOmar Sandoval 106*950cd7e9SOmar Sandoval return seq_list_next(v, &hctx->dispatch, pos); 107*950cd7e9SOmar Sandoval } 108*950cd7e9SOmar Sandoval 109*950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v) 110*950cd7e9SOmar Sandoval { 111*950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 112*950cd7e9SOmar Sandoval 113*950cd7e9SOmar Sandoval spin_unlock(&hctx->lock); 114*950cd7e9SOmar Sandoval } 115*950cd7e9SOmar Sandoval 116*950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = { 117*950cd7e9SOmar Sandoval .start = hctx_dispatch_start, 118*950cd7e9SOmar Sandoval .next = hctx_dispatch_next, 119*950cd7e9SOmar Sandoval .stop = hctx_dispatch_stop, 120*950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 121*950cd7e9SOmar Sandoval }; 122*950cd7e9SOmar Sandoval 123*950cd7e9SOmar Sandoval static int hctx_dispatch_open(struct inode *inode, struct file *file) 124*950cd7e9SOmar Sandoval { 125*950cd7e9SOmar Sandoval return blk_mq_debugfs_seq_open(inode, file, &hctx_dispatch_seq_ops); 126*950cd7e9SOmar Sandoval } 127*950cd7e9SOmar Sandoval 128*950cd7e9SOmar Sandoval static const struct file_operations hctx_dispatch_fops = { 129*950cd7e9SOmar Sandoval .open = hctx_dispatch_open, 130*950cd7e9SOmar Sandoval .read = seq_read, 131*950cd7e9SOmar Sandoval .llseek = seq_lseek, 132*950cd7e9SOmar Sandoval .release = seq_release, 133*950cd7e9SOmar Sandoval }; 134*950cd7e9SOmar Sandoval 135*950cd7e9SOmar Sandoval static void *ctx_rq_list_start(struct seq_file *m, loff_t *pos) 136*950cd7e9SOmar Sandoval { 137*950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 138*950cd7e9SOmar Sandoval 139*950cd7e9SOmar Sandoval spin_lock(&ctx->lock); 140*950cd7e9SOmar Sandoval return seq_list_start(&ctx->rq_list, *pos); 141*950cd7e9SOmar Sandoval } 142*950cd7e9SOmar Sandoval 143*950cd7e9SOmar Sandoval static void *ctx_rq_list_next(struct seq_file *m, void *v, loff_t *pos) 144*950cd7e9SOmar Sandoval { 145*950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 146*950cd7e9SOmar Sandoval 147*950cd7e9SOmar Sandoval return seq_list_next(v, &ctx->rq_list, pos); 148*950cd7e9SOmar Sandoval } 149*950cd7e9SOmar Sandoval 150*950cd7e9SOmar Sandoval static void ctx_rq_list_stop(struct seq_file *m, void *v) 151*950cd7e9SOmar Sandoval { 152*950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 153*950cd7e9SOmar Sandoval 154*950cd7e9SOmar Sandoval spin_unlock(&ctx->lock); 155*950cd7e9SOmar Sandoval } 156*950cd7e9SOmar Sandoval 157*950cd7e9SOmar Sandoval static const struct seq_operations ctx_rq_list_seq_ops = { 158*950cd7e9SOmar Sandoval .start = ctx_rq_list_start, 159*950cd7e9SOmar Sandoval .next = ctx_rq_list_next, 160*950cd7e9SOmar Sandoval .stop = ctx_rq_list_stop, 161*950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 162*950cd7e9SOmar Sandoval }; 163*950cd7e9SOmar Sandoval 164*950cd7e9SOmar Sandoval static int ctx_rq_list_open(struct inode *inode, struct file *file) 165*950cd7e9SOmar Sandoval { 166*950cd7e9SOmar Sandoval return blk_mq_debugfs_seq_open(inode, file, &ctx_rq_list_seq_ops); 167*950cd7e9SOmar Sandoval } 168*950cd7e9SOmar Sandoval 169*950cd7e9SOmar Sandoval static const struct file_operations ctx_rq_list_fops = { 170*950cd7e9SOmar Sandoval .open = ctx_rq_list_open, 171*950cd7e9SOmar Sandoval .read = seq_read, 172*950cd7e9SOmar Sandoval .llseek = seq_lseek, 173*950cd7e9SOmar Sandoval .release = seq_release, 174*950cd7e9SOmar Sandoval }; 175*950cd7e9SOmar Sandoval 17607e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { 1779abb2ad2SOmar Sandoval {"state", 0400, &hctx_state_fops}, 1789abb2ad2SOmar Sandoval {"flags", 0400, &hctx_flags_fops}, 179*950cd7e9SOmar Sandoval {"dispatch", 0400, &hctx_dispatch_fops}, 18007e4feadSOmar Sandoval }; 18107e4feadSOmar Sandoval 18207e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = { 183*950cd7e9SOmar Sandoval {"rq_list", 0400, &ctx_rq_list_fops}, 18407e4feadSOmar Sandoval }; 18507e4feadSOmar Sandoval 18607e4feadSOmar Sandoval int blk_mq_debugfs_register(struct request_queue *q, const char *name) 18707e4feadSOmar Sandoval { 18807e4feadSOmar Sandoval if (!block_debugfs_root) 18907e4feadSOmar Sandoval return -ENOENT; 19007e4feadSOmar Sandoval 19107e4feadSOmar Sandoval q->debugfs_dir = debugfs_create_dir(name, block_debugfs_root); 19207e4feadSOmar Sandoval if (!q->debugfs_dir) 19307e4feadSOmar Sandoval goto err; 19407e4feadSOmar Sandoval 19507e4feadSOmar Sandoval if (blk_mq_debugfs_register_hctxs(q)) 19607e4feadSOmar Sandoval goto err; 19707e4feadSOmar Sandoval 19807e4feadSOmar Sandoval return 0; 19907e4feadSOmar Sandoval 20007e4feadSOmar Sandoval err: 20107e4feadSOmar Sandoval blk_mq_debugfs_unregister(q); 20207e4feadSOmar Sandoval return -ENOMEM; 20307e4feadSOmar Sandoval } 20407e4feadSOmar Sandoval 20507e4feadSOmar Sandoval void blk_mq_debugfs_unregister(struct request_queue *q) 20607e4feadSOmar Sandoval { 20707e4feadSOmar Sandoval debugfs_remove_recursive(q->debugfs_dir); 20807e4feadSOmar Sandoval q->mq_debugfs_dir = NULL; 20907e4feadSOmar Sandoval q->debugfs_dir = NULL; 21007e4feadSOmar Sandoval } 21107e4feadSOmar Sandoval 21207e4feadSOmar Sandoval static int blk_mq_debugfs_register_ctx(struct request_queue *q, 21307e4feadSOmar Sandoval struct blk_mq_ctx *ctx, 21407e4feadSOmar Sandoval struct dentry *hctx_dir) 21507e4feadSOmar Sandoval { 21607e4feadSOmar Sandoval struct dentry *ctx_dir; 21707e4feadSOmar Sandoval char name[20]; 21807e4feadSOmar Sandoval int i; 21907e4feadSOmar Sandoval 22007e4feadSOmar Sandoval snprintf(name, sizeof(name), "cpu%u", ctx->cpu); 22107e4feadSOmar Sandoval ctx_dir = debugfs_create_dir(name, hctx_dir); 22207e4feadSOmar Sandoval if (!ctx_dir) 22307e4feadSOmar Sandoval return -ENOMEM; 22407e4feadSOmar Sandoval 22507e4feadSOmar Sandoval for (i = 0; i < ARRAY_SIZE(blk_mq_debugfs_ctx_attrs); i++) { 22607e4feadSOmar Sandoval const struct blk_mq_debugfs_attr *attr; 22707e4feadSOmar Sandoval 22807e4feadSOmar Sandoval attr = &blk_mq_debugfs_ctx_attrs[i]; 22907e4feadSOmar Sandoval if (!debugfs_create_file(attr->name, attr->mode, ctx_dir, ctx, 23007e4feadSOmar Sandoval attr->fops)) 23107e4feadSOmar Sandoval return -ENOMEM; 23207e4feadSOmar Sandoval } 23307e4feadSOmar Sandoval 23407e4feadSOmar Sandoval return 0; 23507e4feadSOmar Sandoval } 23607e4feadSOmar Sandoval 23707e4feadSOmar Sandoval static int blk_mq_debugfs_register_hctx(struct request_queue *q, 23807e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx) 23907e4feadSOmar Sandoval { 24007e4feadSOmar Sandoval struct blk_mq_ctx *ctx; 24107e4feadSOmar Sandoval struct dentry *hctx_dir; 24207e4feadSOmar Sandoval char name[20]; 24307e4feadSOmar Sandoval int i; 24407e4feadSOmar Sandoval 24507e4feadSOmar Sandoval snprintf(name, sizeof(name), "%u", hctx->queue_num); 24607e4feadSOmar Sandoval hctx_dir = debugfs_create_dir(name, q->mq_debugfs_dir); 24707e4feadSOmar Sandoval if (!hctx_dir) 24807e4feadSOmar Sandoval return -ENOMEM; 24907e4feadSOmar Sandoval 25007e4feadSOmar Sandoval for (i = 0; i < ARRAY_SIZE(blk_mq_debugfs_hctx_attrs); i++) { 25107e4feadSOmar Sandoval const struct blk_mq_debugfs_attr *attr; 25207e4feadSOmar Sandoval 25307e4feadSOmar Sandoval attr = &blk_mq_debugfs_hctx_attrs[i]; 25407e4feadSOmar Sandoval if (!debugfs_create_file(attr->name, attr->mode, hctx_dir, hctx, 25507e4feadSOmar Sandoval attr->fops)) 25607e4feadSOmar Sandoval return -ENOMEM; 25707e4feadSOmar Sandoval } 25807e4feadSOmar Sandoval 25907e4feadSOmar Sandoval hctx_for_each_ctx(hctx, ctx, i) { 26007e4feadSOmar Sandoval if (blk_mq_debugfs_register_ctx(q, ctx, hctx_dir)) 26107e4feadSOmar Sandoval return -ENOMEM; 26207e4feadSOmar Sandoval } 26307e4feadSOmar Sandoval 26407e4feadSOmar Sandoval return 0; 26507e4feadSOmar Sandoval } 26607e4feadSOmar Sandoval 26707e4feadSOmar Sandoval int blk_mq_debugfs_register_hctxs(struct request_queue *q) 26807e4feadSOmar Sandoval { 26907e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx; 27007e4feadSOmar Sandoval int i; 27107e4feadSOmar Sandoval 27207e4feadSOmar Sandoval if (!q->debugfs_dir) 27307e4feadSOmar Sandoval return -ENOENT; 27407e4feadSOmar Sandoval 27507e4feadSOmar Sandoval q->mq_debugfs_dir = debugfs_create_dir("mq", q->debugfs_dir); 27607e4feadSOmar Sandoval if (!q->mq_debugfs_dir) 27707e4feadSOmar Sandoval goto err; 27807e4feadSOmar Sandoval 27907e4feadSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) { 28007e4feadSOmar Sandoval if (blk_mq_debugfs_register_hctx(q, hctx)) 28107e4feadSOmar Sandoval goto err; 28207e4feadSOmar Sandoval } 28307e4feadSOmar Sandoval 28407e4feadSOmar Sandoval return 0; 28507e4feadSOmar Sandoval 28607e4feadSOmar Sandoval err: 28707e4feadSOmar Sandoval blk_mq_debugfs_unregister_hctxs(q); 28807e4feadSOmar Sandoval return -ENOMEM; 28907e4feadSOmar Sandoval } 29007e4feadSOmar Sandoval 29107e4feadSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q) 29207e4feadSOmar Sandoval { 29307e4feadSOmar Sandoval debugfs_remove_recursive(q->mq_debugfs_dir); 29407e4feadSOmar Sandoval q->mq_debugfs_dir = NULL; 29507e4feadSOmar Sandoval } 29607e4feadSOmar Sandoval 29707e4feadSOmar Sandoval void blk_mq_debugfs_init(void) 29807e4feadSOmar Sandoval { 29907e4feadSOmar Sandoval block_debugfs_root = debugfs_create_dir("block", NULL); 30007e4feadSOmar Sandoval } 301