[PATCH 1/1] nvmet: View subsystem connections on nvmeof target

Redouane BOUFENGHOUR redouane.boufenghour at shadow.tech
Tue Mar 12 08:48:47 PDT 2024


From: Redouane Boufengour <redouane.boufenghour at shadow.tech>

We add a new entry in the tcp and rdma factories to retrieve the peer
address of a ctrl.

The functions nvmet_rdma_disc_peer_addr and nvmet_tcp_disc_peer_addr return
a snprintf of size NVMF_TRADDR_SIZE with the address connected to the ctlrs

which is then displayed in debugfs on /sys/kernel/debug/nvmet/ctrls/ctrl_*/

Co-developed-by: Pierre Marsais <pierre.marsais at shadow.tech>
Signed-off-by: Pierre Marsais <pierre.marsais at shadow.tech>
Signed-off-by: Redouane Boufengour <redouane.boufenghour at shadow.tech>
---
 drivers/nvme/target/Kconfig       |   9 +++
 drivers/nvme/target/Makefile      |   1 +
 drivers/nvme/target/core.c        |  18 ++++-
 drivers/nvme/target/debugfs.c     | 118 ++++++++++++++++++++++++++++++
 drivers/nvme/target/debugfs.h     |  41 +++++++++++
 drivers/nvme/target/fabrics-cmd.c |   2 +
 drivers/nvme/target/nvmet.h       |   4 +
 drivers/nvme/target/rdma.c        |  11 +++
 drivers/nvme/target/tcp.c         |  13 ++++
 9 files changed, 216 insertions(+), 1 deletion(-)
 create mode 100644 drivers/nvme/target/debugfs.c
 create mode 100644 drivers/nvme/target/debugfs.h

diff --git a/drivers/nvme/target/Kconfig b/drivers/nvme/target/Kconfig
index 872dd1a0acd8..ec1a8d29ea8d 100644
--- a/drivers/nvme/target/Kconfig
+++ b/drivers/nvme/target/Kconfig
@@ -107,3 +107,12 @@ config NVME_TARGET_AUTH
 	  target side.
 
 	  If unsure, say N.
+
+config NVME_TARGET_DEBUGFS
+	bool "NVMe over Fabrics debugfs support"
+	depends on NVME_TARGET
+	help
+	  This enables the debugfs support to view who is connected to the
+	  target.
+
+	  If unsure, say N.
diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile
index c66820102493..bc58d82af74d 100644
--- a/drivers/nvme/target/Makefile
+++ b/drivers/nvme/target/Makefile
@@ -20,3 +20,4 @@ nvmet-fc-y	+= fc.o
 nvme-fcloop-y	+= fcloop.o
 nvmet-tcp-y	+= tcp.o
 nvmet-$(CONFIG_TRACING)	+= trace.o
+nvmet-$(CONFIG_NVME_TARGET_DEBUGFS)	+= debugfs.o
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 8658e9c08534..e1fe169b38f2 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -15,6 +15,7 @@
 #define CREATE_TRACE_POINTS
 #include "trace.h"
 
+#include "debugfs.h"
 #include "nvmet.h"
 
 struct kmem_cache *nvmet_bvec_cache;
@@ -1474,6 +1475,7 @@ static void nvmet_ctrl_free(struct kref *ref)
 	struct nvmet_ctrl *ctrl = container_of(ref, struct nvmet_ctrl, ref);
 	struct nvmet_subsys *subsys = ctrl->subsys;
 
+	nvmet_debugfs_connected_ctrl_delete(ctrl);
 	mutex_lock(&subsys->lock);
 	nvmet_release_p2p_ns_map(ctrl);
 	list_del(&ctrl->subsys_entry);
@@ -1636,6 +1638,13 @@ void nvmet_subsys_del_ctrls(struct nvmet_subsys *subsys)
 	mutex_unlock(&subsys->lock);
 }
 
