Commit 278237c4 authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds

[PATCH] Fix RPC over TCP 'connect' code

xprt.c:
  Fix the RPC over TCP socket reconnect code.

Cheers,
  Trond
parent e387819a
...@@ -399,7 +399,7 @@ xprt_reconnect(struct rpc_task *task) ...@@ -399,7 +399,7 @@ xprt_reconnect(struct rpc_task *task)
{ {
struct rpc_xprt *xprt = task->tk_xprt; struct rpc_xprt *xprt = task->tk_xprt;
struct socket *sock = xprt->sock; struct socket *sock = xprt->sock;
struct sock *inet = xprt->inet; struct sock *inet;
int status; int status;
dprintk("RPC: %4d xprt_reconnect %p connected %d\n", dprintk("RPC: %4d xprt_reconnect %p connected %d\n",
...@@ -420,8 +420,10 @@ xprt_reconnect(struct rpc_task *task) ...@@ -420,8 +420,10 @@ xprt_reconnect(struct rpc_task *task)
if (xprt_connected(xprt)) if (xprt_connected(xprt))
goto out_write; goto out_write;
if (sock && sock->state != SS_UNCONNECTED)
xprt_close(xprt);
status = -ENOTCONN; status = -ENOTCONN;
if (!inet) { if (!(inet = xprt->inet)) {
/* Create an unconnected socket */ /* Create an unconnected socket */
if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout))) if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout)))
goto defer; goto defer;
...@@ -429,14 +431,6 @@ xprt_reconnect(struct rpc_task *task) ...@@ -429,14 +431,6 @@ xprt_reconnect(struct rpc_task *task)
inet = sock->sk; inet = sock->sk;
} }
xprt_disconnect(xprt);
/* Reset TCP record info */
xprt->tcp_offset = 0;
xprt->tcp_reclen = 0;
xprt->tcp_copied = 0;
xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID;
/* Now connect it asynchronously. */ /* Now connect it asynchronously. */
dprintk("RPC: %4d connecting new socket\n", task->tk_pid); dprintk("RPC: %4d connecting new socket\n", task->tk_pid);
status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
...@@ -459,17 +453,21 @@ xprt_reconnect(struct rpc_task *task) ...@@ -459,17 +453,21 @@ xprt_reconnect(struct rpc_task *task)
goto defer; goto defer;
} }
/* Protect against TCP socket state changes */
lock_sock(inet);
dprintk("RPC: %4d connect status %d connected %d\n", dprintk("RPC: %4d connect status %d connected %d\n",
task->tk_pid, status, xprt_connected(xprt)); task->tk_pid, status, xprt_connected(xprt));
spin_lock_bh(&xprt->sock_lock); if (inet->state != TCP_ESTABLISHED) {
if (!xprt_connected(xprt)) {
task->tk_timeout = xprt->timeout.to_maxval; task->tk_timeout = xprt->timeout.to_maxval;
/* if the socket is already closing, delay 5 secs */
if ((1<<inet->state) & ~(TCP_SYN_SENT|TCP_SYN_RECV))
task->tk_timeout = 5*HZ;
rpc_sleep_on(&xprt->sending, task, xprt_reconn_status, NULL); rpc_sleep_on(&xprt->sending, task, xprt_reconn_status, NULL);
spin_unlock_bh(&xprt->sock_lock); release_sock(inet);
return; return;
} }
spin_unlock_bh(&xprt->sock_lock); release_sock(inet);
} }
defer: defer:
if (status < 0) { if (status < 0) {
...@@ -917,6 +915,13 @@ tcp_state_change(struct sock *sk) ...@@ -917,6 +915,13 @@ tcp_state_change(struct sock *sk)
case TCP_ESTABLISHED: case TCP_ESTABLISHED:
if (xprt_test_and_set_connected(xprt)) if (xprt_test_and_set_connected(xprt))
break; break;
/* Reset TCP record info */
xprt->tcp_offset = 0;
xprt->tcp_reclen = 0;
xprt->tcp_copied = 0;
xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID;
spin_lock(&xprt->sock_lock); spin_lock(&xprt->sock_lock);
if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending) if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
rpc_wake_up_task(xprt->snd_task); rpc_wake_up_task(xprt->snd_task);
......
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