]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
SUNRPC/xprtrdma: Fix reconnection locking
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 26 Jul 2021 12:03:12 +0000 (08:03 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 18 Sep 2021 11:41:53 +0000 (13:41 +0200)
[ Upstream commit f99fa50880f5300fbbb3c0754ddc7f8738d24fe7 ]

The xprtrdma client code currently relies on the task that initiated the
connect to hold the XPRT_LOCK for the duration of the connection
attempt. If the task is woken early, due to some other event, then that
lock could get released early.
Avoid races by using the same mechanism that the socket code uses of
transferring lock ownership to the RDMA connect worker itself. That
frees us to call rpcrdma_xprt_disconnect() directly since we're now
guaranteed exclusion w.r.t. other callers.

Fixes: 4cf44be6f1e8 ("xprtrdma: Fix recursion into rpcrdma_xprt_disconnect()")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/transport.c

index 19fa8616b8cf57f75a2e542f3c6b8d35aae2bc01..8d3983c8b4d60698ed514f0bfea9032a2a6b1c71 100644 (file)
@@ -872,6 +872,7 @@ out:
        spin_unlock(&xprt->transport_lock);
        return ret;
 }
+EXPORT_SYMBOL_GPL(xprt_lock_connect);
 
 void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
 {
@@ -888,6 +889,7 @@ out:
        spin_unlock(&xprt->transport_lock);
        wake_up_bit(&xprt->state, XPRT_LOCKED);
 }
+EXPORT_SYMBOL_GPL(xprt_unlock_connect);
 
 /**
  * xprt_connect - schedule a transport connect operation
index 19a49d26b1e41063e85fde128f1c555325cb382b..d2052f06acfaedc2547a87425478da91f8e3a836 100644 (file)
@@ -249,12 +249,9 @@ xprt_rdma_connect_worker(struct work_struct *work)
                                           xprt->stat.connect_start;
                xprt_set_connected(xprt);
                rc = -EAGAIN;
-       } else {
-               /* Force a call to xprt_rdma_close to clean up */
-               spin_lock(&xprt->transport_lock);
-               set_bit(XPRT_CLOSE_WAIT, &xprt->state);
-               spin_unlock(&xprt->transport_lock);
-       }
+       } else
+               rpcrdma_xprt_disconnect(r_xprt);
+       xprt_unlock_connect(xprt, r_xprt);
        xprt_wake_pending_tasks(xprt, rc);
 }
 
@@ -487,6 +484,8 @@ xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task)
        struct rpcrdma_ep *ep = r_xprt->rx_ep;
        unsigned long delay;
 
+       WARN_ON_ONCE(!xprt_lock_connect(xprt, task, r_xprt));
+
        delay = 0;
        if (ep && ep->re_connect_status != 0) {
                delay = xprt_reconnect_delay(xprt);