scsi: lpfc: Correct nvmet buffer free race condition

A race condition resulted in receive buffers being placed in the free list
twice.

Change the locking and handling to check whether the "other" path will be
freeing the entry in a later thread and skip it if it is.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
James Smart 2019-05-21 17:48:53 -07:00 коммит произвёл Martin K. Petersen
Родитель 32b9386564
Коммит 4767c58af9
1 изменённых файлов: 14 добавлений и 7 удалений

Просмотреть файл

@ -343,16 +343,23 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
}
if (ctxp->rqb_buffer) {
nvmebuf = ctxp->rqb_buffer;
spin_lock_irqsave(&ctxp->ctxlock, iflag);
ctxp->rqb_buffer = NULL;
if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) {
ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ;
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
nvmebuf = ctxp->rqb_buffer;
/* check if freed in another path whilst acquiring lock */
if (nvmebuf) {
ctxp->rqb_buffer = NULL;
if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) {
ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ;
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
nvmebuf->hrq->rqbp->rqb_free_buffer(phba,
nvmebuf);
} else {
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
/* repost */
lpfc_rq_buf_free(phba, &nvmebuf->hbuf);
}
} else {
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */
}
}
ctxp->state = LPFC_NVMET_STE_FREE;