]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
xprtrdma: Fix cwnd update ordering
authorChuck Lever <chuck.lever@oracle.com>
Mon, 19 Apr 2021 18:02:41 +0000 (14:02 -0400)
committerStefan Bader <stefan.bader@canonical.com>
Fri, 18 Jun 2021 09:07:16 +0000 (11:07 +0200)
BugLink: https://bugs.launchpad.net/bugs/1931292
[ 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>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtrdma/xprt_rdma.h

index 8f5d0cb683609901bd7f8eac80ad80df76f5a1d8..d40ace8a973d9f297f3f1e9dd64a4b66e0c65071 100644 (file)
@@ -1459,9 +1459,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 (unlikely(req->rl_reply))
index ec912cf9c618c31fc9cf27959760f06d2bc977c7..f3fffc74ab0fa2983744b0d425a2803599c39de0 100644 (file)
@@ -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)
@@ -1364,21 +1364,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;
index 94b28657aeeb829c52c62bcf2e1e6d34e3d0987e..c3bcc84c16c4cf67de1984766051834f3b9a4a64 100644 (file)
@@ -460,7 +460,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