Skip to content

Commit 5974ea7

Browse files
sungupChristoph Hellwig
authored andcommitted
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: 9ad1927 ("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>
1 parent 63bc732 commit 5974ea7

4 files changed

Lines changed: 34 additions & 8 deletions

File tree

drivers/nvme/host/core.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3627,15 +3627,20 @@ static const struct attribute_group *nvme_dev_attr_groups[] = {
36273627
NULL,
36283628
};
36293629

3630-
static struct nvme_ns_head *nvme_find_ns_head(struct nvme_subsystem *subsys,
3630+
static struct nvme_ns_head *nvme_find_ns_head(struct nvme_ctrl *ctrl,
36313631
unsigned nsid)
36323632
{
36333633
struct nvme_ns_head *h;
36343634

3635-
lockdep_assert_held(&subsys->lock);
3635+
lockdep_assert_held(&ctrl->subsys->lock);
36363636

3637-
list_for_each_entry(h, &subsys->nsheads, entry) {
3638-
if (h->ns_id != nsid)
3637+
list_for_each_entry(h, &ctrl->subsys->nsheads, entry) {
3638+
/*
3639+
* Private namespaces can share NSIDs under some conditions.
3640+
* In that case we can't use the same ns_head for namespaces
3641+
* with the same NSID.
3642+
*/
3643+
if (h->ns_id != nsid || !nvme_is_unique_nsid(ctrl, h))
36393644
continue;
36403645
if (!list_empty(&h->list) && nvme_tryget_ns_head(h))
36413646
return h;
@@ -3829,7 +3834,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
38293834
}
38303835

38313836
mutex_lock(&ctrl->subsys->lock);
3832-
head = nvme_find_ns_head(ctrl->subsys, nsid);
3837+
head = nvme_find_ns_head(ctrl, nsid);
38333838
if (!head) {
38343839
ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, ids);
38353840
if (ret) {

drivers/nvme/host/multipath.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -482,10 +482,11 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
482482

483483
/*
484484
* Add a multipath node if the subsystems supports multiple controllers.
485-
* We also do this for private namespaces as the namespace sharing data could
486-
* change after a rescan.
485+
* We also do this for private namespaces as the namespace sharing flag
486+
* could change after a rescan.
487487
*/
488-
if (!(ctrl->subsys->cmic & NVME_CTRL_CMIC_MULTI_CTRL) || !multipath)
488+
if (!(ctrl->subsys->cmic & NVME_CTRL_CMIC_MULTI_CTRL) ||
489+
!nvme_is_unique_nsid(ctrl, head) || !multipath)
489490
return 0;
490491

491492
head->disk = blk_alloc_disk(ctrl->numa_node);

drivers/nvme/host/nvme.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,25 @@ static inline bool nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
722722
return queue_live;
723723
return __nvme_check_ready(ctrl, rq, queue_live);
724724
}
725+
726+
/*
727+
* NSID shall be unique for all shared namespaces, or if at least one of the
728+
* following conditions is met:
729+
* 1. Namespace Management is supported by the controller
730+
* 2. ANA is supported by the controller
731+
* 3. NVM Set are supported by the controller
732+
*
733+
* In other case, private namespace are not required to report a unique NSID.
734+
*/
735+
static inline bool nvme_is_unique_nsid(struct nvme_ctrl *ctrl,
736+
struct nvme_ns_head *head)
737+
{
738+
return head->shared ||
739+
(ctrl->oacs & NVME_CTRL_OACS_NS_MNGT_SUPP) ||
740+
(ctrl->subsys->cmic & NVME_CTRL_CMIC_ANA) ||
741+
(ctrl->ctratt & NVME_CTRL_CTRATT_NVM_SETS);
742+
}
743+
725744
int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
726745
void *buf, unsigned bufflen);
727746
int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,

include/linux/nvme.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ enum {
345345
NVME_CTRL_ONCS_TIMESTAMP = 1 << 6,
346346
NVME_CTRL_VWC_PRESENT = 1 << 0,
347347
NVME_CTRL_OACS_SEC_SUPP = 1 << 0,
348+
NVME_CTRL_OACS_NS_MNGT_SUPP = 1 << 3,
348349
NVME_CTRL_OACS_DIRECTIVES = 1 << 5,
349350
NVME_CTRL_OACS_DBBUF_SUPP = 1 << 8,
350351
NVME_CTRL_LPA_CMD_EFFECTS_LOG = 1 << 1,

0 commit comments

Comments
 (0)