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

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: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 32b93865
......@@ -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;
......
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