Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: lpfc: devloss timeout race condition caused null pointer reference

A race condition between the context of devloss timeout handler and I/O
completion caused devloss timeout handler de-referencing pointer that had
been released.

Added the check in lpfc_sli_validate_fcp_iocb() on LPFC_IO_ON_TXCMPLQ to
capture the race condition of I/O completion and devloss timeout handler
attemption for aborting the I/O. Also, added check on lpfc_cmd->rdata
pointer before de-referenceing lpfc_cmd->rdata->pnode.

Also, added protection in lpfc_sli_abort_iocb() routine on driver performed
FCP I/O FLUSHING already under way before proceeding to aborting I/Os.

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>

authored by

James Smart and committed by
Martin K. Petersen
b0e83012 6871e814

+14 -4
+5
drivers/scsi/lpfc/lpfc_scsi.c
··· 4538 4538 int err; 4539 4539 4540 4540 rdata = lpfc_rport_data_from_scsi_device(cmnd->device); 4541 + 4542 + /* sanity check on references */ 4543 + if (unlikely(!rdata) || unlikely(!rport)) 4544 + goto out_fail_command; 4545 + 4541 4546 err = fc_remote_port_chkready(rport); 4542 4547 if (err) { 4543 4548 cmnd->result = err;
+9 -4
drivers/scsi/lpfc/lpfc_sli.c
··· 11091 11091 struct lpfc_scsi_buf *lpfc_cmd; 11092 11092 int rc = 1; 11093 11093 11094 - if (!(iocbq->iocb_flag & LPFC_IO_FCP)) 11094 + if (iocbq->vport != vport) 11095 11095 return rc; 11096 11096 11097 - if (iocbq->vport != vport) 11097 + if (!(iocbq->iocb_flag & LPFC_IO_FCP) || 11098 + !(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ)) 11098 11099 return rc; 11099 11100 11100 11101 lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq); ··· 11105 11104 11106 11105 switch (ctx_cmd) { 11107 11106 case LPFC_CTX_LUN: 11108 - if ((lpfc_cmd->rdata->pnode) && 11107 + if ((lpfc_cmd->rdata) && (lpfc_cmd->rdata->pnode) && 11109 11108 (lpfc_cmd->rdata->pnode->nlp_sid == tgt_id) && 11110 11109 (scsilun_to_int(&lpfc_cmd->fcp_cmnd->fcp_lun) == lun_id)) 11111 11110 rc = 0; 11112 11111 break; 11113 11112 case LPFC_CTX_TGT: 11114 - if ((lpfc_cmd->rdata->pnode) && 11113 + if ((lpfc_cmd->rdata) && (lpfc_cmd->rdata->pnode) && 11115 11114 (lpfc_cmd->rdata->pnode->nlp_sid == tgt_id)) 11116 11115 rc = 0; 11117 11116 break; ··· 11225 11224 IOCB_t *cmd = NULL; 11226 11225 int errcnt = 0, ret_val = 0; 11227 11226 int i; 11227 + 11228 + /* all I/Os are in process of being flushed */ 11229 + if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) 11230 + return errcnt; 11228 11231 11229 11232 for (i = 1; i <= phba->sli.last_iotag; i++) { 11230 11233 iocbq = phba->sli.iocbq_lookup[i];