diff options
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 105 |
1 files changed, 82 insertions, 23 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 830faf4d9997..121105355f60 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -20,6 +20,8 @@ | |||
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> | ||
24 | #include <linux/slab.h> | ||
23 | #include <net/ipv6.h> | 25 | #include <net/ipv6.h> |
24 | 26 | ||
25 | #include <linux/sunrpc/clnt.h> | 27 | #include <linux/sunrpc/clnt.h> |
@@ -110,6 +112,9 @@ static void rpcb_getport_done(struct rpc_task *, void *); | |||
110 | static void rpcb_map_release(void *data); | 112 | static void rpcb_map_release(void *data); |
111 | static struct rpc_program rpcb_program; | 113 | static struct rpc_program rpcb_program; |
112 | 114 | ||
115 | static struct rpc_clnt * rpcb_local_clnt; | ||
116 | static struct rpc_clnt * rpcb_local_clnt4; | ||
117 | |||
113 | struct rpcbind_args { | 118 | struct rpcbind_args { |
114 | struct rpc_xprt * r_xprt; | 119 | struct rpc_xprt * r_xprt; |
115 | 120 | ||
@@ -163,21 +168,60 @@ static const struct sockaddr_in rpcb_inaddr_loopback = { | |||
163 | .sin_port = htons(RPCBIND_PORT), | 168 | .sin_port = htons(RPCBIND_PORT), |
164 | }; | 169 | }; |
165 | 170 | ||
166 | static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr, | 171 | static DEFINE_MUTEX(rpcb_create_local_mutex); |
167 | size_t addrlen, u32 version) | 172 | |
173 | /* | ||
174 | * Returns zero on success, otherwise a negative errno value | ||
175 | * is returned. | ||
176 | */ | ||
177 | static int rpcb_create_local(void) | ||
168 | { | 178 | { |
169 | struct rpc_create_args args = { | 179 | struct rpc_create_args args = { |
170 | .protocol = XPRT_TRANSPORT_UDP, | 180 | .protocol = XPRT_TRANSPORT_TCP, |
171 | .address = addr, | 181 | .address = (struct sockaddr *)&rpcb_inaddr_loopback, |
172 | .addrsize = addrlen, | 182 | .addrsize = sizeof(rpcb_inaddr_loopback), |
173 | .servername = "localhost", | 183 | .servername = "localhost", |
174 | .program = &rpcb_program, | 184 | .program = &rpcb_program, |
175 | .version = version, | 185 | .version = RPCBVERS_2, |
176 | .authflavor = RPC_AUTH_UNIX, | 186 | .authflavor = RPC_AUTH_UNIX, |
177 | .flags = RPC_CLNT_CREATE_NOPING, | 187 | .flags = RPC_CLNT_CREATE_NOPING, |
178 | }; | 188 | }; |
189 | struct rpc_clnt *clnt, *clnt4; | ||
190 | int result = 0; | ||
191 | |||
192 | if (rpcb_local_clnt) | ||
193 | return result; | ||
194 | |||
195 | mutex_lock(&rpcb_create_local_mutex); | ||
196 | if (rpcb_local_clnt) | ||
197 | goto out; | ||
198 | |||
199 | clnt = rpc_create(&args); | ||
200 | if (IS_ERR(clnt)) { | ||
201 | dprintk("RPC: failed to create local rpcbind " | ||
202 | "client (errno %ld).\n", PTR_ERR(clnt)); | ||
203 | result = -PTR_ERR(clnt); | ||
204 | goto out; | ||
205 | } | ||
179 | 206 | ||
180 | return rpc_create(&args); | 207 | /* |
208 | * This results in an RPC ping. On systems running portmapper, | ||
209 | * the v4 ping will fail. Proceed anyway, but disallow rpcb | ||
210 | * v4 upcalls. | ||
211 | */ | ||
212 | clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4); | ||
213 | if (IS_ERR(clnt4)) { | ||
214 | dprintk("RPC: failed to create local rpcbind v4 " | ||
215 | "cleint (errno %ld).\n", PTR_ERR(clnt4)); | ||
216 | clnt4 = NULL; | ||
217 | } | ||
218 | |||
219 | rpcb_local_clnt = clnt; | ||
220 | rpcb_local_clnt4 = clnt4; | ||
221 | |||
222 | out: | ||
223 | mutex_unlock(&rpcb_create_local_mutex); | ||
224 | return result; | ||
181 | } | 225 | } |
182 | 226 | ||
183 | static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | 227 | static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, |
@@ -209,22 +253,13 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | |||
209 | return rpc_create(&args); | 253 | return rpc_create(&args); |
210 | } | 254 | } |
211 | 255 | ||
212 | static int rpcb_register_call(const u32 version, struct rpc_message *msg) | 256 | static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg) |
213 | { | 257 | { |
214 | struct sockaddr *addr = (struct sockaddr *)&rpcb_inaddr_loopback; | ||
215 | size_t addrlen = sizeof(rpcb_inaddr_loopback); | ||
216 | struct rpc_clnt *rpcb_clnt; | ||
217 | int result, error = 0; | 258 | int result, error = 0; |
218 | 259 | ||
219 | msg->rpc_resp = &result; | 260 | msg->rpc_resp = &result; |
220 | 261 | ||
221 | rpcb_clnt = rpcb_create_local(addr, addrlen, version); | 262 | error = rpc_call_sync(clnt, msg, RPC_TASK_SOFTCONN); |
222 | if (!IS_ERR(rpcb_clnt)) { | ||
223 | error = rpc_call_sync(rpcb_clnt, msg, 0); | ||
224 | rpc_shutdown_client(rpcb_clnt); | ||
225 | } else | ||
226 | error = PTR_ERR(rpcb_clnt); | ||
227 | |||
228 | if (error < 0) { | 263 | if (error < 0) { |
229 | dprintk("RPC: failed to contact local rpcbind " | 264 | dprintk("RPC: failed to contact local rpcbind " |
230 | "server (errno %d).\n", -error); | 265 | "server (errno %d).\n", -error); |
@@ -279,6 +314,11 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) | |||
279 | struct rpc_message msg = { | 314 | struct rpc_message msg = { |
280 | .rpc_argp = &map, | 315 | .rpc_argp = &map, |
281 | }; | 316 | }; |
317 | int error; | ||
318 | |||
319 | error = rpcb_create_local(); | ||
320 | if (error) | ||
321 | return error; | ||
282 | 322 | ||
283 | dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " | 323 | dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " |
284 | "rpcbind\n", (port ? "" : "un"), | 324 | "rpcbind\n", (port ? "" : "un"), |
@@ -288,7 +328,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) | |||
288 | if (port) | 328 | if (port) |
289 | msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; | 329 | msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; |
290 | 330 | ||
291 | return rpcb_register_call(RPCBVERS_2, &msg); | 331 | return rpcb_register_call(rpcb_local_clnt, &msg); |
292 | } | 332 | } |
293 | 333 | ||
294 | /* | 334 | /* |
@@ -313,7 +353,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap, | |||
313 | if (port) | 353 | if (port) |
314 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; | 354 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; |
315 | 355 | ||
316 | result = rpcb_register_call(RPCBVERS_4, msg); | 356 | result = rpcb_register_call(rpcb_local_clnt4, msg); |
317 | kfree(map->r_addr); | 357 | kfree(map->r_addr); |
318 | return result; | 358 | return result; |
319 | } | 359 | } |
@@ -340,7 +380,7 @@ static int rpcb_register_inet6(const struct sockaddr *sap, | |||
340 | if (port) | 380 | if (port) |
341 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; | 381 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; |
342 | 382 | ||
343 | result = rpcb_register_call(RPCBVERS_4, msg); | 383 | result = rpcb_register_call(rpcb_local_clnt4, msg); |
344 | kfree(map->r_addr); | 384 | kfree(map->r_addr); |
345 | return result; | 385 | return result; |
346 | } | 386 | } |
@@ -356,7 +396,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) | |||
356 | map->r_addr = ""; | 396 | map->r_addr = ""; |
357 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; | 397 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; |
358 | 398 | ||
359 | return rpcb_register_call(RPCBVERS_4, msg); | 399 | return rpcb_register_call(rpcb_local_clnt4, msg); |
360 | } | 400 | } |
361 | 401 | ||
362 | /** | 402 | /** |
@@ -414,6 +454,13 @@ int rpcb_v4_register(const u32 program, const u32 version, | |||
414 | struct rpc_message msg = { | 454 | struct rpc_message msg = { |
415 | .rpc_argp = &map, | 455 | .rpc_argp = &map, |
416 | }; | 456 | }; |
457 | int error; | ||
458 | |||
459 | error = rpcb_create_local(); | ||
460 | if (error) | ||
461 | return error; | ||
462 | if (rpcb_local_clnt4 == NULL) | ||
463 | return -EPROTONOSUPPORT; | ||
417 | 464 | ||
418 | if (address == NULL) | 465 | if (address == NULL) |
419 | return rpcb_unregister_all_protofamilies(&msg); | 466 | return rpcb_unregister_all_protofamilies(&msg); |
@@ -491,7 +538,7 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi | |||
491 | .rpc_message = &msg, | 538 | .rpc_message = &msg, |
492 | .callback_ops = &rpcb_getport_ops, | 539 | .callback_ops = &rpcb_getport_ops, |
493 | .callback_data = map, | 540 | .callback_data = map, |
494 | .flags = RPC_TASK_ASYNC, | 541 | .flags = RPC_TASK_ASYNC | RPC_TASK_SOFTCONN, |
495 | }; | 542 | }; |
496 | 543 | ||
497 | return rpc_run_task(&task_setup_data); | 544 | return rpc_run_task(&task_setup_data); |
@@ -1027,3 +1074,15 @@ static struct rpc_program rpcb_program = { | |||
1027 | .version = rpcb_version, | 1074 | .version = rpcb_version, |
1028 | .stats = &rpcb_stats, | 1075 | .stats = &rpcb_stats, |
1029 | }; | 1076 | }; |
1077 | |||
1078 | /** | ||
1079 | * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister | ||
1080 | * | ||
1081 | */ | ||
1082 | void cleanup_rpcb_clnt(void) | ||
1083 | { | ||
1084 | if (rpcb_local_clnt4) | ||
1085 | rpc_shutdown_client(rpcb_local_clnt4); | ||
1086 | if (rpcb_local_clnt) | ||
1087 | rpc_shutdown_client(rpcb_local_clnt); | ||
1088 | } | ||