[PATCH nvme-cli] nvme: warn about attaching a namespace to unknown controller

Nilay Shroff nilay at linux.ibm.com
Thu Jun 20 05:55:45 PDT 2024


Sometime it's possible for a multi-controller NVMe disk to have only
one of its controller discovered by the kernel. And if this happens
then it's also possible for a user to create and then attach a namespace
to a controller which has not been discovered by the kernel. In such a
case the attached namespace can't be used for IO because there's no path
to reach such namespace from the kernel.

This patch helps to warn about such case to user when user attempts to
attach a namepsace to an undiscovered controller by kernel. If this warning
appears to the user then user have about 10 seconds of time to abort the
operation by pressing CTRL-C. If user doesn't abort this operation
within 10 seconds of timeout then nvme cli goes ahead as usual and attach
the namespace to the controller.

Link: https://lore.kernel.org/all/f1a7c1e2-3203-4b7a-a922-82fa812455bd@linux.ibm.com/
Signed-off-by: Nilay Shroff <nilay at linux.ibm.com>
---
 nvme.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 86 insertions(+), 4 deletions(-)

diff --git a/nvme.c b/nvme.c
index ba760901..0f3b3297 100644
--- a/nvme.c
+++ b/nvme.c
@@ -2811,6 +2811,84 @@ static int delete_ns(int argc, char **argv, struct command *cmd, struct plugin *
 	return err;
 }
 
+static bool nvme_match_subsys_device_filter(nvme_subsystem_t s, nvme_ctrl_t c,
+		   nvme_ns_t ns, void *f_arg)
+{
+	nvme_ctrl_t _c;
+	const char *devname = (const char *)f_arg;
+
+	if (!s)
+		return true;
+
+	nvme_subsystem_for_each_ctrl(s, _c) {
+		if (!strcmp(devname, nvme_ctrl_get_name(_c)))
+			return true;
+	}
+
+	return false;
+}
+
+static int nvme_cli_ns_validate_cntlid(__u32 nsid, struct nvme_dev *dev,
+				       int *list, int num)
+{
+	const char *cntlid;
+	int __cntlid;
+	char *p;
+	nvme_host_t h;
+	nvme_subsystem_t s;
+	nvme_ctrl_t c;
+	nvme_root_t r = NULL;
+	int i, err, matched = 0;
+	nvme_scan_filter_t filter = nvme_match_subsys_device_filter;
+
+	r = nvme_create_root(stderr, log_level);
+	if (!r) {
+		nvme_show_error("Failed to create topology root: %s",
+				nvme_strerror(errno));
+		return -errno;
+	}
+
+	err = nvme_scan_topology(r, filter, (void *)dev->name);
+	if (err < 0) {
+		if (errno != ENOENT)
+			nvme_show_error("Failed to scan topology: %s",
+					nvme_strerror(errno));
+		nvme_free_tree(r);
+		return err;
+	}
+	nvme_for_each_host(r, h) {
+		nvme_for_each_subsystem(h, s) {
+			nvme_subsystem_for_each_ctrl(s, c) {
+				cntlid = nvme_ctrl_get_cntlid(c);
+				errno = 0;
+				__cntlid = strtoul(cntlid, &p, 0);
+				if (errno || *p != 0)
+					continue;
+				for (i = 0; i < num; i++) {
+					if (__cntlid == list[i])
+						matched++;
+				}
+			}
+		}
+	}
+
+	nvme_free_tree(r);
+
+	if (matched != num) {
+		fprintf(stderr,
+			"You are about to attach namespace 0x%x to an undiscovered nvme controller.\n",
+			nsid);
+		fprintf(stderr,
+			"WARNING: Attaching nampespace to undiscovered nvme controller may have undesired side effect!\n"
+			"You may not be able to perform any IO to such namespace.\n"
+			"You have 10 seconds to press Ctrl-C to cancel this operation.\n\n");
+		sleep(10);
+		fprintf(stderr, "Sending attach-ns operation ...\n");
+	}
+
+	return 0;
+}
+
 static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, struct command *cmd)
 {
 	_cleanup_free_ struct nvme_ctrl_list *cntlist = NULL;
@@ -2866,12 +2944,16 @@ static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, s
 
 	nvme_init_ctrl_list(cntlist, num, ctrlist);
 
-	if (attach)
-		err = nvme_cli_ns_attach_ctrls(dev, cfg.namespace_id,
-					       cntlist);
-	else
+	if (attach) {
+		err = nvme_cli_ns_validate_cntlid(cfg.namespace_id, dev,
+						  list, num);
+		if (!err)
+			err = nvme_cli_ns_attach_ctrls(dev, cfg.namespace_id,
+						       cntlist);
+	} else {
 		err = nvme_cli_ns_detach_ctrls(dev, cfg.namespace_id,
 					       cntlist);
+	}
 
 	if (!err)
 		printf("%s: Success, nsid:%d\n", cmd->name, cfg.namespace_id);
-- 
2.45.1




More information about the Linux-nvme mailing list