From: Daniel Wagner wagi@kernel.org
[ Upstream commit 891cdbb162ccdb079cd5228ae43bdeebce8597ad ]
nvme_fc_unregister_remote removes the remote port on a lport object at any point in time when there is no active association. This races with with the reconnect logic, because nvme_fc_create_association is not taking a lock to check the port_state and atomically increase the active count on the rport.
Reported-by: Shinichiro Kawasaki shinichiro.kawasaki@wdc.com Closes: https://lore.kernel.org/all/u4ttvhnn7lark5w3sgrbuy2rxupcvosp4qmvj46nwzgeo5au... Signed-off-by: Daniel Wagner wagi@kernel.org Reviewed-by: Hannes Reinecke hare@suse.de Signed-off-by: Keith Busch kbusch@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES - Adds the missing synchronization in `nvme_fc_create_association()` so we hold `rport->lock` while checking `remoteport.port_state` and bumping `act_ctrl_cnt` via `nvme_fc_ctlr_active_on_rport()` (`drivers/nvme/host/fc.c:3034-3044`). That makes the state check and reference grab atomic with respect to other rport users. - Without this lock, `nvme_fc_unregister_remoteport()` can flip the same `remoteport.port_state` and tear down the rport under lock (`drivers/nvme/host/fc.c:813-839`) while a reconnect path is still between the state check and the `act_ctrl_cnt` increment (`drivers/nvme/host/fc.c:2987-2999`). This window lets the reconnect code touch freed memory or miss the counter bump, causing crashes or failed reconnections—the bug reported on the mailing list. - The fix is tightly scoped to this race, no API or behavioral changes elsewhere, and it follows existing locking rules for the rport. The affected logic is unchanged across supported stable branches, so the patch applies cleanly and removes a long-standing use-after-free hazard.
drivers/nvme/host/fc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 3e12d4683ac72..03987f497a5b5 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -3032,11 +3032,17 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
++ctrl->ctrl.nr_reconnects;
- if (ctrl->rport->remoteport.port_state != FC_OBJSTATE_ONLINE) + spin_lock_irqsave(&ctrl->rport->lock, flags); + if (ctrl->rport->remoteport.port_state != FC_OBJSTATE_ONLINE) { + spin_unlock_irqrestore(&ctrl->rport->lock, flags); return -ENODEV; + }
- if (nvme_fc_ctlr_active_on_rport(ctrl)) + if (nvme_fc_ctlr_active_on_rport(ctrl)) { + spin_unlock_irqrestore(&ctrl->rport->lock, flags); return -ENOTUNIQ; + } + spin_unlock_irqrestore(&ctrl->rport->lock, flags);
dev_info(ctrl->ctrl.device, "NVME-FC{%d}: create association : host wwpn 0x%016llx "