summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorJeff Layton <jlayton@kernel.org>2026-09-01 09:39:44 -0400
committerChuck Lever <cel@kernel.org>2026-10-04 21:15:29 -0400
commit202a557d0c8e65c7fd7fcff2ad2756468d1ab711 (patch)
treee0e4671ff539f2b273d7c5807202115fb912c477 /include/linux
parent8e590a16853fedd2697a3b0c32b3cbf1a444f7b2 (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.h3
-rw-r--r--include/linux/sunrpc/svc.h7
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);