]> www.infradead.org Git - nvme.git/commitdiff
nvme/host: Fix RCU list traversal to use SRCU primitive nvme-6.12-2024-11-07
authorBreno Leitao <leitao@debian.org>
Mon, 4 Nov 2024 12:24:40 +0000 (04:24 -0800)
committerKeith Busch <kbusch@kernel.org>
Mon, 4 Nov 2024 21:25:41 +0000 (13:25 -0800)
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/core.c:3770 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.

Fixes: be647e2c76b2 ("nvme: use srcu for iterating namespace list")
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
drivers/nvme/host/core.c

index ce20b916301a3700e3b5d3bd08a9ae38a4d7c87c..4a83fd1200644ec6721e88e694441949115fa940 100644 (file)
@@ -3795,7 +3795,8 @@ struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        int srcu_idx;
 
        srcu_idx = srcu_read_lock(&ctrl->srcu);
-       list_for_each_entry_rcu(ns, &ctrl->namespaces, list) {
+       list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+                                srcu_read_lock_held(&ctrl->srcu)) {
                if (ns->head->ns_id == nsid) {
                        if (!nvme_get_ns(ns))
                                continue;
@@ -4879,7 +4880,8 @@ void nvme_mark_namespaces_dead(struct nvme_ctrl *ctrl)
        int srcu_idx;
 
        srcu_idx = srcu_read_lock(&ctrl->srcu);
-       list_for_each_entry_rcu(ns, &ctrl->namespaces, list)
+       list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+                                srcu_read_lock_held(&ctrl->srcu))
                blk_mark_disk_dead(ns->disk);
        srcu_read_unlock(&ctrl->srcu, srcu_idx);
 }
@@ -4891,7 +4893,8 @@ void nvme_unfreeze(struct nvme_ctrl *ctrl)
        int srcu_idx;
 
        srcu_idx = srcu_read_lock(&ctrl->srcu);
-       list_for_each_entry_rcu(ns, &ctrl->namespaces, list)
+       list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+                                srcu_read_lock_held(&ctrl->srcu))
                blk_mq_unfreeze_queue(ns->queue);
        srcu_read_unlock(&ctrl->srcu, srcu_idx);
        clear_bit(NVME_CTRL_FROZEN, &ctrl->flags);
@@ -4904,7 +4907,8 @@ int nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout)
        int srcu_idx;
 
        srcu_idx = srcu_read_lock(&ctrl->srcu);
-       list_for_each_entry_rcu(ns, &ctrl->namespaces, list) {
+       list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+                                srcu_read_lock_held(&ctrl->srcu)) {
                timeout = blk_mq_freeze_queue_wait_timeout(ns->queue, timeout);
                if (timeout <= 0)
                        break;
@@ -4920,7 +4924,8 @@ void nvme_wait_freeze(struct nvme_ctrl *ctrl)
        int srcu_idx;
 
        srcu_idx = srcu_read_lock(&ctrl->srcu);
-       list_for_each_entry_rcu(ns, &ctrl->namespaces, list)
+       list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+                                srcu_read_lock_held(&ctrl->srcu))
                blk_mq_freeze_queue_wait(ns->queue);
        srcu_read_unlock(&ctrl->srcu, srcu_idx);
 }
@@ -4933,7 +4938,8 @@ void nvme_start_freeze(struct nvme_ctrl *ctrl)
 
        set_bit(NVME_CTRL_FROZEN, &ctrl->flags);
        srcu_idx = srcu_read_lock(&ctrl->srcu);
-       list_for_each_entry_rcu(ns, &ctrl->namespaces, list)
+       list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+                                srcu_read_lock_held(&ctrl->srcu))
                blk_freeze_queue_start(ns->queue);
        srcu_read_unlock(&ctrl->srcu, srcu_idx);
 }
@@ -4981,7 +4987,8 @@ void nvme_sync_io_queues(struct nvme_ctrl *ctrl)
        int srcu_idx;
 
        srcu_idx = srcu_read_lock(&ctrl->srcu);
-       list_for_each_entry_rcu(ns, &ctrl->namespaces, list)
+       list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+                                srcu_read_lock_held(&ctrl->srcu))
                blk_sync_queue(ns->queue);
        srcu_read_unlock(&ctrl->srcu, srcu_idx);
 }