xprtrdma: Reply buffer exhaustion can be catastrophic
authorChuck Lever <chuck.lever@oracle.com>
Wed, 29 Jun 2016 17:53:35 +0000 (13:53 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Mon, 11 Jul 2016 19:50:43 +0000 (15:50 -0400)
Not having an rpcrdma_rep at call_allocate time can be a problem.
It means that send_request can't post a receive buffer to catch
the RPC's reply. Possible consequences are RPC timeouts or even
transport deadlock.

Instead of allowing an RPC to proceed if an rpcrdma_rep is
not available, return NULL to force call_allocate to wait and
try again.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Tested-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
net/sunrpc/xprtrdma/verbs.c

index cd4c5f1d554a9fcacab2256a5ef3b289bbaa7fd5..6fb73ff2618385ab8d7b5ef61739c17062b13456 100644 (file)
@@ -871,7 +871,7 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
        }
 
        INIT_LIST_HEAD(&buf->rb_recv_bufs);
-       for (i = 0; i < buf->rb_max_requests + 2; i++) {
+       for (i = 0; i < buf->rb_max_requests; i++) {
                struct rpcrdma_rep *rep;
 
                rep = rpcrdma_create_rep(r_xprt);
@@ -989,8 +989,6 @@ rpcrdma_put_mw(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mw *mw)
 
 /*
  * Get a set of request/reply buffers.
- *
- * Reply buffer (if available) is attached to send buffer upon return.
  */
 struct rpcrdma_req *
 rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
@@ -1009,13 +1007,13 @@ rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
 
 out_reqbuf:
        spin_unlock(&buffers->rb_lock);
-       pr_warn("RPC:       %s: out of request buffers\n", __func__);
+       pr_warn("rpcrdma: out of request buffers (%p)\n", buffers);
        return NULL;
 out_repbuf:
+       list_add(&req->rl_free, &buffers->rb_send_bufs);
        spin_unlock(&buffers->rb_lock);
-       pr_warn("RPC:       %s: out of reply buffers\n", __func__);
-       req->rl_reply = NULL;
-       return req;
+       pr_warn("rpcrdma: out of reply buffers (%p)\n", buffers);
+       return NULL;
 }
 
 /*