Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nvmet: add debugfs support

Add a debugfs hierarchy to display the configured subsystems
and the controllers attached to the subsystems.

Suggested-by: Redouane BOUFENGHOUR <redouane.boufenghour@shadow.tech>
Signed-off-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Signed-off-by: Daniel Wagner <dwagner@suse.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>

authored by

Hannes Reinecke and committed by
Keith Busch
649fd414 d1237b32

+262 -3
+9
drivers/nvme/target/Kconfig
··· 17 17 To configure the NVMe target you probably want to use the nvmetcli 18 18 tool from http://git.infradead.org/users/hch/nvmetcli.git. 19 19 20 + config NVME_TARGET_DEBUGFS 21 + bool "NVMe Target debugfs support" 22 + depends on NVME_TARGET 23 + help 24 + This enables debugfs support to display the connected controllers 25 + to each subsystem 26 + 27 + If unsure, say N. 28 + 20 29 config NVME_TARGET_PASSTHRU 21 30 bool "NVMe Target Passthrough support" 22 31 depends on NVME_TARGET
+1
drivers/nvme/target/Makefile
··· 11 11 12 12 nvmet-y += core.o configfs.o admin-cmd.o fabrics-cmd.o \ 13 13 discovery.o io-cmd-file.o io-cmd-bdev.o 14 + nvmet-$(CONFIG_NVME_TARGET_DEBUGFS) += debugfs.o 14 15 nvmet-$(CONFIG_NVME_TARGET_PASSTHRU) += passthru.o 15 16 nvmet-$(CONFIG_BLK_DEV_ZONED) += zns.o 16 17 nvmet-$(CONFIG_NVME_TARGET_AUTH) += fabrics-cmd-auth.o auth.o
+21 -1
drivers/nvme/target/core.c
··· 16 16 #include "trace.h" 17 17 18 18 #include "nvmet.h" 19 + #include "debugfs.h" 19 20 20 21 struct kmem_cache *nvmet_bvec_cache; 21 22 struct workqueue_struct *buffered_io_wq; ··· 1479 1478 mutex_lock(&subsys->lock); 1480 1479 list_add_tail(&ctrl->subsys_entry, &subsys->ctrls); 1481 1480 nvmet_setup_p2p_ns_map(ctrl, req); 1481 + nvmet_debugfs_ctrl_setup(ctrl); 1482 1482 mutex_unlock(&subsys->lock); 1483 1483 1484 1484 *ctrlp = ctrl; ··· 1513 1511 cancel_work_sync(&ctrl->fatal_err_work); 1514 1512 1515 1513 nvmet_destroy_auth(ctrl); 1514 + 1515 + nvmet_debugfs_ctrl_free(ctrl); 1516 1516 1517 1517 ida_free(&cntlid_ida, ctrl->cntlid); 1518 1518 ··· 1636 1632 INIT_LIST_HEAD(&subsys->ctrls); 1637 1633 INIT_LIST_HEAD(&subsys->hosts); 1638 1634 1635 + ret = nvmet_debugfs_subsys_setup(subsys); 1636 + if (ret) 1637 + goto free_subsysnqn; 1638 + 1639 1639 return subsys; 1640 1640 1641 + free_subsysnqn: 1642 + kfree(subsys->subsysnqn); 1641 1643 free_fr: 1642 1644 kfree(subsys->firmware_rev); 1643 1645 free_mn: ··· 1659 1649 container_of(ref, struct nvmet_subsys, ref); 1660 1650 1661 1651 WARN_ON_ONCE(!xa_empty(&subsys->namespaces)); 1652 + 1653 + nvmet_debugfs_subsys_free(subsys); 1662 1654 1663 1655 xa_destroy(&subsys->namespaces); 1664 1656 nvmet_passthru_subsys_free(subsys); ··· 1716 1704 if (error) 1717 1705 goto out_free_nvmet_work_queue; 1718 1706 1719 - error = nvmet_init_configfs(); 1707 + error = nvmet_init_debugfs(); 1720 1708 if (error) 1721 1709 goto out_exit_discovery; 1710 + 1711 + error = nvmet_init_configfs(); 1712 + if (error) 1713 + goto out_exit_debugfs; 1714 + 1722 1715 return 0; 1723 1716 1717 + out_exit_debugfs: 1718 + nvmet_exit_debugfs(); 1724 1719 out_exit_discovery: 1725 1720 nvmet_exit_discovery(); 1726 1721 out_free_nvmet_work_queue: ··· 1744 1725 static void __exit nvmet_exit(void) 1745 1726 { 1746 1727 nvmet_exit_configfs(); 1728 + nvmet_exit_debugfs(); 1747 1729 nvmet_exit_discovery(); 1748 1730 ida_destroy(&cntlid_ida); 1749 1731 destroy_workqueue(nvmet_wq);
+183
drivers/nvme/target/debugfs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * DebugFS interface for the NVMe target. 4 + * Copyright (c) 2022-2024 Shadow 5 + * Copyright (c) 2024 SUSE LLC 6 + */ 7 + 8 + #include <linux/debugfs.h> 9 + #include <linux/fs.h> 10 + #include <linux/init.h> 11 + #include <linux/kernel.h> 12 + 13 + #include "nvmet.h" 14 + #include "debugfs.h" 15 + 16 + struct dentry *nvmet_debugfs; 17 + 18 + #define NVMET_DEBUGFS_ATTR(field) \ 19 + static int field##_open(struct inode *inode, struct file *file) \ 20 + { return single_open(file, field##_show, inode->i_private); } \ 21 + \ 22 + static const struct file_operations field##_fops = { \ 23 + .open = field##_open, \ 24 + .read = seq_read, \ 25 + .release = single_release, \ 26 + } 27 + 28 + #define NVMET_DEBUGFS_RW_ATTR(field) \ 29 + static int field##_open(struct inode *inode, struct file *file) \ 30 + { return single_open(file, field##_show, inode->i_private); } \ 31 + \ 32 + static const struct file_operations field##_fops = { \ 33 + .open = field##_open, \ 34 + .read = seq_read, \ 35 + .write = field##_write, \ 36 + .release = single_release, \ 37 + } 38 + 39 + static int nvmet_ctrl_hostnqn_show(struct seq_file *m, void *p) 40 + { 41 + struct nvmet_ctrl *ctrl = m->private; 42 + 43 + seq_puts(m, ctrl->hostnqn); 44 + return 0; 45 + } 46 + NVMET_DEBUGFS_ATTR(nvmet_ctrl_hostnqn); 47 + 48 + static int nvmet_ctrl_kato_show(struct seq_file *m, void *p) 49 + { 50 + struct nvmet_ctrl *ctrl = m->private; 51 + 52 + seq_printf(m, "%d\n", ctrl->kato); 53 + return 0; 54 + } 55 + NVMET_DEBUGFS_ATTR(nvmet_ctrl_kato); 56 + 57 + static int nvmet_ctrl_port_show(struct seq_file *m, void *p) 58 + { 59 + struct nvmet_ctrl *ctrl = m->private; 60 + 61 + seq_printf(m, "%d\n", le16_to_cpu(ctrl->port->disc_addr.portid)); 62 + return 0; 63 + } 64 + NVMET_DEBUGFS_ATTR(nvmet_ctrl_port); 65 + 66 + static const char *const csts_state_names[] = { 67 + [NVME_CSTS_RDY] = "ready", 68 + [NVME_CSTS_CFS] = "fatal", 69 + [NVME_CSTS_NSSRO] = "reset", 70 + [NVME_CSTS_SHST_OCCUR] = "shutdown", 71 + [NVME_CSTS_SHST_CMPLT] = "completed", 72 + [NVME_CSTS_PP] = "paused", 73 + }; 74 + 75 + static int nvmet_ctrl_state_show(struct seq_file *m, void *p) 76 + { 77 + struct nvmet_ctrl *ctrl = m->private; 78 + bool sep = false; 79 + int i; 80 + 81 + for (i = 0; i < 7; i++) { 82 + int state = BIT(i); 83 + 84 + if (!(ctrl->csts & state)) 85 + continue; 86 + if (sep) 87 + seq_puts(m, "|"); 88 + sep = true; 89 + if (csts_state_names[state]) 90 + seq_puts(m, csts_state_names[state]); 91 + else 92 + seq_printf(m, "%d", state); 93 + } 94 + if (sep) 95 + seq_printf(m, "\n"); 96 + return 0; 97 + } 98 + 99 + static ssize_t nvmet_ctrl_state_write(struct file *file, const char __user *buf, 100 + size_t count, loff_t *ppos) 101 + { 102 + struct seq_file *m = file->private_data; 103 + struct nvmet_ctrl *ctrl = m->private; 104 + char reset[16]; 105 + 106 + if (count >= sizeof(reset)) 107 + return -EINVAL; 108 + if (copy_from_user(reset, buf, count)) 109 + return -EFAULT; 110 + if (!memcmp(reset, "fatal", 5)) 111 + nvmet_ctrl_fatal_error(ctrl); 112 + else 113 + return -EINVAL; 114 + return count; 115 + } 116 + NVMET_DEBUGFS_RW_ATTR(nvmet_ctrl_state); 117 + 118 + int nvmet_debugfs_ctrl_setup(struct nvmet_ctrl *ctrl) 119 + { 120 + char name[32]; 121 + struct dentry *parent = ctrl->subsys->debugfs_dir; 122 + int ret; 123 + 124 + if (!parent) 125 + return -ENODEV; 126 + snprintf(name, sizeof(name), "ctrl%d", ctrl->cntlid); 127 + ctrl->debugfs_dir = debugfs_create_dir(name, parent); 128 + if (IS_ERR(ctrl->debugfs_dir)) { 129 + ret = PTR_ERR(ctrl->debugfs_dir); 130 + ctrl->debugfs_dir = NULL; 131 + return ret; 132 + } 133 + debugfs_create_file("port", S_IRUSR, ctrl->debugfs_dir, ctrl, 134 + &nvmet_ctrl_port_fops); 135 + debugfs_create_file("hostnqn", S_IRUSR, ctrl->debugfs_dir, ctrl, 136 + &nvmet_ctrl_hostnqn_fops); 137 + debugfs_create_file("kato", S_IRUSR, ctrl->debugfs_dir, ctrl, 138 + &nvmet_ctrl_kato_fops); 139 + debugfs_create_file("state", S_IRUSR | S_IWUSR, ctrl->debugfs_dir, ctrl, 140 + &nvmet_ctrl_state_fops); 141 + return 0; 142 + } 143 + 144 + void nvmet_debugfs_ctrl_free(struct nvmet_ctrl *ctrl) 145 + { 146 + debugfs_remove_recursive(ctrl->debugfs_dir); 147 + } 148 + 149 + int nvmet_debugfs_subsys_setup(struct nvmet_subsys *subsys) 150 + { 151 + int ret = 0; 152 + 153 + subsys->debugfs_dir = debugfs_create_dir(subsys->subsysnqn, 154 + nvmet_debugfs); 155 + if (IS_ERR(subsys->debugfs_dir)) { 156 + ret = PTR_ERR(subsys->debugfs_dir); 157 + subsys->debugfs_dir = NULL; 158 + } 159 + return ret; 160 + } 161 + 162 + void nvmet_debugfs_subsys_free(struct nvmet_subsys *subsys) 163 + { 164 + debugfs_remove_recursive(subsys->debugfs_dir); 165 + } 166 + 167 + int __init nvmet_init_debugfs(void) 168 + { 169 + struct dentry *parent; 170 + 171 + parent = debugfs_create_dir("nvmet", NULL); 172 + if (IS_ERR(parent)) { 173 + pr_warn("%s: failed to create debugfs directory\n", "nvmet"); 174 + return PTR_ERR(parent); 175 + } 176 + nvmet_debugfs = parent; 177 + return 0; 178 + } 179 + 180 + void nvmet_exit_debugfs(void) 181 + { 182 + debugfs_remove_recursive(nvmet_debugfs); 183 + }
+42
drivers/nvme/target/debugfs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * DebugFS interface for the NVMe target. 4 + * Copyright (c) 2022-2024 Shadow 5 + * Copyright (c) 2024 SUSE LLC 6 + */ 7 + #ifndef NVMET_DEBUGFS_H 8 + #define NVMET_DEBUGFS_H 9 + 10 + #include <linux/types.h> 11 + 12 + #ifdef CONFIG_NVME_TARGET_DEBUGFS 13 + int nvmet_debugfs_subsys_setup(struct nvmet_subsys *subsys); 14 + void nvmet_debugfs_subsys_free(struct nvmet_subsys *subsys); 15 + int nvmet_debugfs_ctrl_setup(struct nvmet_ctrl *ctrl); 16 + void nvmet_debugfs_ctrl_free(struct nvmet_ctrl *ctrl); 17 + 18 + int __init nvmet_init_debugfs(void); 19 + void nvmet_exit_debugfs(void); 20 + #else 21 + static inline int nvmet_debugfs_subsys_setup(struct nvmet_subsys *subsys) 22 + { 23 + return 0; 24 + } 25 + static inline void nvmet_debugfs_subsys_free(struct nvmet_subsys *subsys){} 26 + 27 + static inline int nvmet_debugfs_ctrl_setup(struct nvmet_ctrl *ctrl) 28 + { 29 + return 0; 30 + } 31 + static inline void nvmet_debugfs_ctrl_free(struct nvmet_ctrl *ctrl) {} 32 + 33 + static inline int __init nvmet_init_debugfs(void) 34 + { 35 + return 0; 36 + } 37 + 38 + static inline void nvmet_exit_debugfs(void) {} 39 + 40 + #endif 41 + 42 + #endif /* NVMET_DEBUGFS_H */
+6 -2
drivers/nvme/target/nvmet.h
··· 230 230 231 231 struct device *p2p_client; 232 232 struct radix_tree_root p2p_ns_map; 233 - 233 + #ifdef CONFIG_NVME_TARGET_DEBUGFS 234 + struct dentry *debugfs_dir; 235 + #endif 234 236 spinlock_t error_lock; 235 237 u64 err_counter; 236 238 struct nvme_error_slot slots[NVMET_ERROR_LOG_SLOTS]; ··· 264 262 265 263 struct list_head hosts; 266 264 bool allow_any_host; 267 - 265 + #ifdef CONFIG_NVME_TARGET_DEBUGFS 266 + struct dentry *debugfs_dir; 267 + #endif 268 268 u16 max_qid; 269 269 270 270 u64 ver;