| From 57e45b5515f283a7bb04afde27170529247a3a6a Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 19 Apr 2021 14:02:41 -0400 |
| Subject: xprtrdma: Fix cwnd update ordering |
| |
| From: Chuck Lever <chuck.lever@oracle.com> |
| |
| [ Upstream commit 35d8b10a25884050bb3b0149b62c3818ec59f77c ] |
| |
| After a reconnect, the reply handler is opening the cwnd (and thus |
| enabling more RPC Calls to be sent) /before/ rpcrdma_post_recvs() |
| can post enough Receive WRs to receive their replies. This causes an |
| RNR and the new connection is lost immediately. |
| |
| The race is most clearly exposed when KASAN and disconnect injection |
| are enabled. This slows down rpcrdma_rep_create() enough to allow |
| the send side to post a bunch of RPC Calls before the Receive |
| completion handler can invoke ib_post_recv(). |
| |
| Fixes: 2ae50ad68cd7 ("xprtrdma: Close window between waking RPC senders and posting Receives") |
| Signed-off-by: Chuck Lever <chuck.lever@oracle.com> |
| Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/sunrpc/xprtrdma/rpc_rdma.c | 3 ++- |
| net/sunrpc/xprtrdma/verbs.c | 10 +++++----- |
| net/sunrpc/xprtrdma/xprt_rdma.h | 2 +- |
| 3 files changed, 8 insertions(+), 7 deletions(-) |
| |
| diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c |
| index c48536f2121f..ca267a855a12 100644 |
| --- a/net/sunrpc/xprtrdma/rpc_rdma.c |
| +++ b/net/sunrpc/xprtrdma/rpc_rdma.c |
| @@ -1467,9 +1467,10 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep) |
| credits = 1; /* don't deadlock */ |
| else if (credits > r_xprt->rx_ep->re_max_requests) |
| credits = r_xprt->rx_ep->re_max_requests; |
| + rpcrdma_post_recvs(r_xprt, credits + (buf->rb_bc_srv_max_requests << 1), |
| + false); |
| if (buf->rb_credits != credits) |
| rpcrdma_update_cwnd(r_xprt, credits); |
| - rpcrdma_post_recvs(r_xprt, false); |
| |
| req = rpcr_to_rdmar(rqst); |
| if (req->rl_reply) { |
| diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c |
| index ad6e2e4994ce..04325f0267c1 100644 |
| --- a/net/sunrpc/xprtrdma/verbs.c |
| +++ b/net/sunrpc/xprtrdma/verbs.c |
| @@ -535,7 +535,7 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt) |
| * outstanding Receives. |
| */ |
| rpcrdma_ep_get(ep); |
| - rpcrdma_post_recvs(r_xprt, true); |
| + rpcrdma_post_recvs(r_xprt, 1, true); |
| |
| rc = rdma_connect(ep->re_id, &ep->re_remote_cma); |
| if (rc) |
| @@ -1377,21 +1377,21 @@ int rpcrdma_post_sends(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) |
| /** |
| * rpcrdma_post_recvs - Refill the Receive Queue |
| * @r_xprt: controlling transport instance |
| - * @temp: mark Receive buffers to be deleted after use |
| + * @needed: current credit grant |
| + * @temp: mark Receive buffers to be deleted after one use |
| * |
| */ |
| -void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp) |
| +void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp) |
| { |
| struct rpcrdma_buffer *buf = &r_xprt->rx_buf; |
| struct rpcrdma_ep *ep = r_xprt->rx_ep; |
| struct ib_recv_wr *wr, *bad_wr; |
| struct rpcrdma_rep *rep; |
| - int needed, count, rc; |
| + int count, rc; |
| |
| rc = 0; |
| count = 0; |
| |
| - needed = buf->rb_credits + (buf->rb_bc_srv_max_requests << 1); |
| if (likely(ep->re_receive_count > needed)) |
| goto out; |
| needed -= ep->re_receive_count; |
| diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h |
| index 43974ef39a50..3cacc6f4c527 100644 |
| --- a/net/sunrpc/xprtrdma/xprt_rdma.h |
| +++ b/net/sunrpc/xprtrdma/xprt_rdma.h |
| @@ -452,7 +452,7 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt); |
| void rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt); |
| |
| int rpcrdma_post_sends(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req); |
| -void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp); |
| +void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp); |
| |
| /* |
| * Buffer calls - xprtrdma/verbs.c |
| -- |
| 2.30.2 |
| |