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.kenn...@broadcom.com>
Signed-off-by: James Smart <jsmart2...@gmail.com>
---
 drivers/scsi/lpfc/lpfc_nvmet.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c
index c9011579aa0f..3a11861b7ad6 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.c
+++ b/drivers/scsi/lpfc/lpfc_nvmet.c
@@ -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;
-- 
2.13.7

Reply via email to