diff options
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 93 |
1 files changed, 77 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 *); | |||
110 | static void rpcb_map_release(void *data); | 111 | static void rpcb_map_release(void *data); |
111 | static struct rpc_program rpcb_program; | 112 | static struct rpc_program rpcb_program; |
112 | 113 | ||
114 | static struct rpc_clnt * rpcb_local_clnt; | ||
115 | static struct rpc_clnt * rpcb_local_clnt4; | ||
116 | |||
113 | struct rpcbind_args { | 117 | struct 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 | ||
166 | static struct rpc_clnt *rpcb_create_local(u32 version) | 170 | static DEFINE_MUTEX(rpcb_create_local_mutex); |
171 | |||
172 | /* | ||
173 | * Returns zero on success, otherwise a negative errno value | ||
174 | * is returned. | ||
175 | */ | ||
176 | static 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 | |||
221 | out: | ||
222 | mutex_unlock(&rpcb_create_local_mutex); | ||
223 | return result; | ||
180 | } | 224 | } |
181 | 225 | ||
182 | static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | 226 | static 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 | ||
211 | static int rpcb_register_call(const u32 version, struct rpc_message *msg) | 255 | static 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 | */ | ||
1081 | void 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 | } | ||