[PATCH 2/3] nvmet: restrict setting of discovery_nqn to discovery subsystem

Hannes Reinecke hare at suse.de
Mon Mar 14 03:53:32 PDT 2022


Changing the discovery NQN only makes sense for the discovery subsystem,
as any other subsystem can only have one (fixed) subsystem NQN.

Signed-off-by: Hannes Reinecke <hare at suse.de>
---
 drivers/nvme/target/configfs.c | 32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 9b94af2444b2..58124abdbf62 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -1310,6 +1310,12 @@ CONFIGFS_ATTR(nvmet_subsys_, attr_model);
 static ssize_t nvmet_subsys_attr_discovery_nqn_show(struct config_item *item,
 			char *page)
 {
+	struct nvmet_subsys *subsys = to_subsys(item);
+
+	/* Only the discovery subsystem can have a different subsystem NQN */
+	if (subsys != nvmet_disc_subsys)
+		return -EBUSY;
+
 	return snprintf(page, PAGE_SIZE, "%s\n",
 			nvmet_disc_subsys->subsysnqn);
 }
@@ -1318,9 +1324,17 @@ static ssize_t nvmet_subsys_attr_discovery_nqn_store(struct config_item *item,
 			const char *page, size_t count)
 {
 	struct nvmet_subsys *subsys = to_subsys(item);
+	struct nvmet_port *port;
+	struct nvmet_subsys_link *p;
 	char *subsysnqn;
 	int len;
 
+	/*
+	 * Can only change the discovery NQN for the discovery subsystem
+	 */
+	if (subsys != nvmet_disc_subsys)
+		return -EBUSY;
+
 	len = strcspn(page, "\n");
 	if (!len)
 		return -EINVAL;
@@ -1330,13 +1344,21 @@ static ssize_t nvmet_subsys_attr_discovery_nqn_store(struct config_item *item,
 		return -ENOMEM;
 
 	/*
-	 * The discovery NQN must be different from subsystem NQN.
+	 * The discovery NQN must be different from other subsystem NQNs.
+	 *
+	 * This is a tad convoluted, but avoids having to do a
+	 * listdir() from the kernel.
 	 */
-	if (!strcmp(subsysnqn, subsys->subsysnqn)) {
-		kfree(subsysnqn);
-		return -EBUSY;
-	}
 	down_write(&nvmet_config_sem);
+	list_for_each_entry(port, &nvmet_ports_list, global_entry) {
+		list_for_each_entry(p, &port->subsystems, entry) {
+			if (!strcmp(subsysnqn, p->subsys->subsysnqn)) {
+				up_write(&nvmet_config_sem);
+				kfree(subsysnqn);
+				return -EBUSY;
+			}
+		}
+	}
 	kfree(nvmet_disc_subsys->subsysnqn);
 	nvmet_disc_subsys->subsysnqn = subsysnqn;
 	up_write(&nvmet_config_sem);
-- 
2.29.2




More information about the Linux-nvme mailing list