1
0
Fork 0

NFS client bugfixes for Linux 4.20

Bugfixes:
 - 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()
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJcGnQMAAoJEA4mA3inWBJc3OIP/iRGQeEKuJrGxarssdzIXrqZ
 ID6t6XuYxuh6nknS3PAvn1TpAPGFRcTya5MIjvMEMCknH4tQVmD7S2v2vOlx395E
 5Cg5Q6FX1dj3i2/flzS1YcByQonUrkJuuMZ36bRJ5uCGjXdryhgC1YNcsq3HXAiA
 G/O4W+BpvxLC9z3KGwWz2+v5K4gnIh9sypSye8qsQdrgDlFDo88jWH57gtxQTVjv
 13vke64pv/bm97EfZ8gfZprcwLegQ3JJsmcoOfwnh2jRd2i5j4S/xmCLaTjOn9Fg
 8fgev7klAzO/39gNV+syGKXVwgOh6mKk5PifDYv986ghvzamPmVT+chIpjgXKSJp
 KOpGXY/547KFHWwMQVsmNI+5RPC7FTwDkTwXuOVcmtVyNiJgpveX45pQS8kwRYxq
 kZXk/t1T1lXbsBPd0S+1KDjUUPd9DjSm3T3CZKvvfJBbH+ITV2gol2eqneizgxDo
 JLBdNFRVTPnud7IEdXiXgjMzl8aFAZsPkXfUmqWPEMtiTn5izSUbXxa04KYgHQpI
 GAAMVAZttl6cYoRkPIVIbQLbpY4LsBxA9iTTR39SGINLYiFQBFUNkP02OR+HaD4l
 bzY8n5Li1/WekxHagq6RFt+ajBgXSPeCXS3WqigEMc0Xw58u/3Td+0DuRIABmhhr
 IJDorHWizxgh2VseZkUB
 =+M4X
 -----END PGP SIGNATURE-----

Merge tag 'nfs-for-4.20-6' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

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
hifive-unleashed-5.1
Linus Torvalds 2018-12-19 18:38:54 -08:00
commit 8c9dff1ebd
3 changed files with 9 additions and 37 deletions

View File

@ -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:

View File

@ -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,

View File

@ -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);
}