Skip to content

Commit d6d6742

Browse files
cleechChristoph Hellwig
authored andcommitted
nvme: fix RCU hole that allowed for endless looping in multipath round robin
Make nvme_ns_remove match the assumptions elsewhere. 1) !NVME_NS_READY needs to be srcu synchronized to make sure nothing is running in __nvme_find_path or nvme_round_robin_path that will re-assign this ns to current_path. 2) Any matching current_path entries need to be cleared before removing from the siblings list, to prevent calling nvme_round_robin_path with an "old" ns that's off list. 3) Finally the list_del_rcu can happen, and then synchronize again before releasing any reference counts. Signed-off-by: Christoph Hellwig <hch@lst.de>
1 parent 5974ea7 commit d6d6742

1 file changed

Lines changed: 10 additions & 4 deletions

File tree

drivers/nvme/host/core.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4031,6 +4031,16 @@ static void nvme_ns_remove(struct nvme_ns *ns)
40314031
set_capacity(ns->disk, 0);
40324032
nvme_fault_inject_fini(&ns->fault_inject);
40334033

4034+
/*
4035+
* Ensure that !NVME_NS_READY is seen by other threads to prevent
4036+
* this ns going back into current_path.
4037+
*/
4038+
synchronize_srcu(&ns->head->srcu);
4039+
4040+
/* wait for concurrent submissions */
4041+
if (nvme_mpath_clear_current_path(ns))
4042+
synchronize_srcu(&ns->head->srcu);
4043+
40344044
mutex_lock(&ns->ctrl->subsys->lock);
40354045
list_del_rcu(&ns->siblings);
40364046
if (list_empty(&ns->head->list)) {
@@ -4042,10 +4052,6 @@ static void nvme_ns_remove(struct nvme_ns *ns)
40424052
/* guarantee not available in head->list */
40434053
synchronize_rcu();
40444054

4045-
/* wait for concurrent submissions */
4046-
if (nvme_mpath_clear_current_path(ns))
4047-
synchronize_srcu(&ns->head->srcu);
4048-
40494055
if (!nvme_ns_head_multipath(ns->head))
40504056
nvme_cdev_del(&ns->cdev, &ns->cdev_device);
40514057
del_gendisk(ns->disk);

0 commit comments

Comments
 (0)