diff options
Diffstat (limited to 'net/sunrpc/svcsock.c')
| -rw-r--r-- | net/sunrpc/svcsock.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 7be3de1a1aed..eb747493db82 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -471,6 +471,7 @@ static void svc_tcp_handshake_done(void *data, int status, key_serial_t peerid) } clear_bit(XPT_HANDSHAKE, &xprt->xpt_flags); complete_all(&svsk->sk_handshake_done); + svc_xprt_put(xprt); } /** @@ -494,9 +495,13 @@ static void svc_tcp_handshake(struct svc_xprt *xprt) clear_bit(XPT_TLS_SESSION, &xprt->xpt_flags); init_completion(&svsk->sk_handshake_done); + /* Pin the transport across the asynchronous handshake callback. */ + svc_xprt_get(xprt); + ret = tls_server_hello_x509(&args, GFP_KERNEL); if (ret) { trace_svc_tls_not_started(xprt); + svc_xprt_put(xprt); goto out_failed; } @@ -505,8 +510,13 @@ static void svc_tcp_handshake(struct svc_xprt *xprt) if (ret <= 0) { if (tls_handshake_cancel(sk)) { trace_svc_tls_timed_out(xprt); + svc_xprt_put(xprt); goto out_close; } + /* Cancellation lost to handshake_complete(): the + * callback is in flight and should finish quickly. + */ + wait_for_completion(&svsk->sk_handshake_done); } if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags)) { |
