Merge tag 'for-5.18/drivers-2022-04-01' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / drivers / nvme / host / multipath.c
index 1b31f19..d464fdf 100644 (file)
@@ -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.
-        * 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);
@@ -612,8 +613,17 @@ static void nvme_update_ns_ana_state(struct nvme_ana_group_desc *desc,
        ns->ana_grpid = le32_to_cpu(desc->grpid);
        ns->ana_state = desc->state;
        clear_bit(NVME_NS_ANA_PENDING, &ns->flags);
-
-       if (nvme_state_is_live(ns->ana_state))
+       /*
+        * nvme_mpath_set_live() will trigger I/O to the multipath path device
+        * and in turn to this path device.  However we cannot accept this I/O
+        * if the controller is not live.  This may deadlock if called from
+        * nvme_mpath_init_identify() and the ctrl will never complete
+        * initialization, preventing I/O from completing.  For this case we
+        * will reprocess the ANA log page in nvme_mpath_update() once the
+        * controller is ready.
+        */
+       if (nvme_state_is_live(ns->ana_state) &&
+           ns->ctrl->state == NVME_CTRL_LIVE)
                nvme_mpath_set_live(ns);
 }
 
@@ -700,6 +710,18 @@ static void nvme_ana_work(struct work_struct *work)
        nvme_read_ana_log(ctrl);
 }
 
+void nvme_mpath_update(struct nvme_ctrl *ctrl)
+{
+       u32 nr_change_groups = 0;
+
+       if (!ctrl->ana_log_buf)
+               return;
+
+       mutex_lock(&ctrl->ana_lock);
+       nvme_parse_ana_log(ctrl, &nr_change_groups, nvme_update_ana_state);
+       mutex_unlock(&ctrl->ana_lock);
+}
+
 static void nvme_anatt_timeout(struct timer_list *t)
 {
        struct nvme_ctrl *ctrl = from_timer(ctrl, t, anatt_timer);