xprtrdma: Do not refresh Receive Queue while it is draining
[linux-2.6-microblaze.git] / net / sunrpc / xprtrdma / verbs.c
index ec912cf..d8ed694 100644 (file)
@@ -101,6 +101,12 @@ static void rpcrdma_xprt_drain(struct rpcrdma_xprt *r_xprt)
        struct rpcrdma_ep *ep = r_xprt->rx_ep;
        struct rdma_cm_id *id = ep->re_id;
 
+       /* Wait for rpcrdma_post_recvs() to leave its critical
+        * section.
+        */
+       if (atomic_inc_return(&ep->re_receiving) > 1)
+               wait_for_completion(&ep->re_done);
+
        /* Flush Receives, then wait for deferred Reply work
         * to complete.
         */
@@ -414,6 +420,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
        __module_get(THIS_MODULE);
        device = id->device;
        ep->re_id = id;
+       reinit_completion(&ep->re_done);
 
        ep->re_max_requests = r_xprt->rx_xprt.max_reqs;
        ep->re_inline_send = xprt_rdma_max_inline_write;
@@ -1385,6 +1392,9 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp)
        if (!temp)
                needed += RPCRDMA_MAX_RECV_BATCH;
 
+       if (atomic_inc_return(&ep->re_receiving) > 1)
+               goto out;
+
        /* fast path: all needed reps can be found on the free list */
        wr = NULL;
        while (needed) {
@@ -1410,6 +1420,9 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp)
 
        rc = ib_post_recv(ep->re_id->qp, wr,
                          (const struct ib_recv_wr **)&bad_wr);
+       if (atomic_dec_return(&ep->re_receiving) > 0)
+               complete(&ep->re_done);
+
 out:
        trace_xprtrdma_post_recvs(r_xprt, count, rc);
        if (rc) {