Commit 8c9dff1e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client bugfixes from Trond Myklebust:

 - Fix TCP socket disconnection races by ensuring we always call
   xprt_disconnect_done() after releasing the socket.

 - Fix a race when clearing both XPRT_CONNECTING and XPRT_LOCKED

 - Remove xprt_connect_status() so it does not mask errors that should
   be handled by call_connect_status()

* tag 'nfs-for-4.20-6' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  SUNRPC: Remove xprt_connect_status()
  SUNRPC: Fix a race with XPRT_CONNECTING
  SUNRPC: Fix disconnection races
parents fe112793 abc13275
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1952,6 +1952,7 @@ call_connect_status(struct rpc_task *task)
		/* retry with existing socket, after a delay */
		rpc_delay(task, 3*HZ);
		/* fall through */
	case -ENOTCONN:
	case -EAGAIN:
		/* Check for timeouts before looping back to call_bind */
	case -ETIMEDOUT:
+4 −31
Original line number Diff line number Diff line
@@ -67,7 +67,6 @@
 */
static void	 xprt_init(struct rpc_xprt *xprt, struct net *net);
static __be32	xprt_alloc_xid(struct rpc_xprt *xprt);
static void	xprt_connect_status(struct rpc_task *task);
static void	 xprt_destroy(struct rpc_xprt *xprt);

static DEFINE_SPINLOCK(xprt_list_lock);
@@ -680,7 +679,9 @@ void xprt_force_disconnect(struct rpc_xprt *xprt)
	/* Try to schedule an autoclose RPC call */
	if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
		queue_work(xprtiod_workqueue, &xprt->task_cleanup);
	xprt_wake_pending_tasks(xprt, -EAGAIN);
	else if (xprt->snd_task)
		rpc_wake_up_queued_task_set_status(&xprt->pending,
				xprt->snd_task, -ENOTCONN);
	spin_unlock_bh(&xprt->transport_lock);
}
EXPORT_SYMBOL_GPL(xprt_force_disconnect);
@@ -820,7 +821,7 @@ void xprt_connect(struct rpc_task *task)
	if (!xprt_connected(xprt)) {
		task->tk_timeout = task->tk_rqstp->rq_timeout;
		task->tk_rqstp->rq_connect_cookie = xprt->connect_cookie;
		rpc_sleep_on(&xprt->pending, task, xprt_connect_status);
		rpc_sleep_on(&xprt->pending, task, NULL);

		if (test_bit(XPRT_CLOSING, &xprt->state))
			return;
@@ -839,34 +840,6 @@ void xprt_connect(struct rpc_task *task)
	xprt_release_write(xprt, task);
}

static void xprt_connect_status(struct rpc_task *task)
{
	switch (task->tk_status) {
	case 0:
		dprintk("RPC: %5u xprt_connect_status: connection established\n",
				task->tk_pid);
		break;
	case -ECONNREFUSED:
	case -ECONNRESET:
	case -ECONNABORTED:
	case -ENETUNREACH:
	case -EHOSTUNREACH:
	case -EPIPE:
	case -EAGAIN:
		dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
		break;
	case -ETIMEDOUT:
		dprintk("RPC: %5u xprt_connect_status: connect attempt timed "
				"out\n", task->tk_pid);
		break;
	default:
		dprintk("RPC: %5u xprt_connect_status: error %d connecting to "
				"server %s\n", task->tk_pid, -task->tk_status,
				task->tk_rqstp->rq_xprt->servername);
		task->tk_status = -EIO;
	}
}

enum xprt_xid_rb_cmp {
	XID_RB_EQUAL,
	XID_RB_LEFT,
+4 −6
Original line number Diff line number Diff line
@@ -1217,6 +1217,8 @@ static void xs_reset_transport(struct sock_xprt *transport)

	trace_rpc_socket_close(xprt, sock);
	sock_release(sock);

	xprt_disconnect_done(xprt);
}

/**
@@ -1237,8 +1239,6 @@ static void xs_close(struct rpc_xprt *xprt)

	xs_reset_transport(transport);
	xprt->reestablish_timeout = 0;

	xprt_disconnect_done(xprt);
}

static void xs_inject_disconnect(struct rpc_xprt *xprt)
@@ -1489,8 +1489,6 @@ static void xs_tcp_state_change(struct sock *sk)
					&transport->sock_state))
			xprt_clear_connecting(xprt);
		clear_bit(XPRT_CLOSING, &xprt->state);
		if (sk->sk_err)
			xprt_wake_pending_tasks(xprt, -sk->sk_err);
		/* Trigger the socket release */
		xs_tcp_force_close(xprt);
	}
@@ -2092,8 +2090,8 @@ static void xs_udp_setup_socket(struct work_struct *work)
	trace_rpc_socket_connect(xprt, sock, 0);
	status = 0;
out:
	xprt_unlock_connect(xprt, transport);
	xprt_clear_connecting(xprt);
	xprt_unlock_connect(xprt, transport);
	xprt_wake_pending_tasks(xprt, status);
}

@@ -2329,8 +2327,8 @@ static void xs_tcp_setup_socket(struct work_struct *work)
	}
	status = -EAGAIN;
out:
	xprt_unlock_connect(xprt, transport);
	xprt_clear_connecting(xprt);
	xprt_unlock_connect(xprt, transport);
	xprt_wake_pending_tasks(xprt, status);
}