nvme_fc_ctrl_put can acquire the rport lock when freeing the
ctrl object:
nvme_fc_ctrl_put
nvme_fc_ctrl_free
spin_lock_irqsave(rport->lock)
Thus we can't hold the rport lock when calling nvme_fc_ctrl_put.
Signed-off-by: Daniel Wagner <wagi@kernel.org>
---
drivers/nvme/host/fc.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 03987f497a5b..2c0ea843ae57 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -1488,7 +1488,9 @@ nvme_fc_match_disconn_ls(struct nvme_fc_rport *rport,
if (ret)
/* leave the ctrl get reference */
break;
+ spin_unlock_irqrestore(&rport->lock, flags);
nvme_fc_ctrl_put(ctrl);
+ spin_lock_irqsave(&rport->lock, flags);
}
spin_unlock_irqrestore(&rport->lock, flags);
--
2.51.0
On 10/28/25 16:26, Daniel Wagner wrote: > nvme_fc_ctrl_put can acquire the rport lock when freeing the > ctrl object: > > nvme_fc_ctrl_put > nvme_fc_ctrl_free > spin_lock_irqsave(rport->lock) > > Thus we can't hold the rport lock when calling nvme_fc_ctrl_put. > > Signed-off-by: Daniel Wagner <wagi@kernel.org> > --- > drivers/nvme/host/fc.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c > index 03987f497a5b..2c0ea843ae57 100644 > --- a/drivers/nvme/host/fc.c > +++ b/drivers/nvme/host/fc.c > @@ -1488,7 +1488,9 @@ nvme_fc_match_disconn_ls(struct nvme_fc_rport *rport, > if (ret) > /* leave the ctrl get reference */ > break; > + spin_unlock_irqrestore(&rport->lock, flags); > nvme_fc_ctrl_put(ctrl); > + spin_lock_irqsave(&rport->lock, flags); > } > > spin_unlock_irqrestore(&rport->lock, flags); > In theory, yes. In practice we're getting a reference to the controller at the start of the loop, so nvme_fc_ctrl_put() should just decrement the refcount. But _if_ someone manages to sneak in an drop the reference while we are within that loop then the entire logic falls apart as the controller will be deleted and the next loop iteration will trip over an uninitialized pointer. So you would need to modify the loop to use loop_for_each_entry_safe() to avoid this, too. Cheers, Hannes -- Dr. Hannes Reinecke Kernel Storage Architect hare@suse.de +49 911 74053 688 SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich
On Tue, Nov 04, 2025 at 11:51:09AM +0100, Hannes Reinecke wrote: > On 10/28/25 16:26, Daniel Wagner wrote: > > nvme_fc_ctrl_put can acquire the rport lock when freeing the > > ctrl object: > > > > nvme_fc_ctrl_put > > nvme_fc_ctrl_free > > spin_lock_irqsave(rport->lock) > > > > Thus we can't hold the rport lock when calling nvme_fc_ctrl_put. > > > > Signed-off-by: Daniel Wagner <wagi@kernel.org> > > --- > > drivers/nvme/host/fc.c | 2 ++ > > 1 file changed, 2 insertions(+) > > > > diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c > > index 03987f497a5b..2c0ea843ae57 100644 > > --- a/drivers/nvme/host/fc.c > > +++ b/drivers/nvme/host/fc.c > > @@ -1488,7 +1488,9 @@ nvme_fc_match_disconn_ls(struct nvme_fc_rport *rport, > > if (ret) > > /* leave the ctrl get reference */ > > break; > > + spin_unlock_irqrestore(&rport->lock, flags); > > nvme_fc_ctrl_put(ctrl); > > + spin_lock_irqsave(&rport->lock, flags); > > } > > spin_unlock_irqrestore(&rport->lock, flags); > > > In theory, yes. I hit this in practice ;)
On Tue, Oct 28, 2025 at 04:26:20PM +0100, Daniel Wagner wrote: > nvme_fc_ctrl_put can acquire the rport lock when freeing the > ctrl object: > > nvme_fc_ctrl_put > nvme_fc_ctrl_free > spin_lock_irqsave(rport->lock) > > Thus we can't hold the rport lock when calling nvme_fc_ctrl_put. > > Signed-off-by: Daniel Wagner <wagi@kernel.org> Looks good: Reviewed-by: Christoph Hellwig <hch@lst.de>
© 2016 - 2026 Red Hat, Inc.