diff options
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 121 |
1 files changed, 68 insertions, 53 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 24db2b4d12d3..41013dd66ac3 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 <net/ipv6.h> | ||
23 | 24 | ||
24 | #include <linux/sunrpc/clnt.h> | 25 | #include <linux/sunrpc/clnt.h> |
25 | #include <linux/sunrpc/sched.h> | 26 | #include <linux/sunrpc/sched.h> |
@@ -176,13 +177,12 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | |||
176 | } | 177 | } |
177 | 178 | ||
178 | static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, | 179 | static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, |
179 | u32 version, struct rpc_message *msg, | 180 | u32 version, struct rpc_message *msg) |
180 | int *result) | ||
181 | { | 181 | { |
182 | struct rpc_clnt *rpcb_clnt; | 182 | struct rpc_clnt *rpcb_clnt; |
183 | int error = 0; | 183 | int result, error = 0; |
184 | 184 | ||
185 | *result = 0; | 185 | msg->rpc_resp = &result; |
186 | 186 | ||
187 | rpcb_clnt = rpcb_create_local(addr, addrlen, version); | 187 | rpcb_clnt = rpcb_create_local(addr, addrlen, version); |
188 | if (!IS_ERR(rpcb_clnt)) { | 188 | if (!IS_ERR(rpcb_clnt)) { |
@@ -191,12 +191,15 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, | |||
191 | } else | 191 | } else |
192 | error = PTR_ERR(rpcb_clnt); | 192 | error = PTR_ERR(rpcb_clnt); |
193 | 193 | ||
194 | if (error < 0) | 194 | if (error < 0) { |
195 | printk(KERN_WARNING "RPC: failed to contact local rpcbind " | 195 | printk(KERN_WARNING "RPC: failed to contact local rpcbind " |
196 | "server (errno %d).\n", -error); | 196 | "server (errno %d).\n", -error); |
197 | dprintk("RPC: registration status %d/%d\n", error, *result); | 197 | return error; |
198 | } | ||
198 | 199 | ||
199 | return error; | 200 | if (!result) |
201 | return -EACCES; | ||
202 | return 0; | ||
200 | } | 203 | } |
201 | 204 | ||
202 | /** | 205 | /** |
@@ -205,7 +208,11 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, | |||
205 | * @vers: RPC version number to bind | 208 | * @vers: RPC version number to bind |
206 | * @prot: transport protocol to register | 209 | * @prot: transport protocol to register |
207 | * @port: port value to register | 210 | * @port: port value to register |
208 | * @okay: OUT: result code | 211 | * |
212 | * Returns zero if the registration request was dispatched successfully | ||
213 | * and the rpcbind daemon returned success. Otherwise, returns an errno | ||
214 | * value that reflects the nature of the error (request could not be | ||
215 | * dispatched, timed out, or rpcbind returned an error). | ||
209 | * | 216 | * |
210 | * RPC services invoke this function to advertise their contact | 217 | * RPC services invoke this function to advertise their contact |
211 | * information via the system's rpcbind daemon. RPC services | 218 | * information via the system's rpcbind daemon. RPC services |
@@ -217,15 +224,6 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, | |||
217 | * all registered transports for [program, version] from the local | 224 | * all registered transports for [program, version] from the local |
218 | * rpcbind database. | 225 | * rpcbind database. |
219 | * | 226 | * |
220 | * Returns zero if the registration request was dispatched | ||
221 | * successfully and a reply was received. The rpcbind daemon's | ||
222 | * boolean result code is stored in *okay. | ||
223 | * | ||
224 | * Returns an errno value and sets *result to zero if there was | ||
225 | * some problem that prevented the rpcbind request from being | ||
226 | * dispatched, or if the rpcbind daemon did not respond within | ||
227 | * the timeout. | ||
228 | * | ||
229 | * This function uses rpcbind protocol version 2 to contact the | 227 | * This function uses rpcbind protocol version 2 to contact the |
230 | * local rpcbind daemon. | 228 | * local rpcbind daemon. |
231 | * | 229 | * |
@@ -236,7 +234,7 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, | |||
236 | * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 | 234 | * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 |
237 | * addresses). | 235 | * addresses). |
238 | */ | 236 | */ |
239 | int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | 237 | int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) |
240 | { | 238 | { |
241 | struct rpcbind_args map = { | 239 | struct rpcbind_args map = { |
242 | .r_prog = prog, | 240 | .r_prog = prog, |
@@ -246,7 +244,6 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |||
246 | }; | 244 | }; |
247 | struct rpc_message msg = { | 245 | struct rpc_message msg = { |
248 | .rpc_argp = &map, | 246 | .rpc_argp = &map, |
249 | .rpc_resp = okay, | ||
250 | }; | 247 | }; |
251 | 248 | ||
252 | dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " | 249 | dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " |
@@ -259,7 +256,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |||
259 | 256 | ||
260 | return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, | 257 | return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, |
261 | sizeof(rpcb_inaddr_loopback), | 258 | sizeof(rpcb_inaddr_loopback), |
262 | RPCBVERS_2, &msg, okay); | 259 | RPCBVERS_2, &msg); |
263 | } | 260 | } |
264 | 261 | ||
265 | /* | 262 | /* |
@@ -290,7 +287,7 @@ static int rpcb_register_netid4(struct sockaddr_in *address_to_register, | |||
290 | 287 | ||
291 | return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, | 288 | return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, |
292 | sizeof(rpcb_inaddr_loopback), | 289 | sizeof(rpcb_inaddr_loopback), |
293 | RPCBVERS_4, msg, msg->rpc_resp); | 290 | RPCBVERS_4, msg); |
294 | } | 291 | } |
295 | 292 | ||
296 | /* | 293 | /* |
@@ -304,10 +301,13 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, | |||
304 | char buf[64]; | 301 | char buf[64]; |
305 | 302 | ||
306 | /* Construct AF_INET6 universal address */ | 303 | /* Construct AF_INET6 universal address */ |
307 | snprintf(buf, sizeof(buf), | 304 | if (ipv6_addr_any(&address_to_register->sin6_addr)) |
308 | NIP6_FMT".%u.%u", | 305 | snprintf(buf, sizeof(buf), "::.%u.%u", |
309 | NIP6(address_to_register->sin6_addr), | 306 | port >> 8, port & 0xff); |
310 | port >> 8, port & 0xff); | 307 | else |
308 | snprintf(buf, sizeof(buf), NIP6_FMT".%u.%u", | ||
309 | NIP6(address_to_register->sin6_addr), | ||
310 | port >> 8, port & 0xff); | ||
311 | map->r_addr = buf; | 311 | map->r_addr = buf; |
312 | 312 | ||
313 | dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " | 313 | dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " |
@@ -321,7 +321,7 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, | |||
321 | 321 | ||
322 | return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback, | 322 | return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback, |
323 | sizeof(rpcb_in6addr_loopback), | 323 | sizeof(rpcb_in6addr_loopback), |
324 | RPCBVERS_4, msg, msg->rpc_resp); | 324 | RPCBVERS_4, msg); |
325 | } | 325 | } |
326 | 326 | ||
327 | /** | 327 | /** |
@@ -330,7 +330,11 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, | |||
330 | * @version: RPC version number of service to (un)register | 330 | * @version: RPC version number of service to (un)register |
331 | * @address: address family, IP address, and port to (un)register | 331 | * @address: address family, IP address, and port to (un)register |
332 | * @netid: netid of transport protocol to (un)register | 332 | * @netid: netid of transport protocol to (un)register |
333 | * @result: result code from rpcbind RPC call | 333 | * |
334 | * Returns zero if the registration request was dispatched successfully | ||
335 | * and the rpcbind daemon returned success. Otherwise, returns an errno | ||
336 | * value that reflects the nature of the error (request could not be | ||
337 | * dispatched, timed out, or rpcbind returned an error). | ||
334 | * | 338 | * |
335 | * RPC services invoke this function to advertise their contact | 339 | * RPC services invoke this function to advertise their contact |
336 | * information via the system's rpcbind daemon. RPC services | 340 | * information via the system's rpcbind daemon. RPC services |
@@ -342,15 +346,6 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, | |||
342 | * to zero. Callers pass a netid of "" to unregister all | 346 | * to zero. Callers pass a netid of "" to unregister all |
343 | * transport netids associated with [program, version, address]. | 347 | * transport netids associated with [program, version, address]. |
344 | * | 348 | * |
345 | * Returns zero if the registration request was dispatched | ||
346 | * successfully and a reply was received. The rpcbind daemon's | ||
347 | * result code is stored in *result. | ||
348 | * | ||
349 | * Returns an errno value and sets *result to zero if there was | ||
350 | * some problem that prevented the rpcbind request from being | ||
351 | * dispatched, or if the rpcbind daemon did not respond within | ||
352 | * the timeout. | ||
353 | * | ||
354 | * This function uses rpcbind protocol version 4 to contact the | 349 | * This function uses rpcbind protocol version 4 to contact the |
355 | * local rpcbind daemon. The local rpcbind daemon must support | 350 | * local rpcbind daemon. The local rpcbind daemon must support |
356 | * version 4 of the rpcbind protocol in order for these functions | 351 | * version 4 of the rpcbind protocol in order for these functions |
@@ -372,8 +367,7 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, | |||
372 | * advertises the service on all IPv4 and IPv6 addresses. | 367 | * advertises the service on all IPv4 and IPv6 addresses. |
373 | */ | 368 | */ |
374 | int rpcb_v4_register(const u32 program, const u32 version, | 369 | int rpcb_v4_register(const u32 program, const u32 version, |
375 | const struct sockaddr *address, const char *netid, | 370 | const struct sockaddr *address, const char *netid) |
376 | int *result) | ||
377 | { | 371 | { |
378 | struct rpcbind_args map = { | 372 | struct rpcbind_args map = { |
379 | .r_prog = program, | 373 | .r_prog = program, |
@@ -383,11 +377,8 @@ int rpcb_v4_register(const u32 program, const u32 version, | |||
383 | }; | 377 | }; |
384 | struct rpc_message msg = { | 378 | struct rpc_message msg = { |
385 | .rpc_argp = &map, | 379 | .rpc_argp = &map, |
386 | .rpc_resp = result, | ||
387 | }; | 380 | }; |
388 | 381 | ||
389 | *result = 0; | ||
390 | |||
391 | switch (address->sa_family) { | 382 | switch (address->sa_family) { |
392 | case AF_INET: | 383 | case AF_INET: |
393 | return rpcb_register_netid4((struct sockaddr_in *)address, | 384 | return rpcb_register_netid4((struct sockaddr_in *)address, |
@@ -469,6 +460,28 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi | |||
469 | return rpc_run_task(&task_setup_data); | 460 | return rpc_run_task(&task_setup_data); |
470 | } | 461 | } |
471 | 462 | ||
463 | /* | ||
464 | * In the case where rpc clients have been cloned, we want to make | ||
465 | * sure that we use the program number/version etc of the actual | ||
466 | * owner of the xprt. To do so, we walk back up the tree of parents | ||
467 | * to find whoever created the transport and/or whoever has the | ||
468 | * autobind flag set. | ||
469 | */ | ||
470 | static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) | ||
471 | { | ||
472 | struct rpc_clnt *parent = clnt->cl_parent; | ||
473 | |||
474 | while (parent != clnt) { | ||
475 | if (parent->cl_xprt != clnt->cl_xprt) | ||
476 | break; | ||
477 | if (clnt->cl_autobind) | ||
478 | break; | ||
479 | clnt = parent; | ||
480 | parent = parent->cl_parent; | ||
481 | } | ||
482 | return clnt; | ||
483 | } | ||
484 | |||
472 | /** | 485 | /** |
473 | * rpcb_getport_async - obtain the port for a given RPC service on a given host | 486 | * rpcb_getport_async - obtain the port for a given RPC service on a given host |
474 | * @task: task that is waiting for portmapper request | 487 | * @task: task that is waiting for portmapper request |
@@ -478,10 +491,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi | |||
478 | */ | 491 | */ |
479 | void rpcb_getport_async(struct rpc_task *task) | 492 | void rpcb_getport_async(struct rpc_task *task) |
480 | { | 493 | { |
481 | struct rpc_clnt *clnt = task->tk_client; | 494 | struct rpc_clnt *clnt; |
482 | struct rpc_procinfo *proc; | 495 | struct rpc_procinfo *proc; |
483 | u32 bind_version; | 496 | u32 bind_version; |
484 | struct rpc_xprt *xprt = task->tk_xprt; | 497 | struct rpc_xprt *xprt; |
485 | struct rpc_clnt *rpcb_clnt; | 498 | struct rpc_clnt *rpcb_clnt; |
486 | static struct rpcbind_args *map; | 499 | static struct rpcbind_args *map; |
487 | struct rpc_task *child; | 500 | struct rpc_task *child; |
@@ -490,13 +503,13 @@ void rpcb_getport_async(struct rpc_task *task) | |||
490 | size_t salen; | 503 | size_t salen; |
491 | int status; | 504 | int status; |
492 | 505 | ||
506 | clnt = rpcb_find_transport_owner(task->tk_client); | ||
507 | xprt = clnt->cl_xprt; | ||
508 | |||
493 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", | 509 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", |
494 | task->tk_pid, __func__, | 510 | task->tk_pid, __func__, |
495 | clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); | 511 | clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); |
496 | 512 | ||
497 | /* Autobind on cloned rpc clients is discouraged */ | ||
498 | BUG_ON(clnt->cl_parent != clnt); | ||
499 | |||
500 | /* Put self on the wait queue to ensure we get notified if | 513 | /* Put self on the wait queue to ensure we get notified if |
501 | * some other task is already attempting to bind the port */ | 514 | * some other task is already attempting to bind the port */ |
502 | rpc_sleep_on(&xprt->binding, task, NULL); | 515 | rpc_sleep_on(&xprt->binding, task, NULL); |
@@ -558,7 +571,7 @@ void rpcb_getport_async(struct rpc_task *task) | |||
558 | status = -ENOMEM; | 571 | status = -ENOMEM; |
559 | dprintk("RPC: %5u %s: no memory available\n", | 572 | dprintk("RPC: %5u %s: no memory available\n", |
560 | task->tk_pid, __func__); | 573 | task->tk_pid, __func__); |
561 | goto bailout_nofree; | 574 | goto bailout_release_client; |
562 | } | 575 | } |
563 | map->r_prog = clnt->cl_prog; | 576 | map->r_prog = clnt->cl_prog; |
564 | map->r_vers = clnt->cl_vers; | 577 | map->r_vers = clnt->cl_vers; |
@@ -578,11 +591,13 @@ void rpcb_getport_async(struct rpc_task *task) | |||
578 | task->tk_pid, __func__); | 591 | task->tk_pid, __func__); |
579 | return; | 592 | return; |
580 | } | 593 | } |
581 | rpc_put_task(child); | ||
582 | 594 | ||
583 | task->tk_xprt->stat.bind_count++; | 595 | xprt->stat.bind_count++; |
596 | rpc_put_task(child); | ||
584 | return; | 597 | return; |
585 | 598 | ||
599 | bailout_release_client: | ||
600 | rpc_release_client(rpcb_clnt); | ||
586 | bailout_nofree: | 601 | bailout_nofree: |
587 | rpcb_wake_rpcbind_waiters(xprt, status); | 602 | rpcb_wake_rpcbind_waiters(xprt, status); |
588 | task->tk_status = status; | 603 | task->tk_status = status; |
@@ -633,7 +648,7 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) | |||
633 | static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p, | 648 | static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p, |
634 | struct rpcbind_args *rpcb) | 649 | struct rpcbind_args *rpcb) |
635 | { | 650 | { |
636 | dprintk("RPC: rpcb_encode_mapping(%u, %u, %d, %u)\n", | 651 | dprintk("RPC: encoding rpcb request (%u, %u, %d, %u)\n", |
637 | rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port); | 652 | rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port); |
638 | *p++ = htonl(rpcb->r_prog); | 653 | *p++ = htonl(rpcb->r_prog); |
639 | *p++ = htonl(rpcb->r_vers); | 654 | *p++ = htonl(rpcb->r_vers); |
@@ -648,7 +663,7 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p, | |||
648 | unsigned short *portp) | 663 | unsigned short *portp) |
649 | { | 664 | { |
650 | *portp = (unsigned short) ntohl(*p++); | 665 | *portp = (unsigned short) ntohl(*p++); |
651 | dprintk("RPC: rpcb_decode_getport result %u\n", | 666 | dprintk("RPC: rpcb getport result: %u\n", |
652 | *portp); | 667 | *portp); |
653 | return 0; | 668 | return 0; |
654 | } | 669 | } |
@@ -657,7 +672,7 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p, | |||
657 | unsigned int *boolp) | 672 | unsigned int *boolp) |
658 | { | 673 | { |
659 | *boolp = (unsigned int) ntohl(*p++); | 674 | *boolp = (unsigned int) ntohl(*p++); |
660 | dprintk("RPC: rpcb_decode_set: call %s\n", | 675 | dprintk("RPC: rpcb set/unset call %s\n", |
661 | (*boolp ? "succeeded" : "failed")); | 676 | (*boolp ? "succeeded" : "failed")); |
662 | return 0; | 677 | return 0; |
663 | } | 678 | } |
@@ -665,7 +680,7 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p, | |||
665 | static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p, | 680 | static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p, |
666 | struct rpcbind_args *rpcb) | 681 | struct rpcbind_args *rpcb) |
667 | { | 682 | { |
668 | dprintk("RPC: rpcb_encode_getaddr(%u, %u, %s)\n", | 683 | dprintk("RPC: encoding rpcb request (%u, %u, %s)\n", |
669 | rpcb->r_prog, rpcb->r_vers, rpcb->r_addr); | 684 | rpcb->r_prog, rpcb->r_vers, rpcb->r_addr); |
670 | *p++ = htonl(rpcb->r_prog); | 685 | *p++ = htonl(rpcb->r_prog); |
671 | *p++ = htonl(rpcb->r_vers); | 686 | *p++ = htonl(rpcb->r_vers); |