The kernel's rpcbind client creates and deletes an rpc_clnt and its underlying transport socket for every upcall to the local rpcbind daemon. Instead, let's create an rpc_clnt for rpcbind upcalls when sunrpc.ko is loaded, and use it until sunrpc.ko is unloaded. This saves the overhead of creating and destroying an rpc_clnt and a socket for every upcall. When starting a typical NFS server on IPv4 and IPv6, this reduces the number of rpcbind sockets created from one per upcall to just one. The NFS service itself does three upcalls (one per version) times two upcalls (one per transport) times two upcalls (one per address family), making 12, plus another one for the initial call to unregister previous NFS services. Starting the NLM service adds an additional 13 upcalls, for similar reasons. Note that at the moment, lockd supports IPv6, but the kernel's NFS service does not, so the NFS service does only six registrations on current systems. Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> --- net/sunrpc/rpcb_clnt.c | 64 +++++++++++++++++++++++++++++++++++----------- net/sunrpc/sunrpc_syms.c | 5 ++++ 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 830faf4..a6fb65e 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -110,6 +110,9 @@ static void rpcb_getport_done(struct rpc_task *, void *); static void rpcb_map_release(void *data); static struct rpc_program rpcb_program; +static struct rpc_clnt * rpcb_local_clnt; +static struct rpc_clnt * rpcb_local_clnt4; + struct rpcbind_args { struct rpc_xprt * r_xprt; @@ -209,22 +212,13 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, return rpc_create(&args); } -static int rpcb_register_call(const u32 version, struct rpc_message *msg) +static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg) { - struct sockaddr *addr = (struct sockaddr *)&rpcb_inaddr_loopback; - size_t addrlen = sizeof(rpcb_inaddr_loopback); - struct rpc_clnt *rpcb_clnt; int result, error = 0; msg->rpc_resp = &result; - rpcb_clnt = rpcb_create_local(addr, addrlen, version); - if (!IS_ERR(rpcb_clnt)) { - error = rpc_call_sync(rpcb_clnt, msg, 0); - rpc_shutdown_client(rpcb_clnt); - } else - error = PTR_ERR(rpcb_clnt); - + error = rpc_call_sync(clnt, msg, 0); if (error < 0) { dprintk("RPC: failed to contact local rpcbind " "server (errno %d).\n", -error); @@ -288,7 +282,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) if (port) msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; - return rpcb_register_call(RPCBVERS_2, &msg); + return rpcb_register_call(rpcb_local_clnt, &msg); } /* @@ -313,7 +307,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap, if (port) msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; - result = rpcb_register_call(RPCBVERS_4, msg); + result = rpcb_register_call(rpcb_local_clnt4, msg); kfree(map->r_addr); return result; } @@ -340,7 +334,7 @@ static int rpcb_register_inet6(const struct sockaddr *sap, if (port) msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; - result = rpcb_register_call(RPCBVERS_4, msg); + result = rpcb_register_call(rpcb_local_clnt4, msg); kfree(map->r_addr); return result; } @@ -356,7 +350,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) map->r_addr = ""; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; - return rpcb_register_call(RPCBVERS_4, msg); + return rpcb_register_call(rpcb_local_clnt4, msg); } /** @@ -1027,3 +1021,43 @@ static struct rpc_program rpcb_program = { .version = rpcb_version, .stats = &rpcb_stats, }; + +/** + * init_rpcb_clnt - set up kernel's rpcbind client + * + */ +int init_rpcb_clnt(void) +{ + struct sockaddr *addr = (struct sockaddr *)&rpcb_inaddr_loopback; + size_t addrlen = sizeof(rpcb_inaddr_loopback); + + rpcb_local_clnt = rpcb_create_local(addr, addrlen, RPCBVERS_2); + if (IS_ERR(rpcb_local_clnt)) { + printk(KERN_ERR "failed to create local rpcbind " + "client (errno %ld).\n", + -PTR_ERR(rpcb_local_clnt)); + return -1; + } + rpcb_local_clnt4 = rpc_bind_new_program(rpcb_local_clnt, + &rpcb_program, + RPCBVERS_4); + if (IS_ERR(rpcb_local_clnt4)) { + printk(KERN_ERR "failed to duplicate local rpcbind " + "client (errno %ld).\n", + -PTR_ERR(rpcb_local_clnt4)); + rpc_shutdown_client(rpcb_local_clnt); + return -1; + } + + return 0; +} + +/** + * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister + * + */ +void cleanup_rpcb_clnt(void) +{ + rpc_shutdown_client(rpcb_local_clnt4); + rpc_shutdown_client(rpcb_local_clnt); +} diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 8cce921..b836572 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -24,6 +24,9 @@ extern struct cache_detail ip_map_cache, unix_gid_cache; +extern int init_rpcb_clnt(void); +extern void cleanup_rpcb_clnt(void); + static int __init init_sunrpc(void) { @@ -46,6 +49,7 @@ init_sunrpc(void) svc_init_xprt_sock(); /* svc sock transport */ init_socket_xprt(); /* clnt sock transport */ rpcauth_init_module(); + init_rpcb_clnt(); out: return err; } @@ -53,6 +57,7 @@ out: static void __exit cleanup_sunrpc(void) { + cleanup_rpcb_clnt(); rpcauth_remove_module(); cleanup_socket_xprt(); svc_cleanup_xprt_sock(); -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html