aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2009-12-03 15:58:56 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2009-12-03 15:58:56 -0500
commitc526611dd631b2802b6b0221ffb306c5fa25c86c (patch)
tree909f241683fbe848b484cef24a77d716c486d25c
parent5a46211540a83871196489247f57da2bdde58d87 (diff)
SUNRPC: Use a cached RPC client and transport for rpcbind upcalls
The kernel's rpcbind client creates and deletes an rpc_clnt and its underlying transport socket for every upcall to the local rpcbind daemon. When starting a typical NFS server on IPv4 and IPv6, 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. (Currently the NFS service doesn't start IPv6 listeners, but it will soon enough). Instead, let's create an rpc_clnt for rpcbind upcalls during the first local rpcbind query, and cache it. This saves the overhead of creating and destroying an rpc_clnt and a socket for every upcall. The new logic also prevents the kernel from attempting an RPCB_SET or RPCB_UNSET if it knows from the start that the local portmapper does not support rpcbind protocol version 4. This will cut down on the number of rpcbind upcalls in legacy environments. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-rw-r--r--net/sunrpc/rpcb_clnt.c93
-rw-r--r--net/sunrpc/sunrpc_syms.c3
2 files changed, 80 insertions, 16 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 28f50da60ceb..116db74dd942 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -20,6 +20,7 @@
20#include <linux/in6.h> 20#include <linux/in6.h>
21#include <linux/kernel.h> 21#include <linux/kernel.h>
22#include <linux/errno.h> 22#include <linux/errno.h>
23#include <linux/mutex.h>
23#include <net/ipv6.h> 24#include <net/ipv6.h>
24 25
25#include <linux/sunrpc/clnt.h> 26#include <linux/sunrpc/clnt.h>
@@ -110,6 +111,9 @@ static void rpcb_getport_done(struct rpc_task *, void *);
110static void rpcb_map_release(void *data); 111static void rpcb_map_release(void *data);
111static struct rpc_program rpcb_program; 112static struct rpc_program rpcb_program;
112 113
114static struct rpc_clnt * rpcb_local_clnt;
115static struct rpc_clnt * rpcb_local_clnt4;
116
113struct rpcbind_args { 117struct rpcbind_args {
114 struct rpc_xprt * r_xprt; 118 struct rpc_xprt * r_xprt;
115 119
@@ -163,7 +167,13 @@ static const struct sockaddr_in rpcb_inaddr_loopback = {
163 .sin_port = htons(RPCBIND_PORT), 167 .sin_port = htons(RPCBIND_PORT),
164}; 168};
165 169
166static struct rpc_clnt *rpcb_create_local(u32 version) 170static DEFINE_MUTEX(rpcb_create_local_mutex);
171
172/*
173 * Returns zero on success, otherwise a negative errno value
174 * is returned.
175 */
176static int rpcb_create_local(void)
167{ 177{
168 struct rpc_create_args args = { 178 struct rpc_create_args args = {
169 .protocol = XPRT_TRANSPORT_UDP, 179 .protocol = XPRT_TRANSPORT_UDP,
@@ -171,12 +181,46 @@ static struct rpc_clnt *rpcb_create_local(u32 version)
171 .addrsize = sizeof(rpcb_inaddr_loopback), 181 .addrsize = sizeof(rpcb_inaddr_loopback),
172 .servername = "localhost", 182 .servername = "localhost",
173 .program = &rpcb_program, 183 .program = &rpcb_program,
174 .version = version, 184 .version = RPCBVERS_2,
175 .authflavor = RPC_AUTH_UNIX, 185 .authflavor = RPC_AUTH_UNIX,
176 .flags = RPC_CLNT_CREATE_NOPING, 186 .flags = RPC_CLNT_CREATE_NOPING,
177 }; 187 };
188 struct rpc_clnt *clnt, *clnt4;
189 int result = 0;
190
191 if (rpcb_local_clnt)
192 return result;
193
194 mutex_lock(&rpcb_create_local_mutex);
195 if (rpcb_local_clnt)
196 goto out;
197
198 clnt = rpc_create(&args);
199 if (IS_ERR(clnt)) {
200 dprintk("RPC: failed to create local rpcbind "
201 "client (errno %ld).\n", PTR_ERR(clnt));
202 result = -PTR_ERR(clnt);
203 goto out;
204 }
178 205
179 return rpc_create(&args); 206 /*
207 * This results in an RPC ping. On systems running portmapper,
208 * the v4 ping will fail. Proceed anyway, but disallow rpcb
209 * v4 upcalls.
210 */
211 clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4);
212 if (IS_ERR(clnt4)) {
213 dprintk("RPC: failed to create local rpcbind v4 "
214 "cleint (errno %ld).\n", PTR_ERR(clnt4));
215 clnt4 = NULL;
216 }
217
218 rpcb_local_clnt = clnt;
219 rpcb_local_clnt4 = clnt4;
220
221out:
222 mutex_unlock(&rpcb_create_local_mutex);
223 return result;
180} 224}
181 225
182static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, 226static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
@@ -208,20 +252,13 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
208 return rpc_create(&args); 252 return rpc_create(&args);
209} 253}
210 254
211static int rpcb_register_call(const u32 version, struct rpc_message *msg) 255static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg)
212{ 256{
213 struct rpc_clnt *rpcb_clnt;
214 int result, error = 0; 257 int result, error = 0;
215 258
216 msg->rpc_resp = &result; 259 msg->rpc_resp = &result;
217 260
218 rpcb_clnt = rpcb_create_local(version); 261 error = rpc_call_sync(clnt, msg, 0);
219 if (!IS_ERR(rpcb_clnt)) {
220 error = rpc_call_sync(rpcb_clnt, msg, 0);
221 rpc_shutdown_client(rpcb_clnt);
222 } else
223 error = PTR_ERR(rpcb_clnt);
224
225 if (error < 0) { 262 if (error < 0) {
226 dprintk("RPC: failed to contact local rpcbind " 263 dprintk("RPC: failed to contact local rpcbind "
227 "server (errno %d).\n", -error); 264 "server (errno %d).\n", -error);
@@ -276,6 +313,11 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
276 struct rpc_message msg = { 313 struct rpc_message msg = {
277 .rpc_argp = &map, 314 .rpc_argp = &map,
278 }; 315 };
316 int error;
317
318 error = rpcb_create_local();
319 if (error)
320 return error;
279 321
280 dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " 322 dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
281 "rpcbind\n", (port ? "" : "un"), 323 "rpcbind\n", (port ? "" : "un"),
@@ -285,7 +327,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
285 if (port) 327 if (port)
286 msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; 328 msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
287 329
288 return rpcb_register_call(RPCBVERS_2, &msg); 330 return rpcb_register_call(rpcb_local_clnt, &msg);
289} 331}
290 332
291/* 333/*
@@ -310,7 +352,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap,
310 if (port) 352 if (port)
311 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; 353 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
312 354
313 result = rpcb_register_call(RPCBVERS_4, msg); 355 result = rpcb_register_call(rpcb_local_clnt4, msg);
314 kfree(map->r_addr); 356 kfree(map->r_addr);
315 return result; 357 return result;
316} 358}
@@ -337,7 +379,7 @@ static int rpcb_register_inet6(const struct sockaddr *sap,
337 if (port) 379 if (port)
338 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; 380 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
339 381
340 result = rpcb_register_call(RPCBVERS_4, msg); 382 result = rpcb_register_call(rpcb_local_clnt4, msg);
341 kfree(map->r_addr); 383 kfree(map->r_addr);
342 return result; 384 return result;
343} 385}
@@ -353,7 +395,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
353 map->r_addr = ""; 395 map->r_addr = "";
354 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; 396 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
355 397
356 return rpcb_register_call(RPCBVERS_4, msg); 398 return rpcb_register_call(rpcb_local_clnt4, msg);
357} 399}
358 400
359/** 401/**
@@ -411,6 +453,13 @@ int rpcb_v4_register(const u32 program, const u32 version,
411 struct rpc_message msg = { 453 struct rpc_message msg = {
412 .rpc_argp = &map, 454 .rpc_argp = &map,
413 }; 455 };
456 int error;
457
458 error = rpcb_create_local();
459 if (error)
460 return error;
461 if (rpcb_local_clnt4 == NULL)
462 return -EPROTONOSUPPORT;
414 463
415 if (address == NULL) 464 if (address == NULL)
416 return rpcb_unregister_all_protofamilies(&msg); 465 return rpcb_unregister_all_protofamilies(&msg);
@@ -1024,3 +1073,15 @@ static struct rpc_program rpcb_program = {
1024 .version = rpcb_version, 1073 .version = rpcb_version,
1025 .stats = &rpcb_stats, 1074 .stats = &rpcb_stats,
1026}; 1075};
1076
1077/**
1078 * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister
1079 *
1080 */
1081void cleanup_rpcb_clnt(void)
1082{
1083 if (rpcb_local_clnt4)
1084 rpc_shutdown_client(rpcb_local_clnt4);
1085 if (rpcb_local_clnt)
1086 rpc_shutdown_client(rpcb_local_clnt);
1087}
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 8cce92189019..f438347d817b 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -24,6 +24,8 @@
24 24
25extern struct cache_detail ip_map_cache, unix_gid_cache; 25extern struct cache_detail ip_map_cache, unix_gid_cache;
26 26
27extern void cleanup_rpcb_clnt(void);
28
27static int __init 29static int __init
28init_sunrpc(void) 30init_sunrpc(void)
29{ 31{
@@ -53,6 +55,7 @@ out:
53static void __exit 55static void __exit
54cleanup_sunrpc(void) 56cleanup_sunrpc(void)
55{ 57{
58 cleanup_rpcb_clnt();
56 rpcauth_remove_module(); 59 rpcauth_remove_module();
57 cleanup_socket_xprt(); 60 cleanup_socket_xprt();
58 svc_cleanup_xprt_sock(); 61 svc_cleanup_xprt_sock();