Commit 5974ea7c authored by Sungup Moon's avatar Sungup Moon Committed by Christoph Hellwig

nvme: allow duplicate NSIDs for private namespaces

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: 9ad1927a ("nvme: always search for namespace head")
Signed-off-by: default avatarSungup Moon <sungup.moon@samsung.com>
[hch: refactored and fixed the controller vs subsystem based naming
      conflict]
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarSagi Grimberg <sagi@grimberg.me>
parent 63bc732c
...@@ -3627,15 +3627,20 @@ static const struct attribute_group *nvme_dev_attr_groups[] = { ...@@ -3627,15 +3627,20 @@ static const struct attribute_group *nvme_dev_attr_groups[] = {
NULL, 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) unsigned nsid)
{ {
struct nvme_ns_head *h; struct nvme_ns_head *h;
lockdep_assert_held(&subsys->lock); lockdep_assert_held(&ctrl->subsys->lock);
list_for_each_entry(h, &subsys->nsheads, entry) { list_for_each_entry(h, &ctrl->subsys->nsheads, entry) {
if (h->ns_id != nsid) /*
* 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; continue;
if (!list_empty(&h->list) && nvme_tryget_ns_head(h)) if (!list_empty(&h->list) && nvme_tryget_ns_head(h))
return h; return h;
...@@ -3829,7 +3834,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid, ...@@ -3829,7 +3834,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
} }
mutex_lock(&ctrl->subsys->lock); mutex_lock(&ctrl->subsys->lock);
head = nvme_find_ns_head(ctrl->subsys, nsid); head = nvme_find_ns_head(ctrl, nsid);
if (!head) { if (!head) {
ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, ids); ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, ids);
if (ret) { if (ret) {
......
...@@ -482,10 +482,11 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head) ...@@ -482,10 +482,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. * Add a multipath node if the subsystems supports multiple controllers.
* We also do this for private namespaces as the namespace sharing data could * We also do this for private namespaces as the namespace sharing flag
* change after a rescan. * 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; return 0;
head->disk = blk_alloc_disk(ctrl->numa_node); head->disk = blk_alloc_disk(ctrl->numa_node);
......
...@@ -722,6 +722,25 @@ static inline bool nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq, ...@@ -722,6 +722,25 @@ static inline bool nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
return queue_live; return queue_live;
return __nvme_check_ready(ctrl, rq, queue_live); 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, int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
void *buf, unsigned bufflen); void *buf, unsigned bufflen);
int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
......
...@@ -345,6 +345,7 @@ enum { ...@@ -345,6 +345,7 @@ enum {
NVME_CTRL_ONCS_TIMESTAMP = 1 << 6, NVME_CTRL_ONCS_TIMESTAMP = 1 << 6,
NVME_CTRL_VWC_PRESENT = 1 << 0, NVME_CTRL_VWC_PRESENT = 1 << 0,
NVME_CTRL_OACS_SEC_SUPP = 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_DIRECTIVES = 1 << 5,
NVME_CTRL_OACS_DBBUF_SUPP = 1 << 8, NVME_CTRL_OACS_DBBUF_SUPP = 1 << 8,
NVME_CTRL_LPA_CMD_EFFECTS_LOG = 1 << 1, NVME_CTRL_LPA_CMD_EFFECTS_LOG = 1 << 1,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment