Commit b15bd3e6 authored by James Smart's avatar James Smart Committed by Martin K. Petersen

scsi: lpfc: Fix nvme remoteport registration race conditions

On tests adding and removing a remote port, calls to nvme_info would
eventually show fewer target ports discovered than were present in the
san. Additionally, the following error messages were seen:

  6031 RemotePort Registration failed err: -116, DID x471301

There is a race condition that exists between the driver and the nvme
transport on remote port unregister vs the confirmed deletion. It's
possible that the driver may rediscover the remote port and reregister
the remote port before a prior unregister delete callback was made (as
it rebinded to the prior remoteport structure). However, the driver was
coded to expect the callback before seeing the remote port again thus a
new registration. The logic results in the driver having an invalid
remoteport pointer set.

Correct by tracking when waiting for the delete callback. In cases where
the ndlp remoteport pointer is updated, it is only cleared when the wait
has not been superceded by a prior registration.
Signed-off-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <james.smart@broadcom.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent b04744ce
...@@ -334,8 +334,14 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) ...@@ -334,8 +334,14 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport)
"6146 remoteport delete of remoteport %p\n", "6146 remoteport delete of remoteport %p\n",
remoteport); remoteport);
spin_lock_irq(&vport->phba->hbalock); spin_lock_irq(&vport->phba->hbalock);
ndlp->nrport = NULL;
ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG; /* The register rebind might have occurred before the delete
* downcall. Guard against this race.
*/
if (ndlp->upcall_flags & NLP_WAIT_FOR_UNREG) {
ndlp->nrport = NULL;
ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG;
}
spin_unlock_irq(&vport->phba->hbalock); spin_unlock_irq(&vport->phba->hbalock);
/* Remove original register reference. The host transport /* Remove original register reference. The host transport
...@@ -2691,6 +2697,12 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ...@@ -2691,6 +2697,12 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
* a resume of the existing rport. Else this is a * a resume of the existing rport. Else this is a
* new rport. * new rport.
*/ */
/* Guard against an unregister/reregister
* race that leaves the WAIT flag set.
*/
spin_lock_irq(&vport->phba->hbalock);
ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG;
spin_unlock_irq(&vport->phba->hbalock);
rport = remote_port->private; rport = remote_port->private;
if (oldrport) { if (oldrport) {
if (oldrport == remote_port->private) { if (oldrport == remote_port->private) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment