mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	blk-mq: create debugfs directory tree
In preparation for putting blk-mq debugging information in debugfs,
create a directory tree mirroring the one in sysfs:
    # tree -d /sys/kernel/debug/block
    /sys/kernel/debug/block
    |-- nvme0n1
    |   `-- mq
    |       |-- 0
    |       |   `-- cpu0
    |       |-- 1
    |       |   `-- cpu1
    |       |-- 2
    |       |   `-- cpu2
    |       `-- 3
    |           `-- cpu3
    `-- vda
        `-- mq
            `-- 0
                |-- cpu0
                |-- cpu1
                |-- cpu2
                `-- cpu3
Also add the scaffolding for the actual files that will go in here,
either under the hardware queue or software queue directories.
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
			
			
This commit is contained in:
		
							parent
							
								
									b48fda0976
								
							
						
					
					
						commit
						07e4fead45
					
				
					 6 changed files with 201 additions and 0 deletions
				
			
		|  | @ -26,3 +26,4 @@ obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o | |||
| obj-$(CONFIG_BLK_MQ_PCI)	+= blk-mq-pci.o | ||||
| obj-$(CONFIG_BLK_DEV_ZONED)	+= blk-zoned.o | ||||
| obj-$(CONFIG_BLK_WBT)		+= blk-wbt.o | ||||
| obj-$(CONFIG_DEBUG_FS)		+= blk-mq-debugfs.o | ||||
|  |  | |||
							
								
								
									
										152
									
								
								block/blk-mq-debugfs.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								block/blk-mq-debugfs.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,152 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2017 Facebook | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public | ||||
|  * License v2 as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/blkdev.h> | ||||
| #include <linux/debugfs.h> | ||||
| 
 | ||||
| #include <linux/blk-mq.h> | ||||
| #include "blk-mq.h" | ||||
| 
 | ||||
| struct blk_mq_debugfs_attr { | ||||
| 	const char *name; | ||||
| 	umode_t mode; | ||||
| 	const struct file_operations *fops; | ||||
| }; | ||||
| 
 | ||||
| static struct dentry *block_debugfs_root; | ||||
| 
 | ||||
| static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { | ||||
| }; | ||||
| 
 | ||||
| static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = { | ||||
| }; | ||||
| 
 | ||||
| int blk_mq_debugfs_register(struct request_queue *q, const char *name) | ||||
| { | ||||
| 	if (!block_debugfs_root) | ||||
| 		return -ENOENT; | ||||
| 
 | ||||
| 	q->debugfs_dir = debugfs_create_dir(name, block_debugfs_root); | ||||
| 	if (!q->debugfs_dir) | ||||
| 		goto err; | ||||
| 
 | ||||
| 	if (blk_mq_debugfs_register_hctxs(q)) | ||||
| 		goto err; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| 	blk_mq_debugfs_unregister(q); | ||||
| 	return -ENOMEM; | ||||
| } | ||||
| 
 | ||||
| void blk_mq_debugfs_unregister(struct request_queue *q) | ||||
| { | ||||
| 	debugfs_remove_recursive(q->debugfs_dir); | ||||
| 	q->mq_debugfs_dir = NULL; | ||||
| 	q->debugfs_dir = NULL; | ||||
| } | ||||
| 
 | ||||
