[PATCH 1/1] scsi: lpfc: Clear rport association before unregistering it
Dai Ngo <[email protected]> Wed, 29 Jul 2026 08:18:33 -0700
| Newsgroups | org.kernel.vger.linux-scsi |
|---|---|
| Message-ID | <[email protected]> |
System crashed when a Fibre Channel cable is removed from an Emulex/Broadcom lpfc HBA. The crash occurs after the lpfc Link Down event, after dm-multipath fails paths, and when the FC remote ports time out and are removed. [ 3214.903257] lpfc 0000:c1:00.0: 0:1305 Link Down Event x2 received Data: x2 x20 x200110 x0 [ 3225.070299] sd 19:0:5:254: rejecting I/O to offline device [ 3225.070330] I/O error, dev sdm, sector 532480 op 0x0:(READ) flags 0x4200 phys_seg 16 prio class 2 [ 3225.070355] device-mapper: multipath: 252:10: Failing path 8:192. ... [ 3245.037613] rport-19:0-1: blocked FC remote port time out: removing rport [ 3245.037651] rport-19:0-0: blocked FC remote port time out: removing rport [ 3245.549614] rport-19:0-3: blocked FC remote port time out: removing rport [ 3245.549632] rport-19:0-2: blocked FC remote port time out: removing rport [ 3245.550290] Oops: general protection fault, probably for non-canonical address 0x400d7115d1923c7a: 0000 [#1] PREEMPT SMP NOPTI [ 3245.550309] CPU: 6 UID: 0 PID: 355 Comm: kworker/6:1 Kdump: loaded Not tainted 6.12.0-203.76.7.5.el9uek.x86_64 #2 [ 3245.550338] Workqueue: fc_wq_19 fc_rport_final_delete [scsi_transport_fc] [ 3245.550360] RIP: 0010:lpfc_dev_loss_tmo_callbk+0x58/0x48d [lpfc] Call trace: lpfc_dev_loss_tmo_callbk+0x58/0x48d [lpfc] fc_rport_final_delete+0xeb/0x1b0 [scsi_transport_fc] process_one_work+0x174/0x31a worker_thread+0x191/0x300 kthread+0xcf/0x100 ret_from_fork+0x31/0x50 ret_from_fork_asm+0x1a/0x30 The crash happened at this statement in lpfc_dev_loss_tmo_callbk(): phba = vport->phba; and vport has an invalid address, 0x400d7115d1923c7a. The crash happened because rport->dd_data->pnode still pointed to an ndlp, but that ndlp was no longer valid. If ndlp->vport is 0x400d7115d1923c7a, that is much more consistent with a stale/reused ndlp object than with a valid node whose vport was separately freed. The node pointer itself can still be canonical because it points into memory that used to be an lpfc_nodelist; its contents are what became invalid. This patch fixes the problem by detaching the node from the SCSI remote port before calling fc_remote_port_delete(). Clear rdata->pnode, ndlp->rport, and the SCSI transport registration flag while holding ndlp->lock. This prevents stale rport-to-node references and keeps the node’s transport state consistent during remote-port teardown. Assisted-by: Codex:gpt-5 Signed-off-by: Dai Ngo <[email protected]> --- drivers/scsi/lpfc/lpfc_hbadisc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index ecc9d6bcda32..f0329bb89e9a 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4564,6 +4564,8 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) { struct fc_rport *rport = ndlp->rport; struct lpfc_vport *vport = ndlp->vport; + struct lpfc_rport_data *rdata; + unsigned long iflags; if (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME) return; @@ -4578,6 +4580,14 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) ndlp->nlp_DID, rport, ndlp->fc4_xpt_flags, kref_read(&ndlp->kref)); + rdata = rport->dd_data; + spin_lock_irqsave(&ndlp->lock, iflags); + if (rdata && rdata->pnode == ndlp) + rdata->pnode = NULL; + ndlp->rport = NULL; + ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; + spin_unlock_irqrestore(&ndlp->lock, iflags); + fc_remote_port_delete(rport); lpfc_nlp_put(ndlp); } -- 2.47.3