Re: [PATCH v3 06/14] SUNRPC: report local rpcbind calls that get no answer
From: Chuck Lever
Date: Sun Aug 30 2026 - 11:52:34 EST
On Fri, Aug 28, 2026, at 12:37 PM, Jeff Layton wrote:
> A caller that creates many listeners in one operation calls svc_register()
> once for each of them. Every call waits for the local rpcbind on its own,
> so a rpcbind that never answers costs the caller one timeout per listener.
> The caller has no way to learn that the first call already failed.
>
> An rpcbind failure can occur one of two ways: either rpcbind fails to
> respond, or it can respond with -EACCES to indicate that the user
> doesn't own the current record.
>
> Give the first case its own errno. rpcb_register_call() returns -ENAVAIL
> when the call got no answer, and the existing -EACCES continues to mean a
> FALSE reply.
>
> svc_generic_rpcbind_set() has to let -ENAVAIL past vs_rpcb_optnl, since it
> is not a refusal. svc_register() applies vs_rpcb_optnl to it instead, so a
> v4-only server still creates its listeners, and then keeps a running total
> in serv->sv_rpcb_failures. -ENAVAIL never escapes svc_register().
>
> svc_rpcb_failure_count() reports the total. A caller reads the count
> before it starts and compares as it goes to determine if there have been
> errors.
>
> The users of this infrastructure will be added in later patches.
>
> Assisted-by: LLM
> Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
> diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
> index 0aa376b82a52..c680137f0fca 100644
> --- a/net/sunrpc/rpcb_clnt.c
> +++ b/net/sunrpc/rpcb_clnt.c
> @@ -412,7 +412,8 @@ static struct rpc_clnt *rpcb_create(struct net
> *net, const char *nodename,
> return rpc_create(&args);
> }
>
> -static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt
> *clnt, struct rpc_message *msg, bool is_set)
> +static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt
> *clnt,
> + struct rpc_message *msg, bool is_set)
> {
> int flags = RPC_TASK_NOCONNECT;
> int error, result = 0;
> @@ -422,8 +423,10 @@ static int rpcb_register_call(struct sunrpc_net
> *sn, struct rpc_clnt *clnt, stru
> msg->rpc_resp = &result;
>
> error = rpc_call_sync(clnt, msg, flags);
> - if (error < 0)
> + if (error == -EPROTONOSUPPORT)
> return error;
> + if (error < 0)
> + return -ENAVAIL;
>
> if (!result)
> return -EACCES;
If I'm reading this correctly, rpcb_register_call() classifies
every failure except -EPROTONOSUPPORT as "no answer".
rpc_call_sync() returns negative errnos that are not "no answer":
pre-dispatch local failures (-ENOMEM from rpc_new_task()), a fatal
signal (-ERESTARTSYS), and reply-derived errors from
rpc_verify_header(): -EPFNOSUPPORT, -EOPNOTSUPP, -EIO, -EACCES
(auth error), -EKEYREJECTED. All of these show that rpcbind *did*
answer.
Now they become -ENAVAIL, get counted in sv_rpcb_failures, are
silently converted to success for a vs_rpcb_optnl version, and
reach userspace as a synthesized -ETIMEDOUT for mandatory versions.
Consequences:
* The commit message says "-EACCES continues to mean a FALSE
reply," but the RPC layer's auth -EACCES is rewritten to
-ENAVAIL before the two can be told apart. Its "one of two
ways" failure taxonomy is not what the code implements.
* "rpcbind not running" (-ECONNREFUSED/-ENOENT) and every
other transport error reach nfsd's listener_set ack, the
svc_register/svc_unregister tracepoints, and the printk
as indistinguishable ETIMEDOUT/ENAVAIL, which IMO is an
observability regression.
* -ERESTARTSYS -> -ETIMEDOUT drops syscall-restart semantics
on a fatal signal during registration.
I'm probably missing something.
--
Chuck Lever (Come to NFS bake-a-thon! https://nfsv4bat.org)