Skip to content

Commit 649fd41

Browse files
Hannes Reineckekeithbusch
authored andcommitted
nvmet: add debugfs support
Add a debugfs hierarchy to display the configured subsystems and the controllers attached to the subsystems. Suggested-by: Redouane BOUFENGHOUR <[email protected]> Signed-off-by: Hannes Reinecke <[email protected]> Reviewed-by: Sagi Grimberg <[email protected]> Reviewed-by: Chaitanya Kulkarni <[email protected]> Signed-off-by: Daniel Wagner <[email protected]> Signed-off-by: Keith Busch <[email protected]>
1 parent d1237b3 commit 649fd41

File tree

6 files changed

+262
-3
lines changed

6 files changed

+262
-3
lines changed

drivers/nvme/target/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ config NVME_TARGET
1717
To configure the NVMe target you probably want to use the nvmetcli
1818
tool from http://git.infradead.org/users/hch/nvmetcli.git.
1919

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+
2029
config NVME_TARGET_PASSTHRU
2130
bool "NVMe Target Passthrough support"
2231
depends on NVME_TARGET

drivers/nvme/target/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ obj-$(CONFIG_NVME_TARGET_TCP) += nvmet-tcp.o
1111

1212
nvmet-y += core.o configfs.o admin-cmd.o fabrics-cmd.o \
1313
discovery.o io-cmd-file.o io-cmd-bdev.o
14+
nvmet-$(CONFIG_NVME_TARGET_DEBUGFS) += debugfs.o
1415
nvmet-$(CONFIG_NVME_TARGET_PASSTHRU) += passthru.o
1516
nvmet-$(CONFIG_BLK_DEV_ZONED) += zns.o
1617
nvmet-$(CONFIG_NVME_TARGET_AUTH) += fabrics-cmd-auth.o auth.o

drivers/nvme/target/core.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "trace.h"
1717

1818
#include "nvmet.h"
19+
#include "debugfs.h"
1920

2021
struct kmem_cache *nvmet_bvec_cache;
2122
struct workqueue_struct *buffered_io_wq;
@@ -1478,6 +1479,7 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
14781479
mutex_lock(&subsys->lock);
14791480
list_add_tail(&ctrl->subsys_entry, &subsys->ctrls);
14801481
nvmet_setup_p2p_ns_map(ctrl, req);
1482+
nvmet_debugfs_ctrl_setup(ctrl);
14811483
mutex_unlock(&subsys->lock);
14821484

14831485
*ctrlp = ctrl;
@@ -1512,6 +1514,8 @@ static void nvmet_ctrl_free(struct kref *ref)
15121514

15131515
nvmet_destroy_auth(ctrl);
15141516

1517+
nvmet_debugfs_ctrl_free(ctrl);
1518+
15151519
ida_free(&cntlid_ida, ctrl->cntlid);
15161520

15171521
nvmet_async_events_free(ctrl);
@@ -1632,8 +1636,14 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
16321636
INIT_LIST_HEAD(&subsys->ctrls);
16331637
INIT_LIST_HEAD(&subsys->hosts);
16341638

1639+
ret = nvmet_debugfs_subsys_setup(subsys);
1640+
if (ret)
1641+
goto free_subsysnqn;
1642+
16351643
return subsys;
16361644

1645+
free_subsysnqn:
1646+
kfree(subsys->subsysnqn);
16371647
free_fr:
16381648
kfree(subsys->firmware_rev);
16391649
free_mn:
@@ -1650,6 +1660,8 @@ static void nvmet_subsys_free(struct kref *ref)
16501660

16511661
WARN_ON_ONCE(!xa_empty(&subsys->namespaces));
16521662

1663+
nvmet_debugfs_subsys_free(subsys);
1664+
16531665
xa_destroy(&subsys->namespaces);
16541666
nvmet_passthru_subsys_free(subsys);
16551667

@@ -1704,11 +1716,18 @@ static int __init nvmet_init(void)
17041716
if (error)
17051717
goto out_free_nvmet_work_queue;
17061718

1707-
error = nvmet_init_configfs();
1719+
error = nvmet_init_debugfs();
17081720
if (error)
17091721
goto out_exit_discovery;
1722+
1723+
error = nvmet_init_configfs();
1724+
if (error)
1725+
goto out_exit_debugfs;
1726+
17101727
return 0;
17111728

1729+
out_exit_debugfs:
1730+
nvmet_exit_debugfs();
17121731
out_exit_discovery:
17131732
nvmet_exit_discovery();
17141733
out_free_nvmet_work_queue:
@@ -1725,6 +1744,7 @@ static int __init nvmet_init(void)
17251744
static void __exit nvmet_exit(void)
17261745
{
17271746
nvmet_exit_configfs();
1747+
nvmet_exit_debugfs();
17281748
nvmet_exit_discovery();
17291749
ida_destroy(&cntlid_ida);
17301750
destroy_workqueue(nvmet_wq);

drivers/nvme/target/debugfs.c

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
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+
}

drivers/nvme/target/debugfs.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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 */

drivers/nvme/target/nvmet.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,9 @@ struct nvmet_ctrl {
230230

231231
struct device *p2p_client;
232232
struct radix_tree_root p2p_ns_map;
233-
233+
#ifdef CONFIG_NVME_TARGET_DEBUGFS
234+
struct dentry *debugfs_dir;
235+
#endif
234236
spinlock_t error_lock;
235237
u64 err_counter;
236238
struct nvme_error_slot slots[NVMET_ERROR_LOG_SLOTS];
@@ -262,7 +264,9 @@ struct nvmet_subsys {
262264

263265
struct list_head hosts;
264266
bool allow_any_host;
265-
267+
#ifdef CONFIG_NVME_TARGET_DEBUGFS
268+
struct dentry *debugfs_dir;
269+
#endif
266270
u16 max_qid;
267271

268272
u64 ver;

0 commit comments

Comments
 (0)