nvmet: track and limit the number of namespaces per subsystem
authorChristoph Hellwig <hch@lst.de>
Sun, 13 May 2018 17:00:13 +0000 (19:00 +0200)
committerChristoph Hellwig <hch@lst.de>
Fri, 27 Jul 2018 17:13:01 +0000 (19:13 +0200)
TP 4004 introduces a new 'Maximum Number of Allocated Namespaces' field
in the Identify controller data to help the host size resources.  Put
an upper limit on the supported namespaces to be able to support this
value as supporting 32-bits worth of namespaces would lead to very
large buffers.  The limit is completely arbitrary at this point.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Keith Busch <keith.busch@intel.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/core.c
drivers/nvme/target/nvmet.h

index 16a9b24270f967b77212f321428add847c9ba617..55f2bf4b5d07453e9fc475a565adcda3306ddc94 100644 (file)
@@ -252,6 +252,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
        id->maxcmd = cpu_to_le16(NVMET_MAX_CMD);
 
        id->nn = cpu_to_le32(ctrl->subsys->max_nsid);
+       id->mnan = cpu_to_le32(NVMET_MAX_NAMESPACES);
        id->oncs = cpu_to_le16(NVME_CTRL_ONCS_DSM |
                        NVME_CTRL_ONCS_WRITE_ZEROES);
 
index cbcd19f52121aba1e09187c1c947bb21bc3bd016..42e8565015d5d7d128f853b10272b3d1d8489b66 100644 (file)
@@ -337,9 +337,13 @@ static void nvmet_ns_dev_disable(struct nvmet_ns *ns)
 int nvmet_ns_enable(struct nvmet_ns *ns)
 {
        struct nvmet_subsys *subsys = ns->subsys;
-       int ret = 0;
+       int ret;
 
        mutex_lock(&subsys->lock);
+       ret = -EMFILE;
+       if (subsys->nr_namespaces == NVMET_MAX_NAMESPACES)
+               goto out_unlock;
+       ret = 0;
        if (ns->enabled)
                goto out_unlock;
 
@@ -374,6 +378,7 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
 
                list_add_tail_rcu(&ns->dev_link, &old->dev_link);
        }
+       subsys->nr_namespaces++;
 
        nvmet_ns_changed(subsys, ns->nsid);
        ns->enabled = true;
@@ -414,6 +419,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns)
        percpu_ref_exit(&ns->ref);
 
        mutex_lock(&subsys->lock);
+       subsys->nr_namespaces--;
        nvmet_ns_changed(subsys, ns->nsid);
        nvmet_ns_dev_disable(ns);
 out_unlock:
index de12dcbfd3f3e5bac80886dfc2bbfc12a05f0e95..701017f7f3df3c24dab297f60ea0b7d28a1068e6 100644 (file)
@@ -170,6 +170,7 @@ struct nvmet_subsys {
        struct kref             ref;
 
        struct list_head        namespaces;
+       unsigned int            nr_namespaces;
        unsigned int            max_nsid;
 
        struct list_head        ctrls;
@@ -362,6 +363,13 @@ u32 nvmet_get_log_page_len(struct nvme_command *cmd);
 #define NVMET_QUEUE_SIZE       1024
 #define NVMET_NR_QUEUES                128
 #define NVMET_MAX_CMD          NVMET_QUEUE_SIZE
+
+/*
+ * Nice round number that makes a list of nsids fit into a page.
+ * Should become tunable at some point in the future.
+ */
+#define NVMET_MAX_NAMESPACES   1024
+
 #define NVMET_KAS              10
 #define NVMET_DISC_KATO                120