RDMA/rxe: Fix a race condition in rxe_requester()
authorBart Van Assche <bart.vanassche@wdc.com>
Fri, 12 Jan 2018 23:11:58 +0000 (15:11 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 Feb 2018 14:42:15 +0000 (15:42 +0100)
commit 65567e41219888feec72fee1de98ccf1efbbc16d upstream.

The rxe driver works as follows:
* The send queue, receive queue and completion queues are implemented as
  circular buffers.
* ib_post_send() and ib_post_recv() calls are serialized through a spinlock.
* Removing elements from various queues happens from tasklet
  context. Tasklets are guaranteed to run on at most one CPU. This serializes
  access to these queues. See also rxe_completer(), rxe_requester() and
  rxe_responder().
* rxe_completer() processes the skbs queued onto qp->resp_pkts.
* rxe_requester() handles the send queue (qp->sq.queue).
* rxe_responder() processes the skbs queued onto qp->req_pkts.

Since rxe_drain_req_pkts() processes qp->req_pkts, calling
rxe_drain_req_pkts() from rxe_requester() is racy. Hence this patch.

Reported-by: Moni Shoua <monis@mellanox.com>
Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
Cc: stable@vger.kernel.org
Signed-off-by: Doug Ledford <dledford@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/infiniband/sw/rxe/rxe_loc.h
drivers/infiniband/sw/rxe/rxe_req.c
drivers/infiniband/sw/rxe/rxe_resp.c

index 77b3ed0df93637a236cf33a02e0f303df5f4e09f..7f945f65d8cd249371b4083a6119a50638e68c88 100644 (file)
@@ -237,7 +237,6 @@ int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
 
 void rxe_release(struct kref *kref);
 
-void rxe_drain_req_pkts(struct rxe_qp *qp, bool notify);
 int rxe_completer(void *arg);
 int rxe_requester(void *arg);
 int rxe_responder(void *arg);
index d84222f9d5d2ed11356c4a3399e311a7c5364e5f..44b838ec9420dc6aabc0a52a9277bdd1840c41a1 100644 (file)
@@ -594,15 +594,8 @@ int rxe_requester(void *arg)
        rxe_add_ref(qp);
 
 next_wqe:
-       if (unlikely(!qp->valid)) {
-               rxe_drain_req_pkts(qp, true);
+       if (unlikely(!qp->valid || qp->req.state == QP_STATE_ERROR))
                goto exit;
-       }
-
-       if (unlikely(qp->req.state == QP_STATE_ERROR)) {
-               rxe_drain_req_pkts(qp, true);
-               goto exit;
-       }
 
        if (unlikely(qp->req.state == QP_STATE_RESET)) {
                qp->req.wqe_index = consumer_index(qp->sq.queue);
index 4240866a5331921f887ffc351d1b385c4aea5760..01f926fd90296e7bbbfcf9da191299bcf39e5146 100644 (file)
@@ -1210,7 +1210,7 @@ static enum resp_states do_class_d1e_error(struct rxe_qp *qp)
        }
 }
 
-void rxe_drain_req_pkts(struct rxe_qp *qp, bool notify)
+static void rxe_drain_req_pkts(struct rxe_qp *qp, bool notify)
 {
        struct sk_buff *skb;