diff options
| author | Jeff Layton <jlayton@kernel.org> | 2026-09-01 09:39:44 -0400 |
|---|---|---|
| committer | Chuck Lever <cel@kernel.org> | 2026-10-04 21:15:29 -0400 |
| commit | 202a557d0c8e65c7fd7fcff2ad2756468d1ab711 (patch) | |
| tree | e0e4671ff539f2b273d7c5807202115fb912c477 /include/linux | |
| parent | 8e590a16853fedd2697a3b0c32b3cbf1a444f7b2 (diff) | |
SUNRPC: report local rpcbind calls that get no answer
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.
Split rpcb_register_call() failures by whether rpcbind answered:
- answered: a FALSE reply, or an RPC-level rejection that
rpc_decode_header() derives from the reply. -EACCES (FALSE reply or
AUTH_ERROR), -EPROTONOSUPPORT, -EPFNOSUPPORT, -EOPNOTSUPP.
- never sent: -ENOMEM, -EMSGSIZE, -ERESTARTSYS.
- no answer: everything else, i.e. transport errors.
Any no-answer error gets represented by -EIO, which is already what the
RPC layer reports for most of it: rpc_check_timeout() returns -EIO for a
soft timeout without RPC_TASK_TIMEOUT, and call_status() documents -EIO
as "shutdown or soft timeout".
Keep a count of the number of rpcbind failures in the serv. Later
patches will use that to watch for hard rpcbind failures, and alter
their behavior accordingly.
Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260901-nfsd-nl-hang-v5-6-a540d86668b0@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/sunrpc/clnt.h | 3 | ||||
| -rw-r--r-- | include/linux/sunrpc/svc.h | 7 |
2 files changed, 7 insertions, 3 deletions
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 3c2b8c355ab3..30344c0d6a9d 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -199,7 +199,8 @@ struct rpc_xprt *rpc_task_get_xprt(struct rpc_clnt *clnt, int rpcb_create_local(struct net *); void rpcb_put_local(struct net *); -int rpcb_register(struct net *, u32, u32, int, unsigned short); +int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, + unsigned short port); int rpcb_v4_register(struct net *net, const u32 program, const u32 version, const struct sockaddr *address, diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 2db1b9ec5658..5fa9417e034d 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -78,6 +78,7 @@ struct svc_serv { unsigned int sv_max_payload; /* datagram payload size */ unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */ unsigned int sv_xdrsize; /* XDR buffer size */ + atomic_t sv_rpcb_failures; /* unanswered rpcbind calls */ struct list_head sv_permsocks; /* all permanent sockets */ struct list_head sv_tempsocks; /* all temporary sockets */ int sv_tmpcnt; /* count of temporary "valid" sockets */ @@ -451,6 +452,7 @@ int sunrpc_set_pool_mode(const char *val); int sunrpc_get_pool_mode(char *val, size_t size); void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net); int svc_bind(struct svc_serv *serv, struct net *net); +unsigned int svc_rpcb_failure_count(struct svc_serv *serv); struct svc_serv *svc_create(struct svc_program *, unsigned int, int (*threadfn)(void *data)); bool svc_rqst_replace_page(struct svc_rqst *rqstp, @@ -471,8 +473,9 @@ unsigned int svc_serv_maxthreads(const struct svc_serv *serv); int svc_pool_stats_open(struct svc_info *si, struct file *file); void svc_process(struct svc_rqst *rqstp); void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp); -int svc_register(const struct svc_serv *, struct net *, const int, - const unsigned short, const unsigned short); +int svc_register(struct svc_serv *serv, struct net *net, + const int family, const unsigned short proto, + const unsigned short port); void svc_wake_up(struct svc_serv *); void svc_reserve(struct svc_rqst *rqstp, int space); |
