Commit a92694eb authored by Trond Myklebust's avatar Trond Myklebust

Fix a TCP race: check whether or not the socket has been disconnected

before we allow an RPC request to wait on a reply.
parent 1a961d01
...@@ -397,8 +397,10 @@ static void ...@@ -397,8 +397,10 @@ static void
xprt_disconnect(struct rpc_xprt *xprt) xprt_disconnect(struct rpc_xprt *xprt)
{ {
dprintk("RPC: disconnected transport %p\n", xprt); dprintk("RPC: disconnected transport %p\n", xprt);
spin_lock_bh(&xprt->sock_lock);
xprt_clear_connected(xprt); xprt_clear_connected(xprt);
rpc_wake_up_status(&xprt->pending, -ENOTCONN); rpc_wake_up_status(&xprt->pending, -ENOTCONN);
spin_unlock_bh(&xprt->sock_lock);
} }
/* /*
...@@ -986,10 +988,10 @@ tcp_state_change(struct sock *sk) ...@@ -986,10 +988,10 @@ tcp_state_change(struct sock *sk)
xprt->tcp_copied = 0; xprt->tcp_copied = 0;
xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID;
spin_lock(&xprt->sock_lock); spin_lock_bh(&xprt->sock_lock);
if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending) if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending)
rpc_wake_up_task(xprt->snd_task); rpc_wake_up_task(xprt->snd_task);
spin_unlock(&xprt->sock_lock); spin_unlock_bh(&xprt->sock_lock);
break; break;
case TCP_SYN_SENT: case TCP_SYN_SENT:
case TCP_SYN_RECV: case TCP_SYN_RECV:
...@@ -1192,7 +1194,10 @@ xprt_transmit(struct rpc_task *task) ...@@ -1192,7 +1194,10 @@ xprt_transmit(struct rpc_task *task)
if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) {
/* Protect against races with xprt_write_space */ /* Protect against races with xprt_write_space */
spin_lock_bh(&xprt->sock_lock); spin_lock_bh(&xprt->sock_lock);
if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { /* Don't race with disconnect */
if (!xprt_connected(xprt))
task->tk_status = -ENOTCONN;
else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) {
task->tk_timeout = req->rq_timeout.to_current; task->tk_timeout = req->rq_timeout.to_current;
rpc_sleep_on(&xprt->pending, task, NULL, NULL); rpc_sleep_on(&xprt->pending, task, NULL, NULL);
} }
...@@ -1230,7 +1235,10 @@ xprt_transmit(struct rpc_task *task) ...@@ -1230,7 +1235,10 @@ xprt_transmit(struct rpc_task *task)
} else } else
task->tk_timeout = req->rq_timeout.to_current; task->tk_timeout = req->rq_timeout.to_current;
spin_lock_bh(&xprt->sock_lock); spin_lock_bh(&xprt->sock_lock);
if (!req->rq_received) /* Don't race with disconnect */
if (!xprt_connected(xprt))
task->tk_status = -ENOTCONN;
else if (!req->rq_received)
rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
__xprt_release_write(xprt, task); __xprt_release_write(xprt, task);
spin_unlock_bh(&xprt->sock_lock); spin_unlock_bh(&xprt->sock_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment