| From foo@baz Sat Nov 10 11:17:19 PST 2018 |
| From: James Smart <jsmart2021@gmail.com> |
| Date: Mon, 10 Sep 2018 10:30:44 -0700 |
| Subject: scsi: lpfc: Correct race with abort on completion path |
| |
| From: James Smart <jsmart2021@gmail.com> |
| |
| [ Upstream commit ca7fb76e091f889cfda1287c07a9358f73832b39 ] |
| |
| On io completion, the driver is taking an adapter wide lock and nulling the |
| scsi command back pointer. The nulling of the back pointer is to signify the |
| io was completed and the scsi_done() routine was called. However, the routine |
| makes no check to see if the abort routine had done the same thing and |
| possibly nulled the pointer. Thus it may doubly-complete the io. |
| |
| Make the following mods: |
| |
| - Check to make sure forward progress (call scsi_done()) only happens if the |
| command pointer was non-null. |
| |
| - As the taking of the lock, which is adapter wide, is very costly on a system |
| under load, null the pointer using an xchg operation rather than under lock. |
| |
| Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com> |
| Signed-off-by: James Smart <james.smart@broadcom.com> |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/scsi/lpfc/lpfc_scsi.c | 14 +++++++++++--- |
| 1 file changed, 11 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/scsi/lpfc/lpfc_scsi.c |
| +++ b/drivers/scsi/lpfc/lpfc_scsi.c |
| @@ -4149,9 +4149,17 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba |
| |
| lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); |
| |
| - spin_lock_irqsave(&phba->hbalock, flags); |
| - lpfc_cmd->pCmd = NULL; |
| - spin_unlock_irqrestore(&phba->hbalock, flags); |
| + /* If pCmd was set to NULL from abort path, do not call scsi_done */ |
| + if (xchg(&lpfc_cmd->pCmd, NULL) == NULL) { |
| + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, |
| + "0711 FCP cmd already NULL, sid: 0x%06x, " |
| + "did: 0x%06x, oxid: 0x%04x\n", |
| + vport->fc_myDID, |
| + (pnode) ? pnode->nlp_DID : 0, |
| + phba->sli_rev == LPFC_SLI_REV4 ? |
| + lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff); |
| + return; |
| + } |
| |
| /* The sdev is not guaranteed to be valid post scsi_done upcall. */ |
| cmd->scsi_done(cmd); |