| static int blk_mq_debugfs_register_ctx(struct request_queue *q, | ||||
| 				       struct blk_mq_ctx *ctx, | ||||
| 				       struct dentry *hctx_dir) | ||||
| { | ||||
| 	struct dentry *ctx_dir; | ||||
| 	char name[20]; | ||||
| 	int i; | ||||
| 
 | ||||
| 	snprintf(name, sizeof(name), "cpu%u", ctx->cpu); | ||||
| 	ctx_dir = debugfs_create_dir(name, hctx_dir); | ||||
| 	if (!ctx_dir) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(blk_mq_debugfs_ctx_attrs); i++) { | ||||
| 		const struct blk_mq_debugfs_attr *attr; | ||||
| 
 | ||||
| 		attr = &blk_mq_debugfs_ctx_attrs[i]; | ||||
| 		if (!debugfs_create_file(attr->name, attr->mode, ctx_dir, ctx, | ||||
| 					 attr->fops)) | ||||
| 			return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int blk_mq_debugfs_register_hctx(struct request_queue *q, | ||||
| 					struct blk_mq_hw_ctx *hctx) | ||||
| { | ||||
| 	struct blk_mq_ctx *ctx; | ||||
| 	struct dentry *hctx_dir; | ||||
| 	char name[20]; | ||||
| 	int i; | ||||
| 
 | ||||
| 	snprintf(name, sizeof(name), "%u", hctx->queue_num); | ||||
| 	hctx_dir = debugfs_create_dir(name, q->mq_debugfs_dir); | ||||
| 	if (!hctx_dir) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(blk_mq_debugfs_hctx_attrs); i++) { | ||||
| 		const struct blk_mq_debugfs_attr *attr; | ||||
| 
 | ||||
| 		attr = &blk_mq_debugfs_hctx_attrs[i]; | ||||
| 		if (!debugfs_create_file(attr->name, attr->mode, hctx_dir, hctx, | ||||
| 					 attr->fops)) | ||||
| 			return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	hctx_for_each_ctx(hctx, ctx, i) { | ||||
| 		if (blk_mq_debugfs_register_ctx(q, ctx, hctx_dir)) | ||||
| 			return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int blk_mq_debugfs_register_hctxs(struct request_queue *q) | ||||
| { | ||||
| 	struct blk_mq_hw_ctx *hctx; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (!q->debugfs_dir) | ||||
| 		return -ENOENT; | ||||
| 
 | ||||
| 	q->mq_debugfs_dir = debugfs_create_dir("mq", q->debugfs_dir); | ||||
| 	if (!q->mq_debugfs_dir) | ||||
| 		goto err; | ||||
| 
 | ||||
| 	queue_for_each_hw_ctx(q, hctx, i) { | ||||
| 		if (blk_mq_debugfs_register_hctx(q, hctx)) | ||||
| 			goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| 	blk_mq_debugfs_unregister_hctxs(q); | ||||
| 	return -ENOMEM; | ||||
| } | ||||
| 
 | ||||
| void blk_mq_debugfs_unregister_hctxs(struct request_queue *q) | ||||
| { | ||||
| 	debugfs_remove_recursive(q->mq_debugfs_dir); | ||||
| 	q->mq_debugfs_dir = NULL; | ||||
| } | ||||
| 
 | ||||
| void blk_mq_debugfs_init(void) | ||||
| { | ||||
| 	block_debugfs_root = debugfs_create_dir("block", NULL); | ||||
| } | ||||
|  | @ -468,6 +468,8 @@ static void __blk_mq_unregister_dev(struct device *dev, struct request_queue *q) | |||
| 		kobject_put(&hctx->kobj); | ||||
| 	} | ||||
| 
 | ||||
| 	blk_mq_debugfs_unregister(q); | ||||
| 
 | ||||
| 	kobject_uevent(&q->mq_kobj, KOBJ_REMOVE); | ||||
| 	kobject_del(&q->mq_kobj); | ||||
| 	kobject_put(&q->mq_kobj); | ||||
|  | @ -517,6 +519,8 @@ int blk_mq_register_dev(struct device *dev, struct request_queue *q) | |||
| 
 | ||||
| 	kobject_uevent(&q->mq_kobj, KOBJ_ADD); | ||||
| 
 | ||||
| 	blk_mq_debugfs_register(q, kobject_name(&dev->kobj)); | ||||
| 
 | ||||
| 	queue_for_each_hw_ctx(q, hctx, i) { | ||||
| 		ret = blk_mq_register_hctx(hctx); | ||||
| 		if (ret) | ||||
|  | @ -542,6 +546,8 @@ void blk_mq_sysfs_unregister(struct request_queue *q) | |||
| 	if (!q->mq_sysfs_init_done) | ||||
| 		return; | ||||
| 
 | ||||
| 	blk_mq_debugfs_unregister_hctxs(q); | ||||
| 
 | ||||
| 	queue_for_each_hw_ctx(q, hctx, i) | ||||
| 		blk_mq_unregister_hctx(hctx); | ||||
| } | ||||
|  | @ -554,6 +560,8 @@ int blk_mq_sysfs_register(struct request_queue *q) | |||
| 	if (!q->mq_sysfs_init_done) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	blk_mq_debugfs_register_hctxs(q); | ||||
| 
 | ||||
| 	queue_for_each_hw_ctx(q, hctx, i) { | ||||
| 		ret = blk_mq_register_hctx(hctx); | ||||
| 		if (ret) | ||||
|  |  | |||
|  | @ -2799,6 +2799,8 @@ void blk_mq_enable_hotplug(void) | |||
| 
 | ||||
| static int __init blk_mq_init(void) | ||||
| { | ||||
| 	blk_mq_debugfs_init(); | ||||
| 
 | ||||
| 	cpuhp_setup_state_multi(CPUHP_BLK_MQ_DEAD, "block/mq:dead", NULL, | ||||
| 				blk_mq_hctx_notify_dead); | ||||
| 
 | ||||
|  |  | |||
|  | @ -78,6 +78,39 @@ extern int blk_mq_sysfs_register(struct request_queue *q); | |||
| extern void blk_mq_sysfs_unregister(struct request_queue *q); | ||||
| extern void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx); | ||||
| 
 | ||||
| /*
 | ||||
|  * debugfs helpers | ||||
|  */ | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| void blk_mq_debugfs_init(void); | ||||
| int blk_mq_debugfs_register(struct request_queue *q, const char *name); | ||||
| void blk_mq_debugfs_unregister(struct request_queue *q); | ||||
| int blk_mq_debugfs_register_hctxs(struct request_queue *q); | ||||
| void blk_mq_debugfs_unregister_hctxs(struct request_queue *q); | ||||
| #else | ||||
| static inline void blk_mq_debugfs_init(void) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| int blk_mq_debugfs_register(struct request_queue *q, const char *name); | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void blk_mq_debugfs_unregister(struct request_queue *q) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| int blk_mq_debugfs_register_hctxs(struct request_queue *q) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void blk_mq_debugfs_unregister_hctxs(struct request_queue *q) | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| extern void blk_mq_rq_timed_out(struct request *req, bool reserved); | ||||
| 
 | ||||
| void blk_mq_release(struct request_queue *q); | ||||
|  |  | |||
|  | @ -571,6 +571,11 @@ struct request_queue { | |||
| 	struct list_head	tag_set_list; | ||||
| 	struct bio_set		*bio_split; | ||||
| 
 | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| 	struct dentry		*debugfs_dir; | ||||
| 	struct dentry		*mq_debugfs_dir; | ||||
| #endif | ||||
| 
 | ||||
| 	bool			mq_sysfs_init_done; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Omar Sandoval
						Omar Sandoval