cxgbe(4): Fix a couple of problems in the sge_wrq data path.

- start_wrq_wr must not drain the wr_list if there are incomplete_wrs
  pending.  This can happen when a t4_wrq_tx runs between two
  start_wrq_wr.

- commit_wrq_wr must examine the cookie's pidx and ndesc with the
  queue's lock held.  Otherwise there is a bad race when incomplete WRs
  are being completed and commit_wrq_wr for the WR that is ahead in the
  queue updates the next incomplete WR's cookie's pidx/ndesc but the
  commit_wrq_wr for the second one is using stale values that it read
  without the lock.

MFC after:	1 week
Sponsored by:	Chelsio Communications
This commit is contained in:
np 2017-09-09 05:12:14 +00:00
parent 9467c0e4be
commit 5f42964041

View File

@ -2354,7 +2354,7 @@ start_wrq_wr(struct sge_wrq *wrq, int len16, struct wrq_cookie *cookie)
EQ_LOCK(eq);
if (!STAILQ_EMPTY(&wrq->wr_list))
if (TAILQ_EMPTY(&wrq->incomplete_wrs) && !STAILQ_EMPTY(&wrq->wr_list))
drain_wrq_wr_list(sc, wrq);
if (!STAILQ_EMPTY(&wrq->wr_list)) {
@ -2408,9 +2408,6 @@ commit_wrq_wr(struct sge_wrq *wrq, void *w, struct wrq_cookie *cookie)
return;
}
ndesc = cookie->ndesc; /* Can be more than SGE_MAX_WR_NDESC here. */
pidx = cookie->pidx;
MPASS(pidx >= 0 && pidx < eq->sidx);
if (__predict_false(w == &wrq->ss[0])) {
int n = (eq->sidx - wrq->ss_pidx) * EQ_ESIZE;
@ -2422,6 +2419,9 @@ commit_wrq_wr(struct sge_wrq *wrq, void *w, struct wrq_cookie *cookie)
wrq->tx_wrs_direct++;
EQ_LOCK(eq);
ndesc = cookie->ndesc; /* Can be more than SGE_MAX_WR_NDESC here. */
pidx = cookie->pidx;
MPASS(pidx >= 0 && pidx < eq->sidx);
prev = TAILQ_PREV(cookie, wrq_incomplete_wrs, link);
next = TAILQ_NEXT(cookie, link);
if (prev == NULL) {