aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2009-12-03 15:58:56 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2009-12-03 15:58:56 -0500
commit09a21c4102c8f7893368553273d39c0cadedf9af (patch)
treeb0a051dbb02d48aa95383e39cc7ce6f503d6f33b
parent206a134b4d8abf57cd34dffacf993869355b9aac (diff)
SUNRPC: Allow RPCs to fail quickly if the server is unreachable
The kernel sometimes makes RPC calls to services that aren't running. Because the kernel's RPC client always assumes the hard retry semantic when reconnecting a connection-oriented RPC transport, the underlying reconnect logic takes a long while to time out, even though the remote may have responded immediately with ECONNREFUSED. In certain cases, like upcalls to our local rpcbind daemon, or for NFS mount requests, we'd like the kernel to fail immediately if the remote service isn't reachable. This allows another transport to be tried immediately, or the pending request can be abandoned quickly. Introduce a per-request flag which controls how call_transmit_status() behaves when request transmission fails because the server cannot be reached. We don't want soft connection semantics to apply to other errors. The default case of the switch statement in call_transmit_status() no longer falls through; the fall through code is copied to the default case, and a "break;" is added. The transport's connection re-establishment timeout is also ignored for such requests. We want the request to fail immediately, so the reconnect delay is skipped. Additionally, we don't want a connect failure here to further increase the reconnect timeout value, since this request will not be retried. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--include/linux/sunrpc/sched.h2
-rw-r--r--net/sunrpc/clnt.c11
-rw-r--r--net/sunrpc/xprtsock.c2
3 files changed, 12 insertions, 3 deletions
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 401097781fc0..1906782ec86b 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -130,12 +130,14 @@ struct rpc_task_setup {
130#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ 130#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */
131#define RPC_TASK_KILLED 0x0100 /* task was killed */ 131#define RPC_TASK_KILLED 0x0100 /* task was killed */
132#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */ 132#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
133#define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */
133 134
134#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) 135#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
135#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) 136#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
136#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) 137#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
137#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) 138#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED)
138#define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT) 139#define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT)
140#define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN)
139 141
140#define RPC_TASK_RUNNING 0 142#define RPC_TASK_RUNNING 0
141#define RPC_TASK_QUEUED 1 143#define RPC_TASK_QUEUED 1
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 7bcd931e06ee..68a23583f44c 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -1197,6 +1197,8 @@ call_transmit_status(struct rpc_task *task)
1197 default: 1197 default:
1198 dprint_status(task); 1198 dprint_status(task);
1199 xprt_end_transmit(task); 1199 xprt_end_transmit(task);
1200 rpc_task_force_reencode(task);
1201 break;
1200 /* 1202 /*
1201 * Special cases: if we've been waiting on the 1203 * Special cases: if we've been waiting on the
1202 * socket's write_space() callback, or if the 1204 * socket's write_space() callback, or if the
@@ -1204,11 +1206,16 @@ call_transmit_status(struct rpc_task *task)
1204 * then hold onto the transport lock. 1206 * then hold onto the transport lock.
1205 */ 1207 */
1206 case -ECONNREFUSED: 1208 case -ECONNREFUSED:
1207 case -ECONNRESET:
1208 case -ENOTCONN:
1209 case -EHOSTDOWN: 1209 case -EHOSTDOWN:
1210 case -EHOSTUNREACH: 1210 case -EHOSTUNREACH:
1211 case -ENETUNREACH: 1211 case -ENETUNREACH:
1212 if (RPC_IS_SOFTCONN(task)) {
1213 xprt_end_transmit(task);
1214 rpc_exit(task, task->tk_status);
1215 break;
1216 }
1217 case -ECONNRESET:
1218 case -ENOTCONN:
1212 case -EPIPE: 1219 case -EPIPE:
1213 rpc_task_force_reencode(task); 1220 rpc_task_force_reencode(task);
1214 } 1221 }
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 37c5475ba258..ff312f8b018d 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2033,7 +2033,7 @@ static void xs_connect(struct rpc_task *task)
2033 if (xprt_test_and_set_connecting(xprt)) 2033 if (xprt_test_and_set_connecting(xprt))
2034 return; 2034 return;
2035 2035
2036 if (transport->sock != NULL) { 2036 if (transport->sock != NULL && !RPC_IS_SOFTCONN(task)) {
2037 dprintk("RPC: xs_connect delayed xprt %p for %lu " 2037 dprintk("RPC: xs_connect delayed xprt %p for %lu "
2038 "seconds\n", 2038 "seconds\n",
2039 xprt, xprt->reestablish_timeout / HZ); 2039 xprt, xprt->reestablish_timeout / HZ);