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" 23d96b37c0SOmar Sandoval #include "blk-mq-tag.h" 2407e4feadSOmar Sandoval 2507e4feadSOmar Sandoval struct blk_mq_debugfs_attr { 2607e4feadSOmar Sandoval const char *name; 2707e4feadSOmar Sandoval umode_t mode; 2807e4feadSOmar Sandoval const struct file_operations *fops; 2907e4feadSOmar Sandoval }; 3007e4feadSOmar Sandoval 3107e4feadSOmar Sandoval static struct dentry *block_debugfs_root; 3207e4feadSOmar Sandoval 33950cd7e9SOmar Sandoval static int blk_mq_debugfs_seq_open(struct inode *inode, struct file *file, 34950cd7e9SOmar Sandoval const struct seq_operations *ops) 35950cd7e9SOmar Sandoval { 36950cd7e9SOmar Sandoval struct seq_file *m; 37950cd7e9SOmar Sandoval int ret; 38950cd7e9SOmar Sandoval 39950cd7e9SOmar Sandoval ret = seq_open(file, ops); 40950cd7e9SOmar Sandoval if (!ret) { 41950cd7e9SOmar Sandoval m = file->private_data; 42950cd7e9SOmar Sandoval m->private = inode->i_private; 43950cd7e9SOmar Sandoval } 44950cd7e9SOmar Sandoval return ret; 45950cd7e9SOmar Sandoval } 46950cd7e9SOmar Sandoval 479abb2ad2SOmar Sandoval static int hctx_state_show(struct seq_file *m, void *v) 489abb2ad2SOmar Sandoval { 499abb2ad2SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 509abb2ad2SOmar Sandoval 519abb2ad2SOmar Sandoval seq_printf(m, "0x%lx\n", hctx->state); 529abb2ad2SOmar Sandoval return 0; 539abb2ad2SOmar Sandoval } 549abb2ad2SOmar Sandoval 559abb2ad2SOmar Sandoval static int hctx_state_open(struct inode *inode, struct file *file) 569abb2ad2SOmar Sandoval { 579abb2ad2SOmar Sandoval return single_open(file, hctx_state_show, inode->i_private); 589abb2ad2SOmar Sandoval } 599abb2ad2SOmar Sandoval 609abb2ad2SOmar Sandoval static const struct file_operations hctx_state_fops = { 619abb2ad2SOmar Sandoval .open = hctx_state_open, 629abb2ad2SOmar Sandoval .read = seq_read, 639abb2ad2SOmar Sandoval .llseek = seq_lseek, 649abb2ad2SOmar Sandoval .release = single_release, 659abb2ad2SOmar Sandoval }; 669abb2ad2SOmar Sandoval 679abb2ad2SOmar Sandoval static int hctx_flags_show(struct seq_file *m, void *v) 689abb2ad2SOmar Sandoval { 699abb2ad2SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 709abb2ad2SOmar Sandoval 719abb2ad2SOmar Sandoval seq_printf(m, "0x%lx\n", hctx->flags); 729abb2ad2SOmar Sandoval return 0; 739abb2ad2SOmar Sandoval } 749abb2ad2SOmar Sandoval 759abb2ad2SOmar Sandoval static int hctx_flags_open(struct inode *inode, struct file *file) 769abb2ad2SOmar Sandoval { 779abb2ad2SOmar Sandoval return single_open(file, hctx_flags_show, inode->i_private); 789abb2ad2SOmar Sandoval } 799abb2ad2SOmar Sandoval 809abb2ad2SOmar Sandoval static const struct file_operations hctx_flags_fops = { 819abb2ad2SOmar Sandoval .open = hctx_flags_open, 829abb2ad2SOmar Sandoval .read = seq_read, 839abb2ad2SOmar Sandoval .llseek = seq_lseek, 849abb2ad2SOmar Sandoval .release = single_release, 859abb2ad2SOmar Sandoval }; 869abb2ad2SOmar Sandoval 87950cd7e9SOmar Sandoval static int blk_mq_debugfs_rq_show(struct seq_file *m, void *v) 88950cd7e9SOmar Sandoval { 89950cd7e9SOmar Sandoval struct request *rq = list_entry_rq(v); 90950cd7e9SOmar Sandoval 917b393852SOmar Sandoval seq_printf(m, "%p {.cmd_type=%u, .cmd_flags=0x%x, .rq_flags=0x%x, .tag=%d, .internal_tag=%d}\n", 927b393852SOmar Sandoval rq, rq->cmd_type, rq->cmd_flags, (unsigned int)rq->rq_flags, 937b393852SOmar Sandoval rq->tag, rq->internal_tag); 94950cd7e9SOmar Sandoval return 0; 95950cd7e9SOmar Sandoval } 96950cd7e9SOmar Sandoval 97950cd7e9SOmar Sandoval static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos) 98950cd7e9SOmar Sandoval { 99950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 100950cd7e9SOmar Sandoval 101950cd7e9SOmar Sandoval spin_lock(&hctx->lock); 102950cd7e9SOmar Sandoval return seq_list_start(&hctx->dispatch, *pos); 103950cd7e9SOmar Sandoval } 104950cd7e9SOmar Sandoval 105950cd7e9SOmar Sandoval static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos) 106950cd7e9SOmar Sandoval { 107950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 108950cd7e9SOmar Sandoval 109950cd7e9SOmar Sandoval return seq_list_next(v, &hctx->dispatch, pos); 110950cd7e9SOmar Sandoval } 111950cd7e9SOmar Sandoval 112950cd7e9SOmar Sandoval static void hctx_dispatch_stop(struct seq_file *m, void *v) 113950cd7e9SOmar Sandoval { 114950cd7e9SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 115950cd7e9SOmar Sandoval 116950cd7e9SOmar Sandoval spin_unlock(&hctx->lock); 117950cd7e9SOmar Sandoval } 118950cd7e9SOmar Sandoval 119950cd7e9SOmar Sandoval static const struct seq_operations hctx_dispatch_seq_ops = { 120950cd7e9SOmar Sandoval .start = hctx_dispatch_start, 121950cd7e9SOmar Sandoval .next = hctx_dispatch_next, 122950cd7e9SOmar Sandoval .stop = hctx_dispatch_stop, 123950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 124950cd7e9SOmar Sandoval }; 125950cd7e9SOmar Sandoval 126950cd7e9SOmar Sandoval static int hctx_dispatch_open(struct inode *inode, struct file *file) 127950cd7e9SOmar Sandoval { 128950cd7e9SOmar Sandoval return blk_mq_debugfs_seq_open(inode, file, &hctx_dispatch_seq_ops); 129950cd7e9SOmar Sandoval } 130950cd7e9SOmar Sandoval 131950cd7e9SOmar Sandoval static const struct file_operations hctx_dispatch_fops = { 132950cd7e9SOmar Sandoval .open = hctx_dispatch_open, 133950cd7e9SOmar Sandoval .read = seq_read, 134950cd7e9SOmar Sandoval .llseek = seq_lseek, 135950cd7e9SOmar Sandoval .release = seq_release, 136950cd7e9SOmar Sandoval }; 137950cd7e9SOmar Sandoval 1380bfa5288SOmar Sandoval static int hctx_ctx_map_show(struct seq_file *m, void *v) 1390bfa5288SOmar Sandoval { 1400bfa5288SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 1410bfa5288SOmar Sandoval 1420bfa5288SOmar Sandoval sbitmap_bitmap_show(&hctx->ctx_map, m); 1430bfa5288SOmar Sandoval return 0; 1440bfa5288SOmar Sandoval } 1450bfa5288SOmar Sandoval 1460bfa5288SOmar Sandoval static int hctx_ctx_map_open(struct inode *inode, struct file *file) 1470bfa5288SOmar Sandoval { 1480bfa5288SOmar Sandoval return single_open(file, hctx_ctx_map_show, inode->i_private); 1490bfa5288SOmar Sandoval } 1500bfa5288SOmar Sandoval 1510bfa5288SOmar Sandoval static const struct file_operations hctx_ctx_map_fops = { 1520bfa5288SOmar Sandoval .open = hctx_ctx_map_open, 1530bfa5288SOmar Sandoval .read = seq_read, 1540bfa5288SOmar Sandoval .llseek = seq_lseek, 1550bfa5288SOmar Sandoval .release = single_release, 1560bfa5288SOmar Sandoval }; 1570bfa5288SOmar Sandoval 158d96b37c0SOmar Sandoval static void blk_mq_debugfs_tags_show(struct seq_file *m, 159d96b37c0SOmar Sandoval struct blk_mq_tags *tags) 160d96b37c0SOmar Sandoval { 161d96b37c0SOmar Sandoval seq_printf(m, "nr_tags=%u\n", tags->nr_tags); 162d96b37c0SOmar Sandoval seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags); 163d96b37c0SOmar Sandoval seq_printf(m, "active_queues=%d\n", 164d96b37c0SOmar Sandoval atomic_read(&tags->active_queues)); 165d96b37c0SOmar Sandoval 166d96b37c0SOmar Sandoval seq_puts(m, "\nbitmap_tags:\n"); 167d96b37c0SOmar Sandoval sbitmap_queue_show(&tags->bitmap_tags, m); 168d96b37c0SOmar Sandoval 169d96b37c0SOmar Sandoval if (tags->nr_reserved_tags) { 170d96b37c0SOmar Sandoval seq_puts(m, "\nbreserved_tags:\n"); 171d96b37c0SOmar Sandoval sbitmap_queue_show(&tags->breserved_tags, m); 172d96b37c0SOmar Sandoval } 173d96b37c0SOmar Sandoval } 174d96b37c0SOmar Sandoval 175d96b37c0SOmar Sandoval static int hctx_tags_show(struct seq_file *m, void *v) 176d96b37c0SOmar Sandoval { 177d96b37c0SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 178d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 179d96b37c0SOmar Sandoval 180d96b37c0SOmar Sandoval mutex_lock(&q->sysfs_lock); 181d96b37c0SOmar Sandoval if (hctx->tags) 182d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->tags); 183d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 184d96b37c0SOmar Sandoval 185d96b37c0SOmar Sandoval return 0; 186d96b37c0SOmar Sandoval } 187d96b37c0SOmar Sandoval 188d96b37c0SOmar Sandoval static int hctx_tags_open(struct inode *inode, struct file *file) 189d96b37c0SOmar Sandoval { 190d96b37c0SOmar Sandoval return single_open(file, hctx_tags_show, inode->i_private); 191d96b37c0SOmar Sandoval } 192d96b37c0SOmar Sandoval 193d96b37c0SOmar Sandoval static const struct file_operations hctx_tags_fops = { 194d96b37c0SOmar Sandoval .open = hctx_tags_open, 195d96b37c0SOmar Sandoval .read = seq_read, 196d96b37c0SOmar Sandoval .llseek = seq_lseek, 197d96b37c0SOmar Sandoval .release = single_release, 198d96b37c0SOmar Sandoval }; 199d96b37c0SOmar Sandoval 200d7e3621aSOmar Sandoval static int hctx_tags_bitmap_show(struct seq_file *m, void *v) 201d7e3621aSOmar Sandoval { 202d7e3621aSOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 203d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 204d7e3621aSOmar Sandoval 205d7e3621aSOmar Sandoval mutex_lock(&q->sysfs_lock); 206d7e3621aSOmar Sandoval if (hctx->tags) 207d7e3621aSOmar Sandoval sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m); 208d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 209d7e3621aSOmar Sandoval return 0; 210d7e3621aSOmar Sandoval } 211d7e3621aSOmar Sandoval 212d7e3621aSOmar Sandoval static int hctx_tags_bitmap_open(struct inode *inode, struct file *file) 213d7e3621aSOmar Sandoval { 214d7e3621aSOmar Sandoval return single_open(file, hctx_tags_bitmap_show, inode->i_private); 215d7e3621aSOmar Sandoval } 216d7e3621aSOmar Sandoval 217d7e3621aSOmar Sandoval static const struct file_operations hctx_tags_bitmap_fops = { 218d7e3621aSOmar Sandoval .open = hctx_tags_bitmap_open, 219d7e3621aSOmar Sandoval .read = seq_read, 220d7e3621aSOmar Sandoval .llseek = seq_lseek, 221d7e3621aSOmar Sandoval .release = single_release, 222d7e3621aSOmar Sandoval }; 223d7e3621aSOmar Sandoval 224d96b37c0SOmar Sandoval static int hctx_sched_tags_show(struct seq_file *m, void *v) 225d96b37c0SOmar Sandoval { 226d96b37c0SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 227d96b37c0SOmar Sandoval struct request_queue *q = hctx->queue; 228d96b37c0SOmar Sandoval 229d96b37c0SOmar Sandoval mutex_lock(&q->sysfs_lock); 230d96b37c0SOmar Sandoval if (hctx->sched_tags) 231d96b37c0SOmar Sandoval blk_mq_debugfs_tags_show(m, hctx->sched_tags); 232d96b37c0SOmar Sandoval mutex_unlock(&q->sysfs_lock); 233d96b37c0SOmar Sandoval 234d96b37c0SOmar Sandoval return 0; 235d96b37c0SOmar Sandoval } 236d96b37c0SOmar Sandoval 237d96b37c0SOmar Sandoval static int hctx_sched_tags_open(struct inode *inode, struct file *file) 238d96b37c0SOmar Sandoval { 239d96b37c0SOmar Sandoval return single_open(file, hctx_sched_tags_show, inode->i_private); 240d96b37c0SOmar Sandoval } 241d96b37c0SOmar Sandoval 242d96b37c0SOmar Sandoval static const struct file_operations hctx_sched_tags_fops = { 243d96b37c0SOmar Sandoval .open = hctx_sched_tags_open, 244d96b37c0SOmar Sandoval .read = seq_read, 245d96b37c0SOmar Sandoval .llseek = seq_lseek, 246d96b37c0SOmar Sandoval .release = single_release, 247d96b37c0SOmar Sandoval }; 248d96b37c0SOmar Sandoval 249d7e3621aSOmar Sandoval static int hctx_sched_tags_bitmap_show(struct seq_file *m, void *v) 250d7e3621aSOmar Sandoval { 251d7e3621aSOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 252d7e3621aSOmar Sandoval struct request_queue *q = hctx->queue; 253d7e3621aSOmar Sandoval 254d7e3621aSOmar Sandoval mutex_lock(&q->sysfs_lock); 255d7e3621aSOmar Sandoval if (hctx->sched_tags) 256d7e3621aSOmar Sandoval sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m); 257d7e3621aSOmar Sandoval mutex_unlock(&q->sysfs_lock); 258d7e3621aSOmar Sandoval return 0; 259d7e3621aSOmar Sandoval } 260d7e3621aSOmar Sandoval 261d7e3621aSOmar Sandoval static int hctx_sched_tags_bitmap_open(struct inode *inode, struct file *file) 262d7e3621aSOmar Sandoval { 263d7e3621aSOmar Sandoval return single_open(file, hctx_sched_tags_bitmap_show, inode->i_private); 264d7e3621aSOmar Sandoval } 265d7e3621aSOmar Sandoval 266d7e3621aSOmar Sandoval static const struct file_operations hctx_sched_tags_bitmap_fops = { 267d7e3621aSOmar Sandoval .open = hctx_sched_tags_bitmap_open, 268d7e3621aSOmar Sandoval .read = seq_read, 269d7e3621aSOmar Sandoval .llseek = seq_lseek, 270d7e3621aSOmar Sandoval .release = single_release, 271d7e3621aSOmar Sandoval }; 272d7e3621aSOmar Sandoval 273*be215473SOmar Sandoval static int hctx_io_poll_show(struct seq_file *m, void *v) 274*be215473SOmar Sandoval { 275*be215473SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 276*be215473SOmar Sandoval 277*be215473SOmar Sandoval seq_printf(m, "considered=%lu\n", hctx->poll_considered); 278*be215473SOmar Sandoval seq_printf(m, "invoked=%lu\n", hctx->poll_invoked); 279*be215473SOmar Sandoval seq_printf(m, "success=%lu\n", hctx->poll_success); 280*be215473SOmar Sandoval return 0; 281*be215473SOmar Sandoval } 282*be215473SOmar Sandoval 283*be215473SOmar Sandoval static int hctx_io_poll_open(struct inode *inode, struct file *file) 284*be215473SOmar Sandoval { 285*be215473SOmar Sandoval return single_open(file, hctx_io_poll_show, inode->i_private); 286*be215473SOmar Sandoval } 287*be215473SOmar Sandoval 288*be215473SOmar Sandoval static ssize_t hctx_io_poll_write(struct file *file, const char __user *buf, 289*be215473SOmar Sandoval size_t count, loff_t *ppos) 290*be215473SOmar Sandoval { 291*be215473SOmar Sandoval struct seq_file *m = file->private_data; 292*be215473SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 293*be215473SOmar Sandoval 294*be215473SOmar Sandoval hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0; 295*be215473SOmar Sandoval return count; 296*be215473SOmar Sandoval } 297*be215473SOmar Sandoval 298*be215473SOmar Sandoval static const struct file_operations hctx_io_poll_fops = { 299*be215473SOmar Sandoval .open = hctx_io_poll_open, 300*be215473SOmar Sandoval .read = seq_read, 301*be215473SOmar Sandoval .write = hctx_io_poll_write, 302*be215473SOmar Sandoval .llseek = seq_lseek, 303*be215473SOmar Sandoval .release = single_release, 304*be215473SOmar Sandoval }; 305*be215473SOmar Sandoval 306*be215473SOmar Sandoval static void print_stat(struct seq_file *m, struct blk_rq_stat *stat) 307*be215473SOmar Sandoval { 308*be215473SOmar Sandoval seq_printf(m, "samples=%d, mean=%lld, min=%llu, max=%llu", 309*be215473SOmar Sandoval stat->nr_samples, stat->mean, stat->min, stat->max); 310*be215473SOmar Sandoval } 311*be215473SOmar Sandoval 312*be215473SOmar Sandoval static int hctx_stats_show(struct seq_file *m, void *v) 313*be215473SOmar Sandoval { 314*be215473SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 315*be215473SOmar Sandoval struct blk_rq_stat stat[2]; 316*be215473SOmar Sandoval 317*be215473SOmar Sandoval blk_stat_init(&stat[BLK_STAT_READ]); 318*be215473SOmar Sandoval blk_stat_init(&stat[BLK_STAT_WRITE]); 319*be215473SOmar Sandoval 320*be215473SOmar Sandoval blk_hctx_stat_get(hctx, stat); 321*be215473SOmar Sandoval 322*be215473SOmar Sandoval seq_puts(m, "read: "); 323*be215473SOmar Sandoval print_stat(m, &stat[BLK_STAT_READ]); 324*be215473SOmar Sandoval seq_puts(m, "\n"); 325*be215473SOmar Sandoval 326*be215473SOmar Sandoval seq_puts(m, "write: "); 327*be215473SOmar Sandoval print_stat(m, &stat[BLK_STAT_WRITE]); 328*be215473SOmar Sandoval seq_puts(m, "\n"); 329*be215473SOmar Sandoval return 0; 330*be215473SOmar Sandoval } 331*be215473SOmar Sandoval 332*be215473SOmar Sandoval static int hctx_stats_open(struct inode *inode, struct file *file) 333*be215473SOmar Sandoval { 334*be215473SOmar Sandoval return single_open(file, hctx_stats_show, inode->i_private); 335*be215473SOmar Sandoval } 336*be215473SOmar Sandoval 337*be215473SOmar Sandoval static ssize_t hctx_stats_write(struct file *file, const char __user *buf, 338*be215473SOmar Sandoval size_t count, loff_t *ppos) 339*be215473SOmar Sandoval { 340*be215473SOmar Sandoval struct seq_file *m = file->private_data; 341*be215473SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 342*be215473SOmar Sandoval struct blk_mq_ctx *ctx; 343*be215473SOmar Sandoval int i; 344*be215473SOmar Sandoval 345*be215473SOmar Sandoval hctx_for_each_ctx(hctx, ctx, i) { 346*be215473SOmar Sandoval blk_stat_init(&ctx->stat[BLK_STAT_READ]); 347*be215473SOmar Sandoval blk_stat_init(&ctx->stat[BLK_STAT_WRITE]); 348*be215473SOmar Sandoval } 349*be215473SOmar Sandoval return count; 350*be215473SOmar Sandoval } 351*be215473SOmar Sandoval 352*be215473SOmar Sandoval static const struct file_operations hctx_stats_fops = { 353*be215473SOmar Sandoval .open = hctx_stats_open, 354*be215473SOmar Sandoval .read = seq_read, 355*be215473SOmar Sandoval .write = hctx_stats_write, 356*be215473SOmar Sandoval .llseek = seq_lseek, 357*be215473SOmar Sandoval .release = single_release, 358*be215473SOmar Sandoval }; 359*be215473SOmar Sandoval 360*be215473SOmar Sandoval static int hctx_dispatched_show(struct seq_file *m, void *v) 361*be215473SOmar Sandoval { 362*be215473SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 363*be215473SOmar Sandoval int i; 364*be215473SOmar Sandoval 365*be215473SOmar Sandoval seq_printf(m, "%8u\t%lu\n", 0U, hctx->dispatched[0]); 366*be215473SOmar Sandoval 367*be215473SOmar Sandoval for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) { 368*be215473SOmar Sandoval unsigned int d = 1U << (i - 1); 369*be215473SOmar Sandoval 370*be215473SOmar Sandoval seq_printf(m, "%8u\t%lu\n", d, hctx->dispatched[i]); 371*be215473SOmar Sandoval } 372*be215473SOmar Sandoval 373*be215473SOmar Sandoval seq_printf(m, "%8u+\t%lu\n", 1U << (i - 1), hctx->dispatched[i]); 374*be215473SOmar Sandoval return 0; 375*be215473SOmar Sandoval } 376*be215473SOmar Sandoval 377*be215473SOmar Sandoval static int hctx_dispatched_open(struct inode *inode, struct file *file) 378*be215473SOmar Sandoval { 379*be215473SOmar Sandoval return single_open(file, hctx_dispatched_show, inode->i_private); 380*be215473SOmar Sandoval } 381*be215473SOmar Sandoval 382*be215473SOmar Sandoval static ssize_t hctx_dispatched_write(struct file *file, const char __user *buf, 383*be215473SOmar Sandoval size_t count, loff_t *ppos) 384*be215473SOmar Sandoval { 385*be215473SOmar Sandoval struct seq_file *m = file->private_data; 386*be215473SOmar Sandoval struct blk_mq_hw_ctx *hctx = m->private; 387*be215473SOmar Sandoval int i; 388*be215473SOmar Sandoval 389*be215473SOmar Sandoval for (i = 0; i < BLK_MQ_MAX_DISPATCH_ORDER; i++) 390*be215473SOmar Sandoval hctx->dispatched[i] = 0; 391*be215473SOmar Sandoval return count; 392*be215473SOmar Sandoval } 393*be215473SOmar Sandoval 394*be215473SOmar Sandoval static const struct file_operations hctx_dispatched_fops = { 395*be215473SOmar Sandoval .open = hctx_dispatched_open, 396*be215473SOmar Sandoval .read = seq_read, 397*be215473SOmar Sandoval .write = hctx_dispatched_write, 398*be215473SOmar Sandoval .llseek = seq_lseek, 399*be215473SOmar Sandoval .release = single_release, 400*be215473SOmar Sandoval }; 401*be215473SOmar Sandoval 402950cd7e9SOmar Sandoval static void *ctx_rq_list_start(struct seq_file *m, loff_t *pos) 403950cd7e9SOmar Sandoval { 404950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 405950cd7e9SOmar Sandoval 406950cd7e9SOmar Sandoval spin_lock(&ctx->lock); 407950cd7e9SOmar Sandoval return seq_list_start(&ctx->rq_list, *pos); 408950cd7e9SOmar Sandoval } 409950cd7e9SOmar Sandoval 410950cd7e9SOmar Sandoval static void *ctx_rq_list_next(struct seq_file *m, void *v, loff_t *pos) 411950cd7e9SOmar Sandoval { 412950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 413950cd7e9SOmar Sandoval 414950cd7e9SOmar Sandoval return seq_list_next(v, &ctx->rq_list, pos); 415950cd7e9SOmar Sandoval } 416950cd7e9SOmar Sandoval 417950cd7e9SOmar Sandoval static void ctx_rq_list_stop(struct seq_file *m, void *v) 418950cd7e9SOmar Sandoval { 419950cd7e9SOmar Sandoval struct blk_mq_ctx *ctx = m->private; 420950cd7e9SOmar Sandoval 421950cd7e9SOmar Sandoval spin_unlock(&ctx->lock); 422950cd7e9SOmar Sandoval } 423950cd7e9SOmar Sandoval 424950cd7e9SOmar Sandoval static const struct seq_operations ctx_rq_list_seq_ops = { 425950cd7e9SOmar Sandoval .start = ctx_rq_list_start, 426950cd7e9SOmar Sandoval .next = ctx_rq_list_next, 427950cd7e9SOmar Sandoval .stop = ctx_rq_list_stop, 428950cd7e9SOmar Sandoval .show = blk_mq_debugfs_rq_show, 429950cd7e9SOmar Sandoval }; 430950cd7e9SOmar Sandoval 431950cd7e9SOmar Sandoval static int ctx_rq_list_open(struct inode *inode, struct file *file) 432950cd7e9SOmar Sandoval { 433950cd7e9SOmar Sandoval return blk_mq_debugfs_seq_open(inode, file, &ctx_rq_list_seq_ops); 434950cd7e9SOmar Sandoval } 435950cd7e9SOmar Sandoval 436950cd7e9SOmar Sandoval static const struct file_operations ctx_rq_list_fops = { 437950cd7e9SOmar Sandoval .open = ctx_rq_list_open, 438950cd7e9SOmar Sandoval .read = seq_read, 439950cd7e9SOmar Sandoval .llseek = seq_lseek, 440950cd7e9SOmar Sandoval .release = seq_release, 441950cd7e9SOmar Sandoval }; 442950cd7e9SOmar Sandoval 44307e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { 4449abb2ad2SOmar Sandoval {"state", 0400, &hctx_state_fops}, 4459abb2ad2SOmar Sandoval {"flags", 0400, &hctx_flags_fops}, 446950cd7e9SOmar Sandoval {"dispatch", 0400, &hctx_dispatch_fops}, 4470bfa5288SOmar Sandoval {"ctx_map", 0400, &hctx_ctx_map_fops}, 448d96b37c0SOmar Sandoval {"tags", 0400, &hctx_tags_fops}, 449d7e3621aSOmar Sandoval {"tags_bitmap", 0400, &hctx_tags_bitmap_fops}, 450d96b37c0SOmar Sandoval {"sched_tags", 0400, &hctx_sched_tags_fops}, 451d7e3621aSOmar Sandoval {"sched_tags_bitmap", 0400, &hctx_sched_tags_bitmap_fops}, 452*be215473SOmar Sandoval {"io_poll", 0600, &hctx_io_poll_fops}, 453*be215473SOmar Sandoval {"stats", 0600, &hctx_stats_fops}, 454*be215473SOmar Sandoval {"dispatched", 0600, &hctx_dispatched_fops}, 45507e4feadSOmar Sandoval }; 45607e4feadSOmar Sandoval 45707e4feadSOmar Sandoval static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = { 458950cd7e9SOmar Sandoval {"rq_list", 0400, &ctx_rq_list_fops}, 45907e4feadSOmar Sandoval }; 46007e4feadSOmar Sandoval 46107e4feadSOmar Sandoval int blk_mq_debugfs_register(struct request_queue *q, const char *name) 46207e4feadSOmar Sandoval { 46307e4feadSOmar Sandoval if (!block_debugfs_root) 46407e4feadSOmar Sandoval return -ENOENT; 46507e4feadSOmar Sandoval 46607e4feadSOmar Sandoval q->debugfs_dir = debugfs_create_dir(name, block_debugfs_root); 46707e4feadSOmar Sandoval if (!q->debugfs_dir) 46807e4feadSOmar Sandoval goto err; 46907e4feadSOmar Sandoval 47007e4feadSOmar Sandoval if (blk_mq_debugfs_register_hctxs(q)) 47107e4feadSOmar Sandoval goto err; 47207e4feadSOmar Sandoval 47307e4feadSOmar Sandoval return 0; 47407e4feadSOmar Sandoval 47507e4feadSOmar Sandoval err: 47607e4feadSOmar Sandoval blk_mq_debugfs_unregister(q); 47707e4feadSOmar Sandoval return -ENOMEM; 47807e4feadSOmar Sandoval } 47907e4feadSOmar Sandoval 48007e4feadSOmar Sandoval void blk_mq_debugfs_unregister(struct request_queue *q) 48107e4feadSOmar Sandoval { 48207e4feadSOmar Sandoval debugfs_remove_recursive(q->debugfs_dir); 48307e4feadSOmar Sandoval q->mq_debugfs_dir = NULL; 48407e4feadSOmar Sandoval q->debugfs_dir = NULL; 48507e4feadSOmar Sandoval } 48607e4feadSOmar Sandoval 48707e4feadSOmar Sandoval static int blk_mq_debugfs_register_ctx(struct request_queue *q, 48807e4feadSOmar Sandoval struct blk_mq_ctx *ctx, 48907e4feadSOmar Sandoval struct dentry *hctx_dir) 49007e4feadSOmar Sandoval { 49107e4feadSOmar Sandoval struct dentry *ctx_dir; 49207e4feadSOmar Sandoval char name[20]; 49307e4feadSOmar Sandoval int i; 49407e4feadSOmar Sandoval 49507e4feadSOmar Sandoval snprintf(name, sizeof(name), "cpu%u", ctx->cpu); 49607e4feadSOmar Sandoval ctx_dir = debugfs_create_dir(name, hctx_dir); 49707e4feadSOmar Sandoval if (!ctx_dir) 49807e4feadSOmar Sandoval return -ENOMEM; 49907e4feadSOmar Sandoval 50007e4feadSOmar Sandoval for (i = 0; i < ARRAY_SIZE(blk_mq_debugfs_ctx_attrs); i++) { 50107e4feadSOmar Sandoval const struct blk_mq_debugfs_attr *attr; 50207e4feadSOmar Sandoval 50307e4feadSOmar Sandoval attr = &blk_mq_debugfs_ctx_attrs[i]; 50407e4feadSOmar Sandoval if (!debugfs_create_file(attr->name, attr->mode, ctx_dir, ctx, 50507e4feadSOmar Sandoval attr->fops)) 50607e4feadSOmar Sandoval return -ENOMEM; 50707e4feadSOmar Sandoval } 50807e4feadSOmar Sandoval 50907e4feadSOmar Sandoval return 0; 51007e4feadSOmar Sandoval } 51107e4feadSOmar Sandoval 51207e4feadSOmar Sandoval static int blk_mq_debugfs_register_hctx(struct request_queue *q, 51307e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx) 51407e4feadSOmar Sandoval { 51507e4feadSOmar Sandoval struct blk_mq_ctx *ctx; 51607e4feadSOmar Sandoval struct dentry *hctx_dir; 51707e4feadSOmar Sandoval char name[20]; 51807e4feadSOmar Sandoval int i; 51907e4feadSOmar Sandoval 52007e4feadSOmar Sandoval snprintf(name, sizeof(name), "%u", hctx->queue_num); 52107e4feadSOmar Sandoval hctx_dir = debugfs_create_dir(name, q->mq_debugfs_dir); 52207e4feadSOmar Sandoval if (!hctx_dir) 52307e4feadSOmar Sandoval return -ENOMEM; 52407e4feadSOmar Sandoval 52507e4feadSOmar Sandoval for (i = 0; i < ARRAY_SIZE(blk_mq_debugfs_hctx_attrs); i++) { 52607e4feadSOmar Sandoval const struct blk_mq_debugfs_attr *attr; 52707e4feadSOmar Sandoval 52807e4feadSOmar Sandoval attr = &blk_mq_debugfs_hctx_attrs[i]; 52907e4feadSOmar Sandoval if (!debugfs_create_file(attr->name, attr->mode, hctx_dir, hctx, 53007e4feadSOmar Sandoval attr->fops)) 53107e4feadSOmar Sandoval return -ENOMEM; 53207e4feadSOmar Sandoval } 53307e4feadSOmar Sandoval 53407e4feadSOmar Sandoval hctx_for_each_ctx(hctx, ctx, i) { 53507e4feadSOmar Sandoval if (blk_mq_debugfs_register_ctx(q, ctx, hctx_dir)) 53607e4feadSOmar Sandoval return -ENOMEM; 53707e4feadSOmar Sandoval } 53807e4feadSOmar Sandoval 53907e4feadSOmar Sandoval return 0; 54007e4feadSOmar Sandoval } 54107e4feadSOmar Sandoval 54207e4feadSOmar Sandoval int blk_mq_debugfs_register_hctxs(struct request_queue *q) 54307e4feadSOmar Sandoval { 54407e4feadSOmar Sandoval struct blk_mq_hw_ctx *hctx; 54507e4feadSOmar Sandoval int i; 54607e4feadSOmar Sandoval 54707e4feadSOmar Sandoval if (!q->debugfs_dir) 54807e4feadSOmar Sandoval return -ENOENT; 54907e4feadSOmar Sandoval 55007e4feadSOmar Sandoval q->mq_debugfs_dir = debugfs_create_dir("mq", q->debugfs_dir); 55107e4feadSOmar Sandoval if (!q->mq_debugfs_dir) 55207e4feadSOmar Sandoval goto err; 55307e4feadSOmar Sandoval 55407e4feadSOmar Sandoval queue_for_each_hw_ctx(q, hctx, i) { 55507e4feadSOmar Sandoval if (blk_mq_debugfs_register_hctx(q, hctx)) 55607e4feadSOmar Sandoval goto err; 55707e4feadSOmar Sandoval } 55807e4feadSOmar Sandoval 55907e4feadSOmar Sandoval return 0; 56007e4feadSOmar Sandoval 56107e4feadSOmar Sandoval err: 56207e4feadSOmar Sandoval blk_mq_debugfs_unregister_hctxs(q); 56307e4feadSOmar Sandoval return -ENOMEM; 56407e4feadSOmar Sandoval } 56507e4feadSOmar Sandoval 56607e4feadSOmar Sandoval void blk_mq_debugfs_unregister_hctxs(struct request_queue *q) 56707e4feadSOmar Sandoval { 56807e4feadSOmar Sandoval debugfs_remove_recursive(q->mq_debugfs_dir); 56907e4feadSOmar Sandoval q->mq_debugfs_dir = NULL; 57007e4feadSOmar Sandoval } 57107e4feadSOmar Sandoval 57207e4feadSOmar Sandoval void blk_mq_debugfs_init(void) 57307e4feadSOmar Sandoval { 57407e4feadSOmar Sandoval block_debugfs_root = debugfs_create_dir("block", NULL); 57507e4feadSOmar Sandoval } 576