Skip to content

Commit 4eaa19c

Browse files
leitaogregkh
authored andcommitted
nvme/multipath: Fix RCU list traversal to use SRCU primitive
[ Upstream commit 5dd18f0 ] The code currently uses list_for_each_entry_rcu() while holding an SRCU lock, triggering false positive warnings with CONFIG_PROVE_RCU=y enabled: drivers/nvme/host/multipath.c:168 RCU-list traversed in non-reader section!! drivers/nvme/host/multipath.c:227 RCU-list traversed in non-reader section!! drivers/nvme/host/multipath.c:260 RCU-list traversed in non-reader section!! While the list is properly protected by SRCU lock, the code uses the wrong list traversal primitive. Replace list_for_each_entry_rcu() with list_for_each_entry_srcu() to correctly indicate SRCU-based protection and eliminate the false warning. Signed-off-by: Breno Leitao <leitao@debian.org> Fixes: be647e2 ("nvme: use srcu for iterating namespace list") Signed-off-by: Keith Busch <kbusch@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 8f95ffb commit 4eaa19c

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

drivers/nvme/host/multipath.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
165165
int srcu_idx;
166166

167167
srcu_idx = srcu_read_lock(&ctrl->srcu);
168-
list_for_each_entry_rcu(ns, &ctrl->namespaces, list) {
168+
list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
169+
srcu_read_lock_held(&ctrl->srcu)) {
169170
if (!ns->head->disk)
170171
continue;
171172
kblockd_schedule_work(&ns->head->requeue_work);
@@ -209,7 +210,8 @@ void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl)
209210
int srcu_idx;
210211

211212
srcu_idx = srcu_read_lock(&ctrl->srcu);
212-
list_for_each_entry_rcu(ns, &ctrl->namespaces, list) {
213+
list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
214+
srcu_read_lock_held(&ctrl->srcu)) {
213215
nvme_mpath_clear_current_path(ns);
214216
kblockd_schedule_work(&ns->head->requeue_work);
215217
}
@@ -224,7 +226,8 @@ void nvme_mpath_revalidate_paths(struct nvme_ns *ns)
224226
int srcu_idx;
225227

226228
srcu_idx = srcu_read_lock(&head->srcu);
227-
list_for_each_entry_rcu(ns, &head->list, siblings) {
229+
list_for_each_entry_srcu(ns, &head->list, siblings,
230+
srcu_read_lock_held(&head->srcu)) {
228231
if (capacity != get_capacity(ns->disk))
229232
clear_bit(NVME_NS_READY, &ns->flags);
230233
}
@@ -257,7 +260,8 @@ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)
257260
int found_distance = INT_MAX, fallback_distance = INT_MAX, distance;
258261
struct nvme_ns *found = NULL, *fallback = NULL, *ns;
259262

260-
list_for_each_entry_rcu(ns, &head->list, siblings) {
263+
list_for_each_entry_srcu(ns, &head->list, siblings,
264+
srcu_read_lock_held(&head->srcu)) {
261265
if (nvme_path_is_disabled(ns))
262266
continue;
263267

@@ -356,7 +360,8 @@ static struct nvme_ns *nvme_queue_depth_path(struct nvme_ns_head *head)
356360
unsigned int min_depth_opt = UINT_MAX, min_depth_nonopt = UINT_MAX;
357361
unsigned int depth;
358362

359-
list_for_each_entry_rcu(ns, &head->list, siblings) {
363+
list_for_each_entry_srcu(ns, &head->list, siblings,
364+
srcu_read_lock_held(&head->srcu)) {
360365
if (nvme_path_is_disabled(ns))
361366
continue;
362367

@@ -424,7 +429,8 @@ static bool nvme_available_path(struct nvme_ns_head *head)
424429
if (!test_bit(NVME_NSHEAD_DISK_LIVE, &head->flags))
425430
return NULL;
426431

427-
list_for_each_entry_rcu(ns, &head->list, siblings) {
432+
list_for_each_entry_srcu(ns, &head->list, siblings,
433+
srcu_read_lock_held(&head->srcu)) {
428434
if (test_bit(NVME_CTRL_FAILFAST_EXPIRED, &ns->ctrl->flags))
429435
continue;
430436
switch (nvme_ctrl_state(ns->ctrl)) {
@@ -785,7 +791,8 @@ static int nvme_update_ana_state(struct nvme_ctrl *ctrl,
785791
return 0;
786792

787793
srcu_idx = srcu_read_lock(&ctrl->srcu);
788-
list_for_each_entry_rcu(ns, &ctrl->namespaces, list) {
794+
list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
795+
srcu_read_lock_held(&ctrl->srcu)) {
789796
unsigned nsid;
790797
again:
791798
nsid = le32_to_cpu(desc->nsids[n]);

0 commit comments

Comments
 (0)