[PATCH] nvmet: parametrize maximum number of namespaces

Aleksandr Dyadyushkin alextalker at ya.ru
Tue Feb 22 00:54:15 PST 2022


From: Aleksandr Dyadyushkin <alextalker at yandex.ru>

Allow the end user (i.e. the administrator) to set maximum number of
namespaces (and thus NN and MNAN implicitly) via module loading-time
parameter, without a need to modify and rebuild source code.

Most of all this can be helpful for mock-up configurations and possibly
really sparse NSID assignments.

For backwards compatibility, default values are left as is.

While permitted values are choosen as high as possible for the current
code architecture and standard limitations, it is worth noting that
allocations at 'nvmet_execute_get_log_page_ana' might yield a failure in
runtime on systems with high parameter value and low free memory.

Signed-off-by: Aleksandr Dyadyushkin <alextalker at ya.ru>
---
 drivers/nvme/target/admin-cmd.c |  6 +++---
 drivers/nvme/target/core.c      | 28 +++++++++++++++++++++++++++-
 drivers/nvme/target/nvmet.h     |  2 ++
 3 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 6fb24746de06..940297233986 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -278,7 +278,7 @@ static void nvmet_execute_get_log_page_ana(struct nvmet_req *req)
 	u16 status;
 
 	status = NVME_SC_INTERNAL;
-	desc = kmalloc(struct_size(desc, nsids, NVMET_MAX_NAMESPACES),
+	desc = kmalloc(struct_size(desc, nsids, nvmet_max_namespaces),
 		       GFP_KERNEL);
 	if (!desc)
 		goto out;
@@ -428,8 +428,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 	/* no enforcement soft-limit for maxcmd - pick arbitrary high value */
 	id->maxcmd = cpu_to_le16(NVMET_MAX_CMD);
 
-	id->nn = cpu_to_le32(NVMET_MAX_NAMESPACES);
-	id->mnan = cpu_to_le32(NVMET_MAX_NAMESPACES);
+	id->nn = cpu_to_le32(nvmet_max_namespaces);
+	id->mnan = cpu_to_le32(nvmet_max_namespaces);
 	id->oncs = cpu_to_le16(NVME_CTRL_ONCS_DSM |
 			NVME_CTRL_ONCS_WRITE_ZEROES);
 
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 5119c687de68..1b925b40074d 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -15,6 +15,32 @@
 
 #include "nvmet.h"
 
+static int max_namespaces_set(const char *val, const struct kernel_param *kp);
+static const struct kernel_param_ops max_namespaces_ops = {
+	.set = max_namespaces_set,
+	.get = param_get_uint,
+};
+
+/* Account for 0h NSID */
+#define NVMET_NSID_MAX (NVME_NSID_ALL - 1)
+
+u32 nvmet_max_namespaces = NVMET_MAX_NAMESPACES;
+module_param_cb(max_namespaces, &max_namespaces_ops, &nvmet_max_namespaces, 0444);
+MODULE_PARM_DESC(max_namespaces, "Set maximum number of namespaces per subsystem (default: 1024)");
+
+static int max_namespaces_set(const char *val, const struct kernel_param *kp) {
+	int ret;
+	u32 n;
+
+	ret = kstrtouint(val, 10, &n);
+	if (ret != 0)
+		return -EINVAL;
+	if (n == 0 || n >= NVMET_NSID_MAX)
+		return -EINVAL;
+
+	return param_set_uint(val, kp);
+}
+
 struct workqueue_struct *buffered_io_wq;
 struct workqueue_struct *zbd_wq;
 static const struct nvmet_fabrics_ops *nvmet_transports[NVMF_TRTYPE_MAX];
@@ -562,7 +588,7 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
 		goto out_unlock;
 
 	ret = -EMFILE;
-	if (subsys->nr_namespaces == NVMET_MAX_NAMESPACES)
+	if (subsys->nr_namespaces == nvmet_max_namespaces)
 		goto out_unlock;
 
 	ret = nvmet_bdev_ns_enable(ns);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index af193423c10b..ed4873963cc3 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -506,6 +506,8 @@ void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
  */
 #define NVMET_MAX_NAMESPACES	1024
 
+extern u32 nvmet_max_namespaces;
+
 /*
  * 0 is not a valid ANA group ID, so we start numbering at 1.
  *
-- 
2.35.1




More information about the Linux-nvme mailing list