Commit f4084744 authored by Trond Myklebust's avatar Trond Myklebust

Ensure that if we need to reconnect the socket, we also resend

the entire RPC message

Assorted TCP reconnection fixes.

Temporarily raise the necessary CAP_NET_BIND_SERVICE capability
if we need to bind the socket to a reserved port during a TCP
reconnection. Check for CAP_NET_BIND_SERVICE at mount time.
parent d4bea820
...@@ -703,6 +703,7 @@ call_status(struct rpc_task *task) ...@@ -703,6 +703,7 @@ call_status(struct rpc_task *task)
break; break;
case -ECONNREFUSED: case -ECONNREFUSED:
case -ENOTCONN: case -ENOTCONN:
req->rq_bytes_sent = 0;
if (clnt->cl_autobind) if (clnt->cl_autobind)
clnt->cl_port = 0; clnt->cl_port = 0;
task->tk_action = call_bind; task->tk_action = call_bind;
......
...@@ -259,6 +259,7 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) ...@@ -259,6 +259,7 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req)
*/ */
case -EAGAIN: case -EAGAIN:
break; break;
case -ECONNRESET:
case -ENOTCONN: case -ENOTCONN:
case -EPIPE: case -EPIPE:
/* connection broken */ /* connection broken */
...@@ -474,8 +475,8 @@ xprt_connect(struct rpc_task *task) ...@@ -474,8 +475,8 @@ xprt_connect(struct rpc_task *task)
release_sock(inet); release_sock(inet);
break; break;
case -ECONNREFUSED: case -ECONNREFUSED:
case -ECONNRESET:
case -ENOTCONN: case -ENOTCONN:
case -ENETUNREACH:
if (!task->tk_client->cl_softrtry) { if (!task->tk_client->cl_softrtry) {
rpc_delay(task, RPC_REESTABLISH_TIMEOUT); rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
task->tk_status = -ENOTCONN; task->tk_status = -ENOTCONN;
...@@ -926,7 +927,7 @@ tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, ...@@ -926,7 +927,7 @@ tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
} }
/* Skip over any trailing bytes on short reads */ /* Skip over any trailing bytes on short reads */
tcp_read_discard(xprt, &desc); tcp_read_discard(xprt, &desc);
} while (desc.count && xprt_connected(xprt)); } while (desc.count);
dprintk("RPC: tcp_data_recv done\n"); dprintk("RPC: tcp_data_recv done\n");
return len - desc.count; return len - desc.count;
} }
...@@ -964,18 +965,18 @@ tcp_state_change(struct sock *sk) ...@@ -964,18 +965,18 @@ tcp_state_change(struct sock *sk)
switch (sk->state) { switch (sk->state) {
case TCP_ESTABLISHED: case TCP_ESTABLISHED:
if (xprt_test_and_set_connected(xprt)) spin_lock_bh(&xprt->sock_lock);
break; if (!xprt_test_and_set_connected(xprt)) {
/* Reset TCP record info */ /* Reset TCP record info */
xprt->tcp_offset = 0; xprt->tcp_offset = 0;
xprt->tcp_reclen = 0; xprt->tcp_reclen = 0;
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_bh(&xprt->sock_lock); if (xprt->snd_task)
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);
rpc_wake_up(&xprt->pending);
}
spin_unlock_bh(&xprt->sock_lock); spin_unlock_bh(&xprt->sock_lock);
break; break;
case TCP_SYN_SENT: case TCP_SYN_SENT:
...@@ -1094,9 +1095,6 @@ xprt_prepare_transmit(struct rpc_task *task) ...@@ -1094,9 +1095,6 @@ xprt_prepare_transmit(struct rpc_task *task)
if (xprt->shutdown) if (xprt->shutdown)
return -EIO; return -EIO;
if (!xprt_connected(xprt))
return -ENOTCONN;
if (task->tk_rpcwait) if (task->tk_rpcwait)
rpc_remove_wait_queue(task); rpc_remove_wait_queue(task);
...@@ -1105,6 +1103,12 @@ xprt_prepare_transmit(struct rpc_task *task) ...@@ -1105,6 +1103,12 @@ xprt_prepare_transmit(struct rpc_task *task)
err = -EAGAIN; err = -EAGAIN;
goto out_unlock; goto out_unlock;
} }
if (!xprt_connected(xprt)) {
err = -ENOTCONN;
goto out_unlock;
}
if (list_empty(&req->rq_list)) { if (list_empty(&req->rq_list)) {
list_add_tail(&req->rq_list, &xprt->recv); list_add_tail(&req->rq_list, &xprt->recv);
req->rq_received = 0; req->rq_received = 0;
...@@ -1193,20 +1197,17 @@ xprt_transmit(struct rpc_task *task) ...@@ -1193,20 +1197,17 @@ xprt_transmit(struct rpc_task *task)
rpc_delay(task, HZ>>4); rpc_delay(task, HZ>>4);
return; return;
case -ECONNREFUSED: case -ECONNREFUSED:
case -ENOTCONN:
if (!xprt->stream) {
task->tk_timeout = RPC_REESTABLISH_TIMEOUT; task->tk_timeout = RPC_REESTABLISH_TIMEOUT;
rpc_sleep_on(&xprt->sending, task, NULL, NULL); rpc_sleep_on(&xprt->sending, task, NULL, NULL);
case -ENOTCONN:
return; return;
}
/* fall through */
default: default:
if (xprt->stream) if (xprt->stream)
xprt_disconnect(xprt); xprt_disconnect(xprt);
req->rq_bytes_sent = 0;
} }
out_release: out_release:
xprt_release_write(xprt, task); xprt_release_write(xprt, task);
req->rq_bytes_sent = 0;
return; return;
out_receive: out_receive:
dprintk("RPC: %4d xmit complete\n", task->tk_pid); dprintk("RPC: %4d xmit complete\n", task->tk_pid);
...@@ -1227,6 +1228,7 @@ xprt_transmit(struct rpc_task *task) ...@@ -1227,6 +1228,7 @@ xprt_transmit(struct rpc_task *task)
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);
req->rq_bytes_sent = 0;
} }
/* /*
...@@ -1410,6 +1412,9 @@ xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) ...@@ -1410,6 +1412,9 @@ xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to)
req->rq_next = NULL; req->rq_next = NULL;
xprt->free = xprt->slot; xprt->free = xprt->slot;
/* Check whether we want to use a reserved port */
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
dprintk("RPC: created transport %p\n", xprt); dprintk("RPC: created transport %p\n", xprt);
return xprt; return xprt;
...@@ -1423,6 +1428,12 @@ xprt_bindresvport(struct socket *sock) ...@@ -1423,6 +1428,12 @@ xprt_bindresvport(struct socket *sock)
{ {
struct sockaddr_in myaddr; struct sockaddr_in myaddr;
int err, port; int err, port;
kernel_cap_t saved_cap = current->cap_effective;
/* Override capabilities.
* They were checked in xprt_create_proto i.e. at mount time
*/
cap_raise(current->cap_effective, CAP_NET_BIND_SERVICE);
memset(&myaddr, 0, sizeof(myaddr)); memset(&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET; myaddr.sin_family = AF_INET;
...@@ -1432,6 +1443,7 @@ xprt_bindresvport(struct socket *sock) ...@@ -1432,6 +1443,7 @@ xprt_bindresvport(struct socket *sock)
err = sock->ops->bind(sock, (struct sockaddr *) &myaddr, err = sock->ops->bind(sock, (struct sockaddr *) &myaddr,
sizeof(myaddr)); sizeof(myaddr));
} while (err == -EADDRINUSE && --port > 0); } while (err == -EADDRINUSE && --port > 0);
current->cap_effective = saved_cap;
if (err < 0) if (err < 0)
printk("RPC: Can't bind to reserved port (%d).\n", -err); printk("RPC: Can't bind to reserved port (%d).\n", -err);
...@@ -1537,7 +1549,6 @@ xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) ...@@ -1537,7 +1549,6 @@ xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
if (!xprt) if (!xprt)
goto out_bad; goto out_bad;
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
if (!xprt->stream) { if (!xprt->stream) {
struct socket *sock; struct socket *sock;
......
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