Merge tag 'for-5.18/drivers-2022-04-01' of git://git.kernel.dk/linux-block
[linux-block.git] / drivers / nvme / host / core.c
index 677fa4bf76d3ba15459032bffed2d8549629a191..efb85c6d8e2d5d723e177116db1986c65f065ab0 100644 (file)
@@ -1830,9 +1830,6 @@ static void nvme_update_disk_info(struct gendisk *disk,
        nvme_config_discard(disk, ns);
        blk_queue_max_write_zeroes_sectors(disk->queue,
                                           ns->ctrl->max_zeroes_sectors);
-
-       set_disk_ro(disk, (id->nsattr & NVME_NS_ATTR_RO) ||
-               test_bit(NVME_NS_FORCE_RO, &ns->flags));
 }
 
 static inline bool nvme_first_scan(struct gendisk *disk)
@@ -1891,6 +1888,8 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
                        goto out_unfreeze;
        }
 
+       set_disk_ro(ns->disk, (id->nsattr & NVME_NS_ATTR_RO) ||
+               test_bit(NVME_NS_FORCE_RO, &ns->flags));
        set_bit(NVME_NS_READY, &ns->flags);
        blk_mq_unfreeze_queue(ns->disk->queue);
 
@@ -1903,6 +1902,9 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
        if (nvme_ns_head_multipath(ns->head)) {
                blk_mq_freeze_queue(ns->head->disk->queue);
                nvme_update_disk_info(ns->head->disk, ns, id);
+               set_disk_ro(ns->head->disk,
+                           (id->nsattr & NVME_NS_ATTR_RO) ||
+                                   test_bit(NVME_NS_FORCE_RO, &ns->flags));
                nvme_mpath_revalidate_paths(ns);
                blk_stack_limits(&ns->head->disk->queue->limits,
                                 &ns->queue->limits, 0);
@@ -3589,15 +3591,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;
@@ -3791,7 +3798,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
        }
 
        mutex_lock(&ctrl->subsys->lock);
-       head = nvme_find_ns_head(ctrl->subsys, nsid);
+       head = nvme_find_ns_head(ctrl, nsid);
        if (!head) {
                ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, ids);
                if (ret) {
@@ -3988,6 +3995,16 @@ static void nvme_ns_remove(struct nvme_ns *ns)
        set_capacity(ns->disk, 0);
        nvme_fault_inject_fini(&ns->fault_inject);
 
+       /*
+        * Ensure that !NVME_NS_READY is seen by other threads to prevent
+        * this ns going back into current_path.
+        */
+       synchronize_srcu(&ns->head->srcu);
+
+       /* wait for concurrent submissions */
+       if (nvme_mpath_clear_current_path(ns))
+               synchronize_srcu(&ns->head->srcu);
+
        mutex_lock(&ns->ctrl->subsys->lock);
        list_del_rcu(&ns->siblings);
        if (list_empty(&ns->head->list)) {
@@ -3999,10 +4016,6 @@ static void nvme_ns_remove(struct nvme_ns *ns)
        /* guarantee not available in head->list */
        synchronize_rcu();
 
-       /* wait for concurrent submissions */
-       if (nvme_mpath_clear_current_path(ns))
-               synchronize_srcu(&ns->head->srcu);
-
        if (!nvme_ns_head_multipath(ns->head))
                nvme_cdev_del(&ns->cdev, &ns->cdev_device);
        del_gendisk(ns->disk);
@@ -4480,6 +4493,7 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl)
        if (ctrl->queue_count > 1) {
                nvme_queue_scan(ctrl);
                nvme_start_queues(ctrl);
+               nvme_mpath_update(ctrl);
        }
 
        nvme_change_uevent(ctrl, "NVME_EVENT=connected");