diff mbox series

[rdma-core,4/4] bnxt_re/lib: Fix flush list processing during poll_cq

Message ID 1537463314-7807-5-git-send-email-devesh.sharma@broadcom.com (mailing list archive)
State Changes Requested
Headers show
Series libnxt_re bug fixes | expand

Commit Message

Devesh Sharma Sept. 20, 2018, 5:08 p.m. UTC
From: Selvin Xavier <selvin.xavier@broadcom.com>

During flush list processing as a part of poll_cq, the budget
is not calculated correctly according to the number of polled
completions. Work completion structure pointers are incremented
each time but budget is not decremented correspondingly. So,
library might end up polling more than the budget. Since the
caller would have wc structures list with number of entries
equal to the budget, completing more than budget can cause
segmentation fault in libbnxt_re.

Reorganized the code to have a common subroutine to poll from a
given flush-list.

Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: Somnath Kotur <somnath.kotur@broadcom.com>
Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com>
---
 providers/bnxt_re/verbs.c | 76 +++++++++++++++++++++++++++++------------------
 1 file changed, 47 insertions(+), 29 deletions(-)
diff mbox series

Patch

diff --git a/providers/bnxt_re/verbs.c b/providers/bnxt_re/verbs.c
index 570dfc1..39b29b0 100644
--- a/providers/bnxt_re/verbs.c
+++ b/providers/bnxt_re/verbs.c
@@ -630,46 +630,64 @@  static int bnxt_re_poll_flush_wcs(struct bnxt_re_queue *que,
 	return cnt;
 }
 
-static int bnxt_re_poll_flush_lists(struct bnxt_re_cq *cq, uint32_t nwc,
-				    struct ibv_wc *ibvwc)
+static int bnxt_re_poll_flush_wqes(struct bnxt_re_cq *cq,
+				   struct list_head *lhead,
+				   struct ibv_wc *ibvwc,
+				   int32_t nwc)
 {
 	struct bnxt_re_fque_node *cur, *tmp;
-	struct bnxt_re_qp *qp;
+	struct bnxt_re_wrid *wridp;
 	struct bnxt_re_queue *que;
-	int dqed = 0, left;
+	struct bnxt_re_qp *qp;
+	bool sq_list = false;
+	uint32_t polled = 0;
+
+	sq_list = (lhead == &cq->sfhead) ? true : false;
+	if (!list_empty(lhead)) {
+		list_for_each_safe(lhead, cur, tmp, list) {
+			if (sq_list) {
+				qp = container_of(cur, struct bnxt_re_qp,
+						  snode);
+				que = qp->sqq;
+				wridp = qp->swrid;
+			} else {
+				qp = container_of(cur, struct bnxt_re_qp,
+						  rnode);
+				que = qp->rqq;
+				wridp = qp->rwrid;
+			}
+			if (bnxt_re_is_que_empty(que))
+				continue;
+			polled += bnxt_re_poll_flush_wcs(que, wridp,
+							 ibvwc + polled,
+							 qp->qpid,
+							 nwc - polled);
+			if (!(nwc - polled))
+				break;
+		}
+	}
+
+	return polled;
+}
+
+static int bnxt_re_poll_flush_lists(struct bnxt_re_cq *cq, uint32_t nwc,
+				    struct ibv_wc *ibvwc)
+{
+	int left, polled = 0;
 
 	/* Check if flush Qs are empty */
 	if (list_empty(&cq->sfhead) && list_empty(&cq->rfhead))
 		return 0;
 
-	if (!list_empty(&cq->sfhead)) {
-		list_for_each_safe(&cq->sfhead, cur, tmp, list) {
-			qp = container_of(cur, struct bnxt_re_qp, snode);
-			que = qp->sqq;
-			if (bnxt_re_is_que_empty(que))
-				continue;
-			dqed = bnxt_re_poll_flush_wcs(que, qp->swrid, ibvwc,
-						      qp->qpid, nwc);
-		}
-	}
+	polled  = bnxt_re_poll_flush_wqes(cq, &cq->sfhead, ibvwc, nwc);
+	left = nwc - polled;
 
-	left = nwc - dqed;
 	if (!left)
-		return dqed;
-
-	if (!list_empty(&cq->rfhead)) {
-		list_for_each_safe(&cq->rfhead, cur, tmp, list) {
-			qp = container_of(cur, struct bnxt_re_qp, rnode);
-			que = qp->rqq;
-			if (!que || bnxt_re_is_que_empty(que))
-				continue;
-			dqed += bnxt_re_poll_flush_wcs(que, qp->rwrid,
-						       ibvwc + dqed, qp->qpid,
-						       left);
-		}
-	}
+		return polled;
 
-	return dqed;
+	polled  += bnxt_re_poll_flush_wqes(cq, &cq->rfhead,
+			ibvwc + polled, left);
+	return polled;
 }
 
 int bnxt_re_poll_cq(struct ibv_cq *ibvcq, int nwc, struct ibv_wc *wc)