[PATCH 2/2] scsi: fnic: free the NVMe port template from the delete callback

From: Linmao Li

Date: Wed Aug 19 2026 - 07:44:47 EST


nvfnic_nvme_unload() calls nvme_fc_unregister_localport(), waits for the
transport to call back into nvfnic_local_port_delete(), and then frees
iport->nv_tmpl. The wait is bounded, and when it expires the driver
only warns and frees the template anyway.

iport->nv_tmpl is the struct nvme_fc_port_template the transport keeps
in lport->ops. nvme_fc_unregister_localport() only invokes
->localport_delete() when the local port has no active remote ports
left; otherwise the call is deferred to
nvme_fc_rport_inactive_on_lport(), which dereferences lport->ops long
after the unregister call returned. Freeing the template on the timeout
path therefore leaves the transport with a dangling ->ops.

Tie the lifetime to the callback that marks the end of the transport's
use of the template instead of to the timeout. nvfnic_local_port_delete()
runs from ->localport_delete(), after which nvme_fc_free_lport() no
longer touches lport->ops, so freeing there is safe in both the direct
and the deferred case. The free is done before the completion is
signalled, because the unload path may tear the fnic down, and with it
the embedded iport, as soon as it wakes up.

Fixes: 5efdd5cf9281 ("scsi: fnic: Add the NVMe/FC transport path")
Signed-off-by: Linmao Li <lilinmao@xxxxxxxxxx>
---
drivers/scsi/fnic/fnic_nvme.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/fnic/fnic_nvme.c b/drivers/scsi/fnic/fnic_nvme.c
index 00d9d5d439a38..a8b7b7d40b9ab 100644
--- a/drivers/scsi/fnic/fnic_nvme.c
+++ b/drivers/scsi/fnic/fnic_nvme.c
@@ -1243,7 +1243,6 @@ void nvfnic_nvme_unload(struct fnic *fnic)
WARN_ON(1);
}
iport->flags &= ~FNIC_LPORT_NVME_REGISTERED;
- kfree(iport->nv_tmpl);
}
}

@@ -1669,6 +1668,9 @@ void nvfnic_local_port_delete(struct nvme_fc_local_port *lport)
FNIC_NVME_DBG(KERN_INFO, fnic, "lport delete 0x%x\n",
iport->fcid);

+ kfree(iport->nv_tmpl);
+ iport->nv_tmpl = NULL;
+
spin_lock_irqsave(&fnic->fnic_lock, flags);
if (fnic->nvme_lport_unreg_done)
complete(fnic->nvme_lport_unreg_done);
--
2.25.1