+int get_peer_traddr(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, char *dstaddr)
+{
+	if (ctrl->ops->disc_peertraddr == NULL)
+		return -EOPNOTSUPP;
+	return ctrl->ops->disc_peertraddr(sq, ctrl->port, dstaddr);
+}
+
 void nvmet_subsys_put(struct nvmet_subsys *subsys)
 {
 	kref_put(&subsys->ref, nvmet_subsys_free);
@@ -1670,11 +1679,17 @@ static int __init nvmet_init(void)
 	if (error)
 		goto out_free_nvmet_work_queue;
 
-	error = nvmet_init_configfs();
+	error = nvmet_init_debugfs();
 	if (error)
 		goto out_exit_discovery;
+
+	error = nvmet_init_configfs();
+	if (error)
+		goto out_exit_debugfs;
 	return 0;
 
+out_exit_debugfs:
+	nvmet_exit_debugfs();
 out_exit_discovery:
 	nvmet_exit_discovery();
 out_free_nvmet_work_queue:
@@ -1690,6 +1705,7 @@ static int __init nvmet_init(void)
 
 static void __exit nvmet_exit(void)
 {
+	nvmet_exit_debugfs();
 	nvmet_exit_configfs();
 	nvmet_exit_discovery();
 	ida_destroy(&cntlid_ida);
diff --git a/drivers/nvme/target/debugfs.c b/drivers/nvme/target/debugfs.c
new file mode 100644
index 000000000000..f1c8d489bdb8
--- /dev/null
+++ b/drivers/nvme/target/debugfs.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DebugFS interface for the NVMe target.
+ * Copyright (c) 2022-2024 Shadow
+ */
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include "debugfs.h"
+#include "nvmet.h"
+
+#define CTRL_MAX_LEN 11 /* sizeof("ctrl_65536") */
+
+static struct dentry *nvmet_debugfs_root;
+static struct dentry *nvmet_ctrls_dir;
+
+static ssize_t hostnqn_debug_read(struct file *filep, char __user *ubuf,
+				  size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+	char hostnqn[NVMF_NQN_FIELD_LEN + 1];
+	struct nvmet_ctrl *ctrl = filep->private_data;
+
+	ret = snprintf(hostnqn, sizeof(hostnqn), "%s\n", ctrl->hostnqn);
+	if (ret < 0)
+		return ret;
+
+	return simple_read_from_buffer(ubuf, count, ppos, hostnqn, ret);
+}
+
+static const struct file_operations hostnqn_debug_fops = {
+	.read = hostnqn_debug_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+static ssize_t host_traddr_debug_read(struct file *filep, char __user *ubuf,
+				      size_t count, loff_t *ppos)
+{
+	ssize_t size;
+	char buf[NVMF_TRADDR_SIZE + 1];
+	struct nvmet_ctrl *ctrl = filep->private_data;
+
+	size = get_peer_traddr(ctrl, ctrl->sqs[0], buf);
+	if (size < 0)
+		size = strscpy(buf, "unknown", sizeof(buf));
+
+	buf[size] = '\n';
+	size++;
+
+	return simple_read_from_buffer(ubuf, count, ppos, buf, size);
+}
+
+static const struct file_operations host_traddr_debug_fops = {
+	.read = host_traddr_debug_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+void nvmet_debugfs_connected_ctrl_delete(struct nvmet_ctrl *ctrl)
+{
+	struct dentry *controller_dir_parent;
+	char folder_id[CTRL_MAX_LEN];
+
+	snprintf(folder_id, sizeof(folder_id), "ctrl_%u", ctrl->cntlid);
+	controller_dir_parent = debugfs_lookup(folder_id, nvmet_ctrls_dir);
+	if (!controller_dir_parent)
+		return;
+
+	debugfs_remove_recursive(controller_dir_parent);
+}
+
+ssize_t nvmet_debugfs_connected_ctrl_write(struct nvmet_ctrl *ctrl)
+{
+	struct dentry *controller_dir_parent;
+	char folder_id[CTRL_MAX_LEN];
+
+	snprintf(folder_id, sizeof(folder_id), "ctrl_%u", ctrl->cntlid);
+
+	controller_dir_parent = debugfs_lookup(folder_id, nvmet_ctrls_dir);
+	if (!controller_dir_parent) {
+		controller_dir_parent =
+			debugfs_create_dir(folder_id, nvmet_ctrls_dir);
+		if (!controller_dir_parent)
+			return -ENODEV;
+	}
+
+	debugfs_create_str("subsystem", 0400, controller_dir_parent,
+			   &ctrl->subsys->subsysnqn);
+	debugfs_create_file("host_traddr", 0400, controller_dir_parent, ctrl,
+			    &host_traddr_debug_fops);
+	debugfs_create_file("hostnqn", 0400, controller_dir_parent, ctrl,
+			    &hostnqn_debug_fops);
+
+	return 0;
+}
+
+int __init nvmet_init_debugfs(void)
+{
+	nvmet_debugfs_root = debugfs_create_dir("nvmet", NULL);
+	if (!nvmet_debugfs_root)
+		return -ENODEV;
+
+	nvmet_ctrls_dir = debugfs_create_dir("ctrls", nvmet_debugfs_root);
+	if (!nvmet_ctrls_dir) {
+		debugfs_remove_recursive(nvmet_debugfs_root);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+void nvmet_exit_debugfs(void)
+{
+	debugfs_remove_recursive(nvmet_debugfs_root);
+}
diff --git a/drivers/nvme/target/debugfs.h b/drivers/nvme/target/debugfs.h
new file mode 100644
index 000000000000..7104a98903a5
--- /dev/null
+++ b/drivers/nvme/target/debugfs.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * DebugFS interface for the NVMe target.
+ * Copyright (c) 2022-2024 Shadow
+ */
+#ifndef NVMET_DEBUGFS_H
+#define NVMET_DEBUGFS_H
+
+#include <linux/types.h>
+
+#include "nvmet.h"
+
+#ifdef CONFIG_NVME_TARGET_DEBUGFS
+
+void nvmet_debugfs_connected_ctrl_delete(struct nvmet_ctrl *ctrl);
+ssize_t nvmet_debugfs_connected_ctrl_write(struct nvmet_ctrl *ctrl);
+
+int __init nvmet_init_debugfs(void);
+void nvmet_exit_debugfs(void);
+
+#else
+
+static inline void nvmet_debugfs_connected_ctrl_delete(struct nvmet_ctrl *){};
+
+static inline ssize_t nvmet_debugfs_connected_ctrl_write(struct nvmet_ctrl *)
+{
+	return 0;
+};
+
+static inline int __init nvmet_init_debugfs(void)
+{
+	return 0;
+}
+
+static inline void nvmet_exit_debugfs(void)
+{
+}
+
+#endif
+
+#endif // NVMET_DEBUGFS_H
diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c
index 9964ffe347d2..86b819afbc29 100644
--- a/drivers/nvme/target/fabrics-cmd.c
+++ b/drivers/nvme/target/fabrics-cmd.c
@@ -6,6 +6,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/blkdev.h>
 #include "nvmet.h"
+#include "debugfs.h"
 
 static void nvmet_execute_prop_set(struct nvmet_req *req)
 {
@@ -278,6 +279,7 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req)
 		ctrl->pi_support ? " T10-PI is enabled" : "",
 		nvmet_has_auth(ctrl) ? " with DH-HMAC-CHAP" : "");
 	req->cqe->result.u32 = cpu_to_le32(nvmet_connect_result(ctrl));
+	nvmet_debugfs_connected_ctrl_write(ctrl);
 out:
 	kfree(d);
 complete:
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 6c8acebe1a1a..7055991b8410 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -353,6 +353,8 @@ struct nvmet_fabrics_ops {
 	void (*discovery_chg)(struct nvmet_port *port);
 	u8 (*get_mdts)(const struct nvmet_ctrl *ctrl);
 	u16 (*get_max_queue_size)(const struct nvmet_ctrl *ctrl);
+	int (*disc_peertraddr)(struct nvmet_sq *nvme_sq,
+			struct nvmet_port *port, char *dstaddr);
 };
 
 #define NVMET_MAX_INLINE_BIOVEC	8
@@ -750,4 +752,6 @@ static inline bool nvmet_has_auth(struct nvmet_ctrl *ctrl)
 static inline const char *nvmet_dhchap_dhgroup_name(u8 dhgid) { return NULL; }
 #endif
 
+int get_peer_traddr(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq,
+		    char *dstaddr);
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index 3a0f2c170f4c..63faaa2b56b7 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -2006,6 +2006,16 @@ static void nvmet_rdma_disc_port_addr(struct nvmet_req *req,
 	}
 }
 
+static int nvmet_rdma_disc_peer_addr(struct nvmet_sq *nvme_sq,
+		struct nvmet_port *nport, char *dstaddr)
+{
+	struct nvmet_rdma_queue *queue =
+		container_of(nvme_sq, struct nvmet_rdma_queue, nvme_sq);
+
+	return snprintf(dstaddr, NVMF_TRADDR_SIZE, "%pISc",
+			(struct sockaddr *)&queue->cm_id->route.addr.dst_addr);
+}
+
 static u8 nvmet_rdma_get_mdts(const struct nvmet_ctrl *ctrl)
 {
 	if (ctrl->pi_support)
@@ -2028,6 +2038,7 @@ static const struct nvmet_fabrics_ops nvmet_rdma_ops = {
 	.queue_response		= nvmet_rdma_queue_response,
 	.delete_ctrl		= nvmet_rdma_delete_ctrl,
 	.disc_traddr		= nvmet_rdma_disc_port_addr,
+	.disc_peertraddr        = nvmet_rdma_disc_peer_addr,
 	.get_mdts		= nvmet_rdma_get_mdts,
 	.get_max_queue_size	= nvmet_rdma_get_max_queue_size,
 };
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index c8655fc5aa5b..4a7c78235d96 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -2171,6 +2171,18 @@ static void nvmet_tcp_disc_port_addr(struct nvmet_req *req,
 	}
 }
 
+static int nvmet_tcp_disc_peer_addr(struct nvmet_sq *sq,
+		struct nvmet_port *nport, char *dstaddr)
+{
+	struct nvmet_tcp_queue *queue =
+		container_of(sq, struct nvmet_tcp_queue, nvme_sq);
+
+	if (queue->sockaddr_peer.ss_family == AF_UNSPEC)
+		return -EINVAL;
+	return snprintf(dstaddr, NVMF_TRADDR_SIZE, "%pISc",
+			(struct sockaddr *)&queue->sockaddr_peer);
+}
+
 static const struct nvmet_fabrics_ops nvmet_tcp_ops = {
 	.owner			= THIS_MODULE,
 	.type			= NVMF_TRTYPE_TCP,
@@ -2181,6 +2193,7 @@ static const struct nvmet_fabrics_ops nvmet_tcp_ops = {
 	.delete_ctrl		= nvmet_tcp_delete_ctrl,
 	.install_queue		= nvmet_tcp_install_queue,
 	.disc_traddr		= nvmet_tcp_disc_port_addr,
+	.disc_peertraddr        = nvmet_tcp_disc_peer_addr,
 };
 
 static int __init nvmet_tcp_init(void)
-- 
2.39.3 (Apple Git-145)




More information about the Linux-nvme mailing list