be2iscsi: Fix WRB leak in login/logout path
authorJitendra Bhivare <jitendra.bhivare@avagotech.com>
Wed, 20 Jan 2016 08:41:00 +0000 (14:11 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 24 Feb 2016 02:27:02 +0000 (21:27 -0500)
Login/Logout loop was hanging after few hours. /var/log/message showed
that alloc_wrb_handle() function was not able to allocate any new WRB.

Sep 11 11:25:22 Jhelum10 kernel: connection32513:0: Could not send nopout
Sep 11 11:25:22 Jhelum10 kernel: scsi host10: BM_4989 : Alloc of WRB_HANDLE
Failed for the CID : 384
Sep 11 11:25:22 Jhelum10 kernel: connection32513:0: Could not allocate pdu for
mgmt task.

Driver allocates WRB to pass login negotiated parameters information to FW
in beiscsi_offload_connection(). This allocated WRB was not freed so there
was WRB_Leak happening.

Put WRB used for posting the login-negotiated parameters back in pool.

Signed-off-by: Jitendra Bhivare <jitendra.bhivare@avagotech.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/be2iscsi/be_main.c

index 9c3a7b2421c8d9aed5051f71c76d41e031157d21..2f58772d4e0b56226e192e95eb33a5ac991434c8 100644 (file)
@@ -1180,6 +1180,22 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
                phba->io_sgl_free_index++;
 }
 
+static inline struct wrb_handle *
+beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context,
+                      unsigned int wrbs_per_cxn)
+{
+       struct wrb_handle *pwrb_handle;
+
+       pwrb_handle = pwrb_context->pwrb_handle_base[pwrb_context->alloc_index];
+       pwrb_context->wrb_handles_available--;
+       if (pwrb_context->alloc_index == (wrbs_per_cxn - 1))
+               pwrb_context->alloc_index = 0;
+       else
+               pwrb_context->alloc_index++;
+
+       return pwrb_handle;
+}
+
 /**
  * alloc_wrb_handle - To allocate a wrb handle
  * @phba: The hba pointer
@@ -1189,30 +1205,30 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
  * This happens under session_lock until submission to chip
  */
 struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
-                                    struct hwi_wrb_context **pcontext)
+                                   struct hwi_wrb_context **pcontext)
 {
        struct hwi_wrb_context *pwrb_context;
        struct hwi_controller *phwi_ctrlr;
-       struct wrb_handle *pwrb_handle;
        uint16_t cri_index = BE_GET_CRI_FROM_CID(cid);
 
        phwi_ctrlr = phba->phwi_ctrlr;
        pwrb_context = &phwi_ctrlr->wrb_context[cri_index];
-       if (pwrb_context->wrb_handles_available >= 2) {
-               pwrb_handle = pwrb_context->pwrb_handle_base[
-                                           pwrb_context->alloc_index];
-               pwrb_context->wrb_handles_available--;
-               if (pwrb_context->alloc_index ==
-                                               (phba->params.wrbs_per_cxn - 1))
-                       pwrb_context->alloc_index = 0;
-               else
-                       pwrb_context->alloc_index++;
+       /* return the context address */
+       *pcontext = pwrb_context;
+       return beiscsi_get_wrb_handle(pwrb_context, phba->params.wrbs_per_cxn);
+}
 
-               /* Return the context address */
-               *pcontext = pwrb_context;
-       } else
-               pwrb_handle = NULL;
-       return pwrb_handle;
+static inline void
+beiscsi_put_wrb_handle(struct hwi_wrb_context *pwrb_context,
+                      struct wrb_handle *pwrb_handle,
+                      unsigned int wrbs_per_cxn)
+{
+       pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle;
+       pwrb_context->wrb_handles_available++;
+       if (pwrb_context->free_index == (wrbs_per_cxn - 1))
+               pwrb_context->free_index = 0;
+       else
+               pwrb_context->free_index++;
 }
 
 /**
@@ -1227,13 +1243,9 @@ static void
 free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context,
                struct wrb_handle *pwrb_handle)
 {
-       pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle;
-       pwrb_context->wrb_handles_available++;
-       if (pwrb_context->free_index == (phba->params.wrbs_per_cxn - 1))
-               pwrb_context->free_index = 0;
-       else
-               pwrb_context->free_index++;
-
+       beiscsi_put_wrb_handle(pwrb_context,
+                              pwrb_handle,
+                              phba->params.wrbs_per_cxn);
        beiscsi_log(phba, KERN_INFO,
                    BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
                    "BM_%d : FREE WRB: pwrb_handle=%p free_index=0x%x"
@@ -4711,6 +4723,20 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
        doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
        iowrite32(doorbell, phba->db_va +
                  beiscsi_conn->doorbell_offset);
+
+       /*
+        * There is no completion for CONTEXT_UPDATE. The completion of next
+        * WRB posted guarantees FW's processing and DMA'ing of it.
+        * Use beiscsi_put_wrb_handle to put it back in the pool which makes
+        * sure zero'ing or reuse of the WRB only after wrbs_per_cxn.
+        */
+       beiscsi_put_wrb_handle(pwrb_context, pwrb_handle,
+                              phba->params.wrbs_per_cxn);
+       beiscsi_log(phba, KERN_INFO,
+                   BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
+                   "BM_%d : put CONTEXT_UPDATE pwrb_handle=%p free_index=0x%x wrb_handles_available=%d\n",
+                   pwrb_handle, pwrb_context->free_index,
+                   pwrb_context->wrb_handles_available);
 }
 
 static void beiscsi_parse_pdu(struct iscsi_conn *conn, itt_t itt,