nvme: allow duplicate NSIDs for private namespaces
authorSungup Moon <sungup.moon@samsung.com>
Mon, 14 Mar 2022 11:05:45 +0000 (20:05 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 8 Apr 2022 12:24:09 +0000 (14:24 +0200)
commit 5974ea7ce0f9a5987fc8cf5e08ad6e3e70bb542e upstream.

A NVMe subsystem with multiple controller can have private namespaces
that use the same NSID under some conditions:

 "If Namespace Management, ANA Reporting, or NVM Sets are supported, the
  NSIDs shall be unique within the NVM subsystem. If the Namespace
  Management, ANA Reporting, and NVM Sets are not supported, then NSIDs:
   a) for shared namespace shall be unique; and
   b) for private namespace are not required to be unique."

Reference: Section 6.1.6 NSID and Namespace Usage; NVM Express 1.4c spec.

Make sure this specific setup is supported in Linux.

Fixes: 9ad1927a3bc2 ("nvme: always search for namespace head")
Signed-off-by: Sungup Moon <sungup.moon@samsung.com>
[hch: refactored and fixed the controller vs subsystem based naming
      conflict]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/nvme/host/core.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
include/linux/nvme.h

index b349e19e745b1dffe0bcce786c25486f0fba1360..916f55bb76626c843cd4f7b05ec1b2ac5964f6d9 100644 (file)
@@ -3510,15 +3510,20 @@ static const struct attribute_group *nvme_dev_attr_groups[] = {
        NULL,
 };
 
-static struct nvme_ns_head *nvme_find_ns_head(struct nvme_subsystem *subsys,
+static struct nvme_ns_head *nvme_find_ns_head(struct nvme_ctrl *ctrl,
                unsigned nsid)
 {
        struct nvme_ns_head *h;
 
-       lockdep_assert_held(&subsys->lock);
+       lockdep_assert_held(&ctrl->subsys->lock);
 
-       list_for_each_entry(h, &subsys->nsheads, entry) {
-               if (h->ns_id != nsid)
+       list_for_each_entry(h, &ctrl->subsys->nsheads, entry) {
+               /*
+                * Private namespaces can share NSIDs under some conditions.
+                * In that case we can't use the same ns_head for namespaces
+                * with the same NSID.
+                */
+               if (h->ns_id != nsid || !nvme_is_unique_nsid(ctrl, h))
                        continue;
                if (!list_empty(&h->list) && nvme_tryget_ns_head(h))
                        return h;
@@ -3686,7 +3691,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
        int ret = 0;
 
        mutex_lock(&ctrl->subsys->lock);
-       head = nvme_find_ns_head(ctrl->subsys, nsid);
+       head = nvme_find_ns_head(ctrl, nsid);
        if (!head) {
                head = nvme_alloc_ns_head(ctrl, nsid, ids);
                if (IS_ERR(head)) {
index 727520c397109203aa98dae966a4eaac957b67fe..e9301b51db7636c3107d0a867372e0b60936e403 100644 (file)
@@ -462,10 +462,11 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
 
        /*
         * Add a multipath node if the subsystems supports multiple controllers.
-        * We also do this for private namespaces as the namespace sharing data could
-        * change after a rescan.
+        * We also do this for private namespaces as the namespace sharing flag
+        * could change after a rescan.
         */
-       if (!(ctrl->subsys->cmic & NVME_CTRL_CMIC_MULTI_CTRL) || !multipath)
+       if (!(ctrl->subsys->cmic & NVME_CTRL_CMIC_MULTI_CTRL) ||
+           !nvme_is_unique_nsid(ctrl, head) || !multipath)
                return 0;
 
        head->disk = blk_alloc_disk(ctrl->numa_node);
index ed79a6c7e8043b50d9770d278d0b8316436e4bbf..0628e2d802e731b2de74ac33eaf2df8f1adf76cc 100644 (file)
@@ -693,6 +693,25 @@ static inline bool nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
                return true;
        return __nvme_check_ready(ctrl, rq, queue_live);
 }
+
+/*
+ * NSID shall be unique for all shared namespaces, or if at least one of the
+ * following conditions is met:
+ *   1. Namespace Management is supported by the controller
+ *   2. ANA is supported by the controller
+ *   3. NVM Set are supported by the controller
+ *
+ * In other case, private namespace are not required to report a unique NSID.
+ */
+static inline bool nvme_is_unique_nsid(struct nvme_ctrl *ctrl,
+               struct nvme_ns_head *head)
+{
+       return head->shared ||
+               (ctrl->oacs & NVME_CTRL_OACS_NS_MNGT_SUPP) ||
+               (ctrl->subsys->cmic & NVME_CTRL_CMIC_ANA) ||
+               (ctrl->ctratt & NVME_CTRL_CTRATT_NVM_SETS);
+}
+
 int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
                void *buf, unsigned bufflen);
 int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
index b7c4c4130b65eff7d1b8ad85fa20e67e3b5a4448..039f59ee8f435f64f91fcb32700914033fda608d 100644 (file)
@@ -322,6 +322,7 @@ enum {
        NVME_CTRL_ONCS_TIMESTAMP                = 1 << 6,
        NVME_CTRL_VWC_PRESENT                   = 1 << 0,
        NVME_CTRL_OACS_SEC_SUPP                 = 1 << 0,
+       NVME_CTRL_OACS_NS_MNGT_SUPP             = 1 << 3,
        NVME_CTRL_OACS_DIRECTIVES               = 1 << 5,
        NVME_CTRL_OACS_DBBUF_SUPP               = 1 << 8,
        NVME_CTRL_LPA_CMD_EFFECTS_LOG           = 1 << 1,