Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe315e76 authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust
Browse files

SUNRPC: Avoid spurious wake-up during UDP connect processing



To clear out old state, the UDP connect workers unconditionally invoke
xs_close() before proceeding with a new connect.  Nowadays this causes
a spurious wake-up of the task waiting for the connect to complete.

This is a little racey, but usually harmless.  The waiting task
immediately retries the connect via a call_bind/call_connect sequence,
which usually finds the transport already in the connected state
because the connect worker has finished in the background.

To avoid a spurious wake-up, factor the xs_close() logic that resets
the underlying socket into a helper, and have the UDP connect workers
call that helper instead of xs_close().

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 01d37c42
Loading
Loading
Loading
Loading
+26 −18
Original line number Diff line number Diff line
@@ -767,23 +767,13 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s
	sk->sk_error_report = transport->old_error_report;
}

/**
 * xs_close - close a socket
 * @xprt: transport
 *
 * This is used when all requests are complete; ie, no DRC state remains
 * on the server we want to save.
 */
static void xs_close(struct rpc_xprt *xprt)
static void xs_reset_transport(struct sock_xprt *transport)
{
	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
	struct socket *sock = transport->sock;
	struct sock *sk = transport->inet;

	if (!sk)
		goto clear_close_wait;

	dprintk("RPC:       xs_close xprt %p\n", xprt);
	if (sk == NULL)
		return;

	write_lock_bh(&sk->sk_callback_lock);
	transport->inet = NULL;
@@ -797,7 +787,23 @@ static void xs_close(struct rpc_xprt *xprt)
	sk->sk_no_check = 0;

	sock_release(sock);
clear_close_wait:
}

/**
 * xs_close - close a socket
 * @xprt: transport
 *
 * This is used when all requests are complete; ie, no DRC state remains
 * on the server we want to save.
 */
static void xs_close(struct rpc_xprt *xprt)
{
	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);

	dprintk("RPC:       xs_close xprt %p\n", xprt);

	xs_reset_transport(transport);

	smp_mb__before_clear_bit();
	clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
	clear_bit(XPRT_CLOSING, &xprt->state);
@@ -1537,9 +1543,10 @@ static void xs_udp_connect_worker4(struct work_struct *work)
		goto out;

	/* Start by resetting any existing state */
	xs_close(xprt);
	xs_reset_transport(transport);

	if ((err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
	err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
	if (err < 0) {
		dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
		goto out;
	}
@@ -1578,9 +1585,10 @@ static void xs_udp_connect_worker6(struct work_struct *work)
		goto out;

	/* Start by resetting any existing state */
	xs_close(xprt);
	xs_reset_transport(transport);

	if ((err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
	err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock);
	if (err < 0) {
		dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
		goto out;
	}