Commit 16f42ab6 authored by Breno Leitao's avatar Breno Leitao Committed by Wen Zhiwei
Browse files

nvme/host: Fix RCU list traversal to use SRCU primitive

stable inclusion
from stable-v6.6.62
commit 5a526388d0ac5ab5a2eb2b3dd6ef9d1a1866b5d7
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IB5BUT

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=5a526388d0ac5ab5a2eb2b3dd6ef9d1a1866b5d7



--------------------------------

[ Upstream commit 6d1c69945ce63a9fba22a4abf646cf960d878782 ]

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: default avatarBreno Leitao <leitao@debian.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarKeith Busch <kbusch@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarWen Zhiwei <wenzhiwei@kylinos.cn>
parent 013bf45f
Loading
Loading
Loading
Loading
+14 −7
Original line number Diff line number Diff line
@@ -3544,7 +3544,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;
@@ -4555,7 +4556,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);
}
@@ -4567,7 +4569,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);
@@ -4580,7 +4583,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;
@@ -4596,7 +4600,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);
}
@@ -4609,7 +4614,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);
}
@@ -4657,7 +4663,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);
}