2006-10-24 02:49:11

by NeilBrown

[permalink] [raw]
Subject: [PATCH 003 of 4] Make RPC 'ping' requests fail more quickly.


Sometimes when an RPC client is created, an initial 'PING' is sent to
the RPC/NULL procedure to make sure the server is running.
This is always done as a 'soft' call so a major timeout will be fatal.

We change semantics so that if portmap reports that the service does
not exist, or if a ECONNREFUSED error is returned we abort early
rather than persist for the full timeout.

The core mechanism is a new flag RPC_TASK_ACCEPT_NO which tell the rpc
client to accept a 'no' answer rather than retrying.

This patch also causes lockd clients to *not* do the initial 'ping'
otherwise a lock request could fail due to a missing server, even on a
hard mount.

Signed-off-by: Neil Brown <[email protected]>

### Diffstat output
./fs/lockd/host.c | 1 +
./include/linux/sunrpc/sched.h | 4 ++++
./net/sunrpc/clnt.c | 14 +++++++++++---
./net/sunrpc/pmap_clnt.c | 4 +++-
4 files changed, 19 insertions(+), 4 deletions(-)

diff .prev/fs/lockd/host.c ./fs/lockd/host.c
--- .prev/fs/lockd/host.c 2006-10-24 10:09:41.000000000 +1000
+++ ./fs/lockd/host.c 2006-10-24 11:48:05.000000000 +1000
@@ -236,6 +236,7 @@ nlm_bind_host(struct nlm_host *host)
.version = host->h_version,
.authflavor = RPC_AUTH_UNIX,
.flags = (RPC_CLNT_CREATE_HARDRTRY |
+ RPC_CLNT_CREATE_NOPING |
RPC_CLNT_CREATE_AUTOBIND),
};


diff .prev/include/linux/sunrpc/sched.h ./include/linux/sunrpc/sched.h
--- .prev/include/linux/sunrpc/sched.h 2006-10-24 11:35:21.000000000 +1000
+++ ./include/linux/sunrpc/sched.h 2006-10-24 11:46:25.000000000 +1000
@@ -133,6 +133,10 @@ struct rpc_call_ops {
#define RPC_TASK_KILLED 0x0100 /* task was killed */
#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
#define RPC_TASK_NOINTR 0x0400 /* uninterruptible task */
+#define RPC_TASK_ACCEPT_NO 0x0800 /* Accept a 'no' such as
+ * -ECONNREFUSED or '0' from
+ * portmap, to be reliable.
+ */

#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)

diff .prev/net/sunrpc/clnt.c ./net/sunrpc/clnt.c
--- .prev/net/sunrpc/clnt.c 2006-10-24 09:43:48.000000000 +1000
+++ ./net/sunrpc/clnt.c 2006-10-24 11:45:54.000000000 +1000
@@ -221,7 +221,7 @@ struct rpc_clnt *rpc_create(struct rpc_c
return clnt;

if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
- int tskflags = RPC_TASK_SOFT;
+ int tskflags = RPC_TASK_SOFT | RPC_TASK_ACCEPT_NO;
int err;
if ( ! (args->flags & RPC_CLNT_CREATE_INTR))
tskflags |= RPC_TASK_NOINTR;
@@ -868,6 +868,8 @@ call_bind_status(struct rpc_task *task)
case -EACCES:
dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n",
task->tk_pid);
+ if (task->tk_flags & RPC_TASK_ACCEPT_NO)
+ break;
rpc_delay(task, 3*HZ);
goto retry_timeout;
case -ETIMEDOUT:
@@ -941,6 +943,8 @@ call_connect_status(struct rpc_task *tas
switch (status) {
case -ENOTCONN:
case -EAGAIN:
+ if (task->tk_flags & RPC_TASK_ACCEPT_NO)
+ break;
task->tk_action = call_bind;
if (!RPC_IS_SOFT(task))
return;
@@ -1044,8 +1048,12 @@ call_status(struct rpc_task *task)
break;
case -ECONNREFUSED:
case -ENOTCONN:
- rpc_force_rebind(clnt);
- task->tk_action = call_bind;
+ if (task->tk_flags & RPC_TASK_ACCEPT_NO)
+ rpc_exit(task, status);
+ else {
+ rpc_force_rebind(clnt);
+ task->tk_action = call_bind;
+ }
break;
case -EAGAIN:
task->tk_action = call_transmit;

diff .prev/net/sunrpc/pmap_clnt.c ./net/sunrpc/pmap_clnt.c
--- .prev/net/sunrpc/pmap_clnt.c 2006-10-24 09:33:08.000000000 +1000
+++ ./net/sunrpc/pmap_clnt.c 2006-10-24 11:51:32.000000000 +1000
@@ -139,7 +139,9 @@ void rpc_getport(struct rpc_task *task)
goto bailout;

status = -EIO;
- child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
+ child = rpc_run_task(pmap_clnt,
+ RPC_TASK_ASYNC | (task->tk_flags & RPC_TASK_ACCEPT_NO),
+ &pmap_getport_ops, map);
if (IS_ERR(child))
goto bailout;
rpc_release_task(child);

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs


2006-10-24 23:37:26

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH 003 of 4] Make RPC 'ping' requests fail more quickly.

On 10/23/06, NeilBrown <[email protected]> wrote:
>
> Sometimes when an RPC client is created, an initial 'PING' is sent to
> the RPC/NULL procedure to make sure the server is running.
> This is always done as a 'soft' call so a major timeout will be fatal.
>
> We change semantics so that if portmap reports that the service does
> not exist, or if a ECONNREFUSED error is returned we abort early
> rather than persist for the full timeout.
>
> The core mechanism is a new flag RPC_TASK_ACCEPT_NO which tell the rpc
> client to accept a 'no' answer rather than retrying.

This doesn't seem like a per task thing.... It maybe should be a
client option, like AUTOBIND is. RPC_CREATE_BIND_ONE_SHOT, perhaps?

Is the local statd case the only one where an immediate timeout is desirable?

> This patch also causes lockd clients to *not* do the initial 'ping'
> otherwise a lock request could fail due to a missing server, even on a
> hard mount.

It's a small change, but maybe it's worth splitting this into a
separate patch. This seems a worthy change, but the other stuff I
still don't quite grok.


> ### Diffstat output
> ./fs/lockd/host.c | 1 +
> ./include/linux/sunrpc/sched.h | 4 ++++
> ./net/sunrpc/clnt.c | 14 +++++++++++---
> ./net/sunrpc/pmap_clnt.c | 4 +++-
> 4 files changed, 19 insertions(+), 4 deletions(-)
>
> diff .prev/fs/lockd/host.c ./fs/lockd/host.c
> --- .prev/fs/lockd/host.c 2006-10-24 10:09:41.000000000 +1000
> +++ ./fs/lockd/host.c 2006-10-24 11:48:05.000000000 +1000
> @@ -236,6 +236,7 @@ nlm_bind_host(struct nlm_host *host)
> .version = host->h_version,
> .authflavor = RPC_AUTH_UNIX,
> .flags = (RPC_CLNT_CREATE_HARDRTRY |
> + RPC_CLNT_CREATE_NOPING |
> RPC_CLNT_CREATE_AUTOBIND),
> };
>
>
> diff .prev/include/linux/sunrpc/sched.h ./include/linux/sunrpc/sched.h
> --- .prev/include/linux/sunrpc/sched.h 2006-10-24 11:35:21.000000000 +1000
> +++ ./include/linux/sunrpc/sched.h 2006-10-24 11:46:25.000000000 +1000
> @@ -133,6 +133,10 @@ struct rpc_call_ops {
> #define RPC_TASK_KILLED 0x0100 /* task was killed */
> #define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
> #define RPC_TASK_NOINTR 0x0400 /* uninterruptible task */
> +#define RPC_TASK_ACCEPT_NO 0x0800 /* Accept a 'no' such as
> + * -ECONNREFUSED or '0' from
> + * portmap, to be reliable.
> + */
>
> #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
> #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
>
> diff .prev/net/sunrpc/clnt.c ./net/sunrpc/clnt.c
> --- .prev/net/sunrpc/clnt.c 2006-10-24 09:43:48.000000000 +1000
> +++ ./net/sunrpc/clnt.c 2006-10-24 11:45:54.000000000 +1000
> @@ -221,7 +221,7 @@ struct rpc_clnt *rpc_create(struct rpc_c
> return clnt;
>
> if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
> - int tskflags = RPC_TASK_SOFT;
> + int tskflags = RPC_TASK_SOFT | RPC_TASK_ACCEPT_NO;
> int err;
> if ( ! (args->flags & RPC_CLNT_CREATE_INTR))
> tskflags |= RPC_TASK_NOINTR;
> @@ -868,6 +868,8 @@ call_bind_status(struct rpc_task *task)
> case -EACCES:
> dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n",
> task->tk_pid);
> + if (task->tk_flags & RPC_TASK_ACCEPT_NO)
> + break;
> rpc_delay(task, 3*HZ);
> goto retry_timeout;
> case -ETIMEDOUT:
> @@ -941,6 +943,8 @@ call_connect_status(struct rpc_task *tas
> switch (status) {
> case -ENOTCONN:
> case -EAGAIN:
> + if (task->tk_flags & RPC_TASK_ACCEPT_NO)
> + break;
> task->tk_action = call_bind;
> if (!RPC_IS_SOFT(task))
> return;
> @@ -1044,8 +1048,12 @@ call_status(struct rpc_task *task)
> break;
> case -ECONNREFUSED:
> case -ENOTCONN:
> - rpc_force_rebind(clnt);
> - task->tk_action = call_bind;
> + if (task->tk_flags & RPC_TASK_ACCEPT_NO)
> + rpc_exit(task, status);
> + else {
> + rpc_force_rebind(clnt);
> + task->tk_action = call_bind;
> + }
> break;
> case -EAGAIN:
> task->tk_action = call_transmit;
>
> diff .prev/net/sunrpc/pmap_clnt.c ./net/sunrpc/pmap_clnt.c
> --- .prev/net/sunrpc/pmap_clnt.c 2006-10-24 09:33:08.000000000 +1000
> +++ ./net/sunrpc/pmap_clnt.c 2006-10-24 11:51:32.000000000 +1000
> @@ -139,7 +139,9 @@ void rpc_getport(struct rpc_task *task)
> goto bailout;
>
> status = -EIO;
> - child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
> + child = rpc_run_task(pmap_clnt,
> + RPC_TASK_ASYNC | (task->tk_flags & RPC_TASK_ACCEPT_NO),
> + &pmap_getport_ops, map);
> if (IS_ERR(child))
> goto bailout;
> rpc_release_task(child);
>
> -------------------------------------------------------------------------
> Using Tomcat but need to do more? Need to support web services, security?
> Get stuff done quickly with pre-integrated technology to make your job easier
> Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
> http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
> _______________________________________________
> NFS maillist - [email protected]
> https://lists.sourceforge.net/lists/listinfo/nfs
>

--
"We who cut mere stones must always be envisioning cathedrals"
-- Quarry worker's creed

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2006-11-15 17:15:01

by Trond Myklebust

[permalink] [raw]
Subject: Re: [PATCH 003 of 4] Make RPC 'ping' requests fail more quickly.

On Tue, 2006-10-24 at 12:49 +1000, NeilBrown wrote:
> Sometimes when an RPC client is created, an initial 'PING' is sent to
> the RPC/NULL procedure to make sure the server is running.
> This is always done as a 'soft' call so a major timeout will be fatal.
>
> We change semantics so that if portmap reports that the service does
> not exist, or if a ECONNREFUSED error is returned we abort early
> rather than persist for the full timeout.

What if the server is in the process of booting? If the RPC layer
doesn't handle that case, then we will have to add a loop to sleep and
wait in the NLM client.

Cheers
Trond


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2006-11-16 03:20:54

by NeilBrown

[permalink] [raw]
Subject: Re: [PATCH 003 of 4] Make RPC 'ping' requests fail more quickly.

On Wednesday November 15, [email protected] wrote:
> On Tue, 2006-10-24 at 12:49 +1000, NeilBrown wrote:
> > Sometimes when an RPC client is created, an initial 'PING' is sent to
> > the RPC/NULL procedure to make sure the server is running.
> > This is always done as a 'soft' call so a major timeout will be fatal.
> >
> > We change semantics so that if portmap reports that the service does
> > not exist, or if a ECONNREFUSED error is returned we abort early
> > rather than persist for the full timeout.
>
> What if the server is in the process of booting? If the RPC layer
> doesn't handle that case, then we will have to add a loop to sleep and
> wait in the NLM client.

What is the purpose of the PING?

It seems to me that it is intended to allow a one-time soft-fail.
e.g. it would be used when first mounting a filesystem. If the server
isn't responding, then fail the mount, even if it is a hard mount.

Once the PING succeeds we assume the server is genuine and all future
requests follow whatever soft/hard/intr rules are given for the mount.

If this is the case, then a PING should fail as soon as there seems to
be a genuine justification for the failure, such as an rpcbind error.

NeilBrown

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs