diff options
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 57 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 148 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 63 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 47 |
4 files changed, 234 insertions, 81 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 084656671d6e..97912b40c254 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -420,41 +420,53 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg) | |||
420 | memcpy(gss_msg->databuf, &uid, sizeof(uid)); | 420 | memcpy(gss_msg->databuf, &uid, sizeof(uid)); |
421 | gss_msg->msg.data = gss_msg->databuf; | 421 | gss_msg->msg.data = gss_msg->databuf; |
422 | gss_msg->msg.len = sizeof(uid); | 422 | gss_msg->msg.len = sizeof(uid); |
423 | BUG_ON(sizeof(uid) > UPCALL_BUF_LEN); | 423 | |
424 | BUILD_BUG_ON(sizeof(uid) > sizeof(gss_msg->databuf)); | ||
424 | } | 425 | } |
425 | 426 | ||
426 | static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | 427 | static int gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, |
427 | const char *service_name, | 428 | const char *service_name, |
428 | const char *target_name) | 429 | const char *target_name) |
429 | { | 430 | { |
430 | struct gss_api_mech *mech = gss_msg->auth->mech; | 431 | struct gss_api_mech *mech = gss_msg->auth->mech; |
431 | char *p = gss_msg->databuf; | 432 | char *p = gss_msg->databuf; |
432 | int len = 0; | 433 | size_t buflen = sizeof(gss_msg->databuf); |
433 | 434 | int len; | |
434 | gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ", | 435 | |
435 | mech->gm_name, | 436 | len = scnprintf(p, buflen, "mech=%s uid=%d ", mech->gm_name, |
436 | from_kuid(&init_user_ns, gss_msg->uid)); | 437 | from_kuid(&init_user_ns, gss_msg->uid)); |
437 | p += gss_msg->msg.len; | 438 | buflen -= len; |
439 | p += len; | ||
440 | gss_msg->msg.len = len; | ||
438 | if (target_name) { | 441 | if (target_name) { |
439 | len = sprintf(p, "target=%s ", target_name); | 442 | len = scnprintf(p, buflen, "target=%s ", target_name); |
443 | buflen -= len; | ||
440 | p += len; | 444 | p += len; |
441 | gss_msg->msg.len += len; | 445 | gss_msg->msg.len += len; |
442 | } | 446 | } |
443 | if (service_name != NULL) { | 447 | if (service_name != NULL) { |
444 | len = sprintf(p, "service=%s ", service_name); | 448 | len = scnprintf(p, buflen, "service=%s ", service_name); |
449 | buflen -= len; | ||
445 | p += len; | 450 | p += len; |
446 | gss_msg->msg.len += len; | 451 | gss_msg->msg.len += len; |
447 | } | 452 | } |
448 | if (mech->gm_upcall_enctypes) { | 453 | if (mech->gm_upcall_enctypes) { |
449 | len = sprintf(p, "enctypes=%s ", mech->gm_upcall_enctypes); | 454 | len = scnprintf(p, buflen, "enctypes=%s ", |
455 | mech->gm_upcall_enctypes); | ||
456 | buflen -= len; | ||
450 | p += len; | 457 | p += len; |
451 | gss_msg->msg.len += len; | 458 | gss_msg->msg.len += len; |
452 | } | 459 | } |
453 | len = sprintf(p, "\n"); | 460 | len = scnprintf(p, buflen, "\n"); |
461 | if (len == 0) | ||
462 | goto out_overflow; | ||
454 | gss_msg->msg.len += len; | 463 | gss_msg->msg.len += len; |
455 | 464 | ||
456 | gss_msg->msg.data = gss_msg->databuf; | 465 | gss_msg->msg.data = gss_msg->databuf; |
457 | BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN); | 466 | return 0; |
467 | out_overflow: | ||
468 | WARN_ON_ONCE(1); | ||
469 | return -ENOMEM; | ||
458 | } | 470 | } |
459 | 471 | ||
460 | static struct gss_upcall_msg * | 472 | static struct gss_upcall_msg * |
@@ -463,15 +475,15 @@ gss_alloc_msg(struct gss_auth *gss_auth, | |||
463 | { | 475 | { |
464 | struct gss_upcall_msg *gss_msg; | 476 | struct gss_upcall_msg *gss_msg; |
465 | int vers; | 477 | int vers; |
478 | int err = -ENOMEM; | ||
466 | 479 | ||
467 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); | 480 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); |
468 | if (gss_msg == NULL) | 481 | if (gss_msg == NULL) |
469 | return ERR_PTR(-ENOMEM); | 482 | goto err; |
470 | vers = get_pipe_version(gss_auth->net); | 483 | vers = get_pipe_version(gss_auth->net); |
471 | if (vers < 0) { | 484 | err = vers; |
472 | kfree(gss_msg); | 485 | if (err < 0) |
473 | return ERR_PTR(vers); | 486 | goto err_free_msg; |
474 | } | ||
475 | gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe; | 487 | gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe; |
476 | INIT_LIST_HEAD(&gss_msg->list); | 488 | INIT_LIST_HEAD(&gss_msg->list); |
477 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); | 489 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); |
@@ -482,10 +494,17 @@ gss_alloc_msg(struct gss_auth *gss_auth, | |||
482 | switch (vers) { | 494 | switch (vers) { |
483 | case 0: | 495 | case 0: |
484 | gss_encode_v0_msg(gss_msg); | 496 | gss_encode_v0_msg(gss_msg); |
497 | break; | ||
485 | default: | 498 | default: |
486 | gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name); | 499 | err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name); |
500 | if (err) | ||
501 | goto err_free_msg; | ||
487 | }; | 502 | }; |
488 | return gss_msg; | 503 | return gss_msg; |
504 | err_free_msg: | ||
505 | kfree(gss_msg); | ||
506 | err: | ||
507 | return ERR_PTR(err); | ||
489 | } | 508 | } |
490 | 509 | ||
491 | static struct gss_upcall_msg * | 510 | static struct gss_upcall_msg * |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 77479606a971..dab09dac8fc7 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -25,12 +25,12 @@ | |||
25 | #include <linux/namei.h> | 25 | #include <linux/namei.h> |
26 | #include <linux/mount.h> | 26 | #include <linux/mount.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/rcupdate.h> | ||
28 | #include <linux/utsname.h> | 29 | #include <linux/utsname.h> |
29 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
30 | #include <linux/in.h> | 31 | #include <linux/in.h> |
31 | #include <linux/in6.h> | 32 | #include <linux/in6.h> |
32 | #include <linux/un.h> | 33 | #include <linux/un.h> |
33 | #include <linux/rcupdate.h> | ||
34 | 34 | ||
35 | #include <linux/sunrpc/clnt.h> | 35 | #include <linux/sunrpc/clnt.h> |
36 | #include <linux/sunrpc/addr.h> | 36 | #include <linux/sunrpc/addr.h> |
@@ -264,6 +264,26 @@ void rpc_clients_notifier_unregister(void) | |||
264 | return rpc_pipefs_notifier_unregister(&rpc_clients_block); | 264 | return rpc_pipefs_notifier_unregister(&rpc_clients_block); |
265 | } | 265 | } |
266 | 266 | ||
267 | static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt, | ||
268 | struct rpc_xprt *xprt, | ||
269 | const struct rpc_timeout *timeout) | ||
270 | { | ||
271 | struct rpc_xprt *old; | ||
272 | |||
273 | spin_lock(&clnt->cl_lock); | ||
274 | old = rcu_dereference_protected(clnt->cl_xprt, | ||
275 | lockdep_is_held(&clnt->cl_lock)); | ||
276 | |||
277 | if (!xprt_bound(xprt)) | ||
278 | clnt->cl_autobind = 1; | ||
279 | |||
280 | clnt->cl_timeout = timeout; | ||
281 | rcu_assign_pointer(clnt->cl_xprt, xprt); | ||
282 | spin_unlock(&clnt->cl_lock); | ||
283 | |||
284 | return old; | ||
285 | } | ||
286 | |||
267 | static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename) | 287 | static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename) |
268 | { | 288 | { |
269 | clnt->cl_nodelen = strlen(nodename); | 289 | clnt->cl_nodelen = strlen(nodename); |
@@ -272,12 +292,13 @@ static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename) | |||
272 | memcpy(clnt->cl_nodename, nodename, clnt->cl_nodelen); | 292 | memcpy(clnt->cl_nodename, nodename, clnt->cl_nodelen); |
273 | } | 293 | } |
274 | 294 | ||
275 | static int rpc_client_register(const struct rpc_create_args *args, | 295 | static int rpc_client_register(struct rpc_clnt *clnt, |
276 | struct rpc_clnt *clnt) | 296 | rpc_authflavor_t pseudoflavor, |
297 | const char *client_name) | ||
277 | { | 298 | { |
278 | struct rpc_auth_create_args auth_args = { | 299 | struct rpc_auth_create_args auth_args = { |
279 | .pseudoflavor = args->authflavor, | 300 | .pseudoflavor = pseudoflavor, |
280 | .target_name = args->client_name, | 301 | .target_name = client_name, |
281 | }; | 302 | }; |
282 | struct rpc_auth *auth; | 303 | struct rpc_auth *auth; |
283 | struct net *net = rpc_net_ns(clnt); | 304 | struct net *net = rpc_net_ns(clnt); |
@@ -298,7 +319,7 @@ static int rpc_client_register(const struct rpc_create_args *args, | |||
298 | auth = rpcauth_create(&auth_args, clnt); | 319 | auth = rpcauth_create(&auth_args, clnt); |
299 | if (IS_ERR(auth)) { | 320 | if (IS_ERR(auth)) { |
300 | dprintk("RPC: Couldn't create auth handle (flavor %u)\n", | 321 | dprintk("RPC: Couldn't create auth handle (flavor %u)\n", |
301 | args->authflavor); | 322 | pseudoflavor); |
302 | err = PTR_ERR(auth); | 323 | err = PTR_ERR(auth); |
303 | goto err_auth; | 324 | goto err_auth; |
304 | } | 325 | } |
@@ -337,7 +358,8 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, | |||
337 | { | 358 | { |
338 | const struct rpc_program *program = args->program; | 359 | const struct rpc_program *program = args->program; |
339 | const struct rpc_version *version; | 360 | const struct rpc_version *version; |
340 | struct rpc_clnt *clnt = NULL; | 361 | struct rpc_clnt *clnt = NULL; |
362 | const struct rpc_timeout *timeout; | ||
341 | int err; | 363 | int err; |
342 | 364 | ||
343 | /* sanity check the name before trying to print it */ | 365 | /* sanity check the name before trying to print it */ |
@@ -365,7 +387,6 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, | |||
365 | if (err) | 387 | if (err) |
366 | goto out_no_clid; | 388 | goto out_no_clid; |
367 | 389 | ||
368 | rcu_assign_pointer(clnt->cl_xprt, xprt); | ||
369 | clnt->cl_procinfo = version->procs; | 390 | clnt->cl_procinfo = version->procs; |
370 | clnt->cl_maxproc = version->nrprocs; | 391 | clnt->cl_maxproc = version->nrprocs; |
371 | clnt->cl_prog = args->prognumber ? : program->number; | 392 | clnt->cl_prog = args->prognumber ? : program->number; |
@@ -380,16 +401,15 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, | |||
380 | INIT_LIST_HEAD(&clnt->cl_tasks); | 401 | INIT_LIST_HEAD(&clnt->cl_tasks); |
381 | spin_lock_init(&clnt->cl_lock); | 402 | spin_lock_init(&clnt->cl_lock); |
382 | 403 | ||
383 | if (!xprt_bound(xprt)) | 404 | timeout = xprt->timeout; |
384 | clnt->cl_autobind = 1; | ||
385 | |||
386 | clnt->cl_timeout = xprt->timeout; | ||
387 | if (args->timeout != NULL) { | 405 | if (args->timeout != NULL) { |
388 | memcpy(&clnt->cl_timeout_default, args->timeout, | 406 | memcpy(&clnt->cl_timeout_default, args->timeout, |
389 | sizeof(clnt->cl_timeout_default)); | 407 | sizeof(clnt->cl_timeout_default)); |
390 | clnt->cl_timeout = &clnt->cl_timeout_default; | 408 | timeout = &clnt->cl_timeout_default; |
391 | } | 409 | } |
392 | 410 | ||
411 | rpc_clnt_set_transport(clnt, xprt, timeout); | ||
412 | |||
393 | clnt->cl_rtt = &clnt->cl_rtt_default; | 413 | clnt->cl_rtt = &clnt->cl_rtt_default; |
394 | rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval); | 414 | rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval); |
395 | 415 | ||
@@ -398,7 +418,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, | |||
398 | /* save the nodename */ | 418 | /* save the nodename */ |
399 | rpc_clnt_set_nodename(clnt, utsname()->nodename); | 419 | rpc_clnt_set_nodename(clnt, utsname()->nodename); |
400 | 420 | ||
401 | err = rpc_client_register(args, clnt); | 421 | err = rpc_client_register(clnt, args->authflavor, args->client_name); |
402 | if (err) | 422 | if (err) |
403 | goto out_no_path; | 423 | goto out_no_path; |
404 | if (parent) | 424 | if (parent) |
@@ -600,6 +620,80 @@ rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
600 | } | 620 | } |
601 | EXPORT_SYMBOL_GPL(rpc_clone_client_set_auth); | 621 | EXPORT_SYMBOL_GPL(rpc_clone_client_set_auth); |
602 | 622 | ||
623 | /** | ||
624 | * rpc_switch_client_transport: switch the RPC transport on the fly | ||
625 | * @clnt: pointer to a struct rpc_clnt | ||
626 | * @args: pointer to the new transport arguments | ||
627 | * @timeout: pointer to the new timeout parameters | ||
628 | * | ||
629 | * This function allows the caller to switch the RPC transport for the | ||
630 | * rpc_clnt structure 'clnt' to allow it to connect to a mirrored NFS | ||
631 | * server, for instance. It assumes that the caller has ensured that | ||
632 | * there are no active RPC tasks by using some form of locking. | ||
633 | * | ||
634 | * Returns zero if "clnt" is now using the new xprt. Otherwise a | ||
635 | * negative errno is returned, and "clnt" continues to use the old | ||
636 | * xprt. | ||
637 | */ | ||
638 | int rpc_switch_client_transport(struct rpc_clnt *clnt, | ||
639 | struct xprt_create *args, | ||
640 | const struct rpc_timeout *timeout) | ||
641 | { | ||
642 | const struct rpc_timeout *old_timeo; | ||
643 | rpc_authflavor_t pseudoflavor; | ||
644 | struct rpc_xprt *xprt, *old; | ||
645 | struct rpc_clnt *parent; | ||
646 | int err; | ||
647 | |||
648 | xprt = xprt_create_transport(args); | ||
649 | if (IS_ERR(xprt)) { | ||
650 | dprintk("RPC: failed to create new xprt for clnt %p\n", | ||
651 | clnt); | ||
652 | return PTR_ERR(xprt); | ||
653 | } | ||
654 | |||
655 | pseudoflavor = clnt->cl_auth->au_flavor; | ||
656 | |||
657 | old_timeo = clnt->cl_timeout; | ||
658 | old = rpc_clnt_set_transport(clnt, xprt, timeout); | ||
659 | |||
660 | rpc_unregister_client(clnt); | ||
661 | __rpc_clnt_remove_pipedir(clnt); | ||
662 | |||
663 | /* | ||
664 | * A new transport was created. "clnt" therefore | ||
665 | * becomes the root of a new cl_parent tree. clnt's | ||
666 | * children, if it has any, still point to the old xprt. | ||
667 | */ | ||
668 | parent = clnt->cl_parent; | ||
669 | clnt->cl_parent = clnt; | ||
670 | |||
671 | /* | ||
672 | * The old rpc_auth cache cannot be re-used. GSS | ||
673 | * contexts in particular are between a single | ||
674 | * client and server. | ||
675 | */ | ||
676 | err = rpc_client_register(clnt, pseudoflavor, NULL); | ||
677 | if (err) | ||
678 | goto out_revert; | ||
679 | |||
680 | synchronize_rcu(); | ||
681 | if (parent != clnt) | ||
682 | rpc_release_client(parent); | ||
683 | xprt_put(old); | ||
684 | dprintk("RPC: replaced xprt for clnt %p\n", clnt); | ||
685 | return 0; | ||
686 | |||
687 | out_revert: | ||
688 | rpc_clnt_set_transport(clnt, old, old_timeo); | ||
689 | clnt->cl_parent = parent; | ||
690 | rpc_client_register(clnt, pseudoflavor, NULL); | ||
691 | xprt_put(xprt); | ||
692 | dprintk("RPC: failed to switch xprt for clnt %p\n", clnt); | ||
693 | return err; | ||
694 | } | ||
695 | EXPORT_SYMBOL_GPL(rpc_switch_client_transport); | ||
696 | |||
603 | /* | 697 | /* |
604 | * Kill all tasks for the given client. | 698 | * Kill all tasks for the given client. |
605 | * XXX: kill their descendants as well? | 699 | * XXX: kill their descendants as well? |
@@ -772,6 +866,8 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) | |||
772 | atomic_inc(&clnt->cl_count); | 866 | atomic_inc(&clnt->cl_count); |
773 | if (clnt->cl_softrtry) | 867 | if (clnt->cl_softrtry) |
774 | task->tk_flags |= RPC_TASK_SOFT; | 868 | task->tk_flags |= RPC_TASK_SOFT; |
869 | if (clnt->cl_noretranstimeo) | ||
870 | task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT; | ||
775 | if (sk_memalloc_socks()) { | 871 | if (sk_memalloc_socks()) { |
776 | struct rpc_xprt *xprt; | 872 | struct rpc_xprt *xprt; |
777 | 873 | ||
@@ -1690,6 +1786,7 @@ call_connect_status(struct rpc_task *task) | |||
1690 | dprint_status(task); | 1786 | dprint_status(task); |
1691 | 1787 | ||
1692 | trace_rpc_connect_status(task, status); | 1788 | trace_rpc_connect_status(task, status); |
1789 | task->tk_status = 0; | ||
1693 | switch (status) { | 1790 | switch (status) { |
1694 | /* if soft mounted, test if we've timed out */ | 1791 | /* if soft mounted, test if we've timed out */ |
1695 | case -ETIMEDOUT: | 1792 | case -ETIMEDOUT: |
@@ -1698,12 +1795,14 @@ call_connect_status(struct rpc_task *task) | |||
1698 | case -ECONNREFUSED: | 1795 | case -ECONNREFUSED: |
1699 | case -ECONNRESET: | 1796 | case -ECONNRESET: |
1700 | case -ENETUNREACH: | 1797 | case -ENETUNREACH: |
1798 | /* retry with existing socket, after a delay */ | ||
1799 | rpc_delay(task, 3*HZ); | ||
1701 | if (RPC_IS_SOFTCONN(task)) | 1800 | if (RPC_IS_SOFTCONN(task)) |
1702 | break; | 1801 | break; |
1703 | /* retry with existing socket, after a delay */ | ||
1704 | case 0: | ||
1705 | case -EAGAIN: | 1802 | case -EAGAIN: |
1706 | task->tk_status = 0; | 1803 | task->tk_action = call_bind; |
1804 | return; | ||
1805 | case 0: | ||
1707 | clnt->cl_stats->netreconn++; | 1806 | clnt->cl_stats->netreconn++; |
1708 | task->tk_action = call_transmit; | 1807 | task->tk_action = call_transmit; |
1709 | return; | 1808 | return; |
@@ -1717,13 +1816,14 @@ call_connect_status(struct rpc_task *task) | |||
1717 | static void | 1816 | static void |
1718 | call_transmit(struct rpc_task *task) | 1817 | call_transmit(struct rpc_task *task) |
1719 | { | 1818 | { |
1819 | int is_retrans = RPC_WAS_SENT(task); | ||
1820 | |||
1720 | dprint_status(task); | 1821 | dprint_status(task); |
1721 | 1822 | ||
1722 | task->tk_action = call_status; | 1823 | task->tk_action = call_status; |
1723 | if (task->tk_status < 0) | 1824 | if (task->tk_status < 0) |
1724 | return; | 1825 | return; |
1725 | task->tk_status = xprt_prepare_transmit(task); | 1826 | if (!xprt_prepare_transmit(task)) |
1726 | if (task->tk_status != 0) | ||
1727 | return; | 1827 | return; |
1728 | task->tk_action = call_transmit_status; | 1828 | task->tk_action = call_transmit_status; |
1729 | /* Encode here so that rpcsec_gss can use correct sequence number. */ | 1829 | /* Encode here so that rpcsec_gss can use correct sequence number. */ |
@@ -1742,6 +1842,8 @@ call_transmit(struct rpc_task *task) | |||
1742 | xprt_transmit(task); | 1842 | xprt_transmit(task); |
1743 | if (task->tk_status < 0) | 1843 | if (task->tk_status < 0) |
1744 | return; | 1844 | return; |
1845 | if (is_retrans) | ||
1846 | task->tk_client->cl_stats->rpcretrans++; | ||
1745 | /* | 1847 | /* |
1746 | * On success, ensure that we call xprt_end_transmit() before sleeping | 1848 | * On success, ensure that we call xprt_end_transmit() before sleeping |
1747 | * in order to allow access to the socket to other RPC requests. | 1849 | * in order to allow access to the socket to other RPC requests. |
@@ -1811,8 +1913,7 @@ call_bc_transmit(struct rpc_task *task) | |||
1811 | { | 1913 | { |
1812 | struct rpc_rqst *req = task->tk_rqstp; | 1914 | struct rpc_rqst *req = task->tk_rqstp; |
1813 | 1915 | ||
1814 | task->tk_status = xprt_prepare_transmit(task); | 1916 | if (!xprt_prepare_transmit(task)) { |
1815 | if (task->tk_status == -EAGAIN) { | ||
1816 | /* | 1917 | /* |
1817 | * Could not reserve the transport. Try again after the | 1918 | * Could not reserve the transport. Try again after the |
1818 | * transport is released. | 1919 | * transport is released. |
@@ -1900,7 +2001,8 @@ call_status(struct rpc_task *task) | |||
1900 | rpc_delay(task, 3*HZ); | 2001 | rpc_delay(task, 3*HZ); |
1901 | case -ETIMEDOUT: | 2002 | case -ETIMEDOUT: |
1902 | task->tk_action = call_timeout; | 2003 | task->tk_action = call_timeout; |
1903 | if (task->tk_client->cl_discrtry) | 2004 | if (!(task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) |
2005 | && task->tk_client->cl_discrtry) | ||
1904 | xprt_conditional_disconnect(req->rq_xprt, | 2006 | xprt_conditional_disconnect(req->rq_xprt, |
1905 | req->rq_connect_cookie); | 2007 | req->rq_connect_cookie); |
1906 | break; | 2008 | break; |
@@ -1982,7 +2084,6 @@ call_timeout(struct rpc_task *task) | |||
1982 | rpcauth_invalcred(task); | 2084 | rpcauth_invalcred(task); |
1983 | 2085 | ||
1984 | retry: | 2086 | retry: |
1985 | clnt->cl_stats->rpcretrans++; | ||
1986 | task->tk_action = call_bind; | 2087 | task->tk_action = call_bind; |
1987 | task->tk_status = 0; | 2088 | task->tk_status = 0; |
1988 | } | 2089 | } |
@@ -2025,7 +2126,6 @@ call_decode(struct rpc_task *task) | |||
2025 | if (req->rq_rcv_buf.len < 12) { | 2126 | if (req->rq_rcv_buf.len < 12) { |
2026 | if (!RPC_IS_SOFT(task)) { | 2127 | if (!RPC_IS_SOFT(task)) { |
2027 | task->tk_action = call_bind; | 2128 | task->tk_action = call_bind; |
2028 | clnt->cl_stats->rpcretrans++; | ||
2029 | goto out_retry; | 2129 | goto out_retry; |
2030 | } | 2130 | } |
2031 | dprintk("RPC: %s: too small RPC reply size (%d bytes)\n", | 2131 | dprintk("RPC: %s: too small RPC reply size (%d bytes)\n", |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 095363eee764..04199bc8416f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -205,10 +205,8 @@ int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) | |||
205 | goto out_sleep; | 205 | goto out_sleep; |
206 | } | 206 | } |
207 | xprt->snd_task = task; | 207 | xprt->snd_task = task; |
208 | if (req != NULL) { | 208 | if (req != NULL) |
209 | req->rq_bytes_sent = 0; | ||
210 | req->rq_ntrans++; | 209 | req->rq_ntrans++; |
211 | } | ||
212 | 210 | ||
213 | return 1; | 211 | return 1; |
214 | 212 | ||
@@ -263,7 +261,6 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) | |||
263 | } | 261 | } |
264 | if (__xprt_get_cong(xprt, task)) { | 262 | if (__xprt_get_cong(xprt, task)) { |
265 | xprt->snd_task = task; | 263 | xprt->snd_task = task; |
266 | req->rq_bytes_sent = 0; | ||
267 | req->rq_ntrans++; | 264 | req->rq_ntrans++; |
268 | return 1; | 265 | return 1; |
269 | } | 266 | } |
@@ -300,10 +297,8 @@ static bool __xprt_lock_write_func(struct rpc_task *task, void *data) | |||
300 | 297 | ||
301 | req = task->tk_rqstp; | 298 | req = task->tk_rqstp; |
302 | xprt->snd_task = task; | 299 | xprt->snd_task = task; |
303 | if (req) { | 300 | if (req) |
304 | req->rq_bytes_sent = 0; | ||
305 | req->rq_ntrans++; | 301 | req->rq_ntrans++; |
306 | } | ||
307 | return true; | 302 | return true; |
308 | } | 303 | } |
309 | 304 | ||
@@ -329,7 +324,6 @@ static bool __xprt_lock_write_cong_func(struct rpc_task *task, void *data) | |||
329 | } | 324 | } |
330 | if (__xprt_get_cong(xprt, task)) { | 325 | if (__xprt_get_cong(xprt, task)) { |
331 | xprt->snd_task = task; | 326 | xprt->snd_task = task; |
332 | req->rq_bytes_sent = 0; | ||
333 | req->rq_ntrans++; | 327 | req->rq_ntrans++; |
334 | return true; | 328 | return true; |
335 | } | 329 | } |
@@ -358,6 +352,11 @@ out_unlock: | |||
358 | void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) | 352 | void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) |
359 | { | 353 | { |
360 | if (xprt->snd_task == task) { | 354 | if (xprt->snd_task == task) { |
355 | if (task != NULL) { | ||
356 | struct rpc_rqst *req = task->tk_rqstp; | ||
357 | if (req != NULL) | ||
358 | req->rq_bytes_sent = 0; | ||
359 | } | ||
361 | xprt_clear_locked(xprt); | 360 | xprt_clear_locked(xprt); |
362 | __xprt_lock_write_next(xprt); | 361 | __xprt_lock_write_next(xprt); |
363 | } | 362 | } |
@@ -375,6 +374,11 @@ EXPORT_SYMBOL_GPL(xprt_release_xprt); | |||
375 | void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) | 374 | void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) |
376 | { | 375 | { |
377 | if (xprt->snd_task == task) { | 376 | if (xprt->snd_task == task) { |
377 | if (task != NULL) { | ||
378 | struct rpc_rqst *req = task->tk_rqstp; | ||
379 | if (req != NULL) | ||
380 | req->rq_bytes_sent = 0; | ||
381 | } | ||
378 | xprt_clear_locked(xprt); | 382 | xprt_clear_locked(xprt); |
379 | __xprt_lock_write_next_cong(xprt); | 383 | __xprt_lock_write_next_cong(xprt); |
380 | } | 384 | } |
@@ -854,24 +858,36 @@ static inline int xprt_has_timer(struct rpc_xprt *xprt) | |||
854 | * @task: RPC task about to send a request | 858 | * @task: RPC task about to send a request |
855 | * | 859 | * |
856 | */ | 860 | */ |
857 | int xprt_prepare_transmit(struct rpc_task *task) | 861 | bool xprt_prepare_transmit(struct rpc_task *task) |
858 | { | 862 | { |
859 | struct rpc_rqst *req = task->tk_rqstp; | 863 | struct rpc_rqst *req = task->tk_rqstp; |
860 | struct rpc_xprt *xprt = req->rq_xprt; | 864 | struct rpc_xprt *xprt = req->rq_xprt; |
861 | int err = 0; | 865 | bool ret = false; |
862 | 866 | ||
863 | dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); | 867 | dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); |
864 | 868 | ||
865 | spin_lock_bh(&xprt->transport_lock); | 869 | spin_lock_bh(&xprt->transport_lock); |
866 | if (req->rq_reply_bytes_recvd && !req->rq_bytes_sent) { | 870 | if (!req->rq_bytes_sent) { |
867 | err = req->rq_reply_bytes_recvd; | 871 | if (req->rq_reply_bytes_recvd) { |
872 | task->tk_status = req->rq_reply_bytes_recvd; | ||
873 | goto out_unlock; | ||
874 | } | ||
875 | if ((task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) | ||
876 | && xprt_connected(xprt) | ||
877 | && req->rq_connect_cookie == xprt->connect_cookie) { | ||
878 | xprt->ops->set_retrans_timeout(task); | ||
879 | rpc_sleep_on(&xprt->pending, task, xprt_timer); | ||
880 | goto out_unlock; | ||
881 | } | ||
882 | } | ||
883 | if (!xprt->ops->reserve_xprt(xprt, task)) { | ||
884 | task->tk_status = -EAGAIN; | ||
868 | goto out_unlock; | 885 | goto out_unlock; |
869 | } | 886 | } |
870 | if (!xprt->ops->reserve_xprt(xprt, task)) | 887 | ret = true; |
871 | err = -EAGAIN; | ||
872 | out_unlock: | 888 | out_unlock: |
873 | spin_unlock_bh(&xprt->transport_lock); | 889 | spin_unlock_bh(&xprt->transport_lock); |
874 | return err; | 890 | return ret; |
875 | } | 891 | } |
876 | 892 | ||
877 | void xprt_end_transmit(struct rpc_task *task) | 893 | void xprt_end_transmit(struct rpc_task *task) |
@@ -912,7 +928,6 @@ void xprt_transmit(struct rpc_task *task) | |||
912 | } else if (!req->rq_bytes_sent) | 928 | } else if (!req->rq_bytes_sent) |
913 | return; | 929 | return; |
914 | 930 | ||
915 | req->rq_connect_cookie = xprt->connect_cookie; | ||
916 | req->rq_xtime = ktime_get(); | 931 | req->rq_xtime = ktime_get(); |
917 | status = xprt->ops->send_request(task); | 932 | status = xprt->ops->send_request(task); |
918 | if (status != 0) { | 933 | if (status != 0) { |
@@ -938,12 +953,14 @@ void xprt_transmit(struct rpc_task *task) | |||
938 | /* Don't race with disconnect */ | 953 | /* Don't race with disconnect */ |
939 | if (!xprt_connected(xprt)) | 954 | if (!xprt_connected(xprt)) |
940 | task->tk_status = -ENOTCONN; | 955 | task->tk_status = -ENOTCONN; |
941 | else if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task)) { | 956 | else { |
942 | /* | 957 | /* |
943 | * Sleep on the pending queue since | 958 | * Sleep on the pending queue since |
944 | * we're expecting a reply. | 959 | * we're expecting a reply. |
945 | */ | 960 | */ |
946 | rpc_sleep_on(&xprt->pending, task, xprt_timer); | 961 | if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task)) |
962 | rpc_sleep_on(&xprt->pending, task, xprt_timer); | ||
963 | req->rq_connect_cookie = xprt->connect_cookie; | ||
947 | } | 964 | } |
948 | spin_unlock_bh(&xprt->transport_lock); | 965 | spin_unlock_bh(&xprt->transport_lock); |
949 | } | 966 | } |
@@ -1087,11 +1104,9 @@ struct rpc_xprt *xprt_alloc(struct net *net, size_t size, | |||
1087 | for (i = 0; i < num_prealloc; i++) { | 1104 | for (i = 0; i < num_prealloc; i++) { |
1088 | req = kzalloc(sizeof(struct rpc_rqst), GFP_KERNEL); | 1105 | req = kzalloc(sizeof(struct rpc_rqst), GFP_KERNEL); |
1089 | if (!req) | 1106 | if (!req) |
1090 | break; | 1107 | goto out_free; |
1091 | list_add(&req->rq_list, &xprt->free); | 1108 | list_add(&req->rq_list, &xprt->free); |
1092 | } | 1109 | } |
1093 | if (i < num_prealloc) | ||
1094 | goto out_free; | ||
1095 | if (max_alloc > num_prealloc) | 1110 | if (max_alloc > num_prealloc) |
1096 | xprt->max_reqs = max_alloc; | 1111 | xprt->max_reqs = max_alloc; |
1097 | else | 1112 | else |
@@ -1186,6 +1201,12 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) | |||
1186 | req->rq_xprt = xprt; | 1201 | req->rq_xprt = xprt; |
1187 | req->rq_buffer = NULL; | 1202 | req->rq_buffer = NULL; |
1188 | req->rq_xid = xprt_alloc_xid(xprt); | 1203 | req->rq_xid = xprt_alloc_xid(xprt); |
1204 | req->rq_connect_cookie = xprt->connect_cookie - 1; | ||
1205 | req->rq_bytes_sent = 0; | ||
1206 | req->rq_snd_buf.len = 0; | ||
1207 | req->rq_snd_buf.buflen = 0; | ||
1208 | req->rq_rcv_buf.len = 0; | ||
1209 | req->rq_rcv_buf.buflen = 0; | ||
1189 | req->rq_release_snd_buf = NULL; | 1210 | req->rq_release_snd_buf = NULL; |
1190 | xprt_reset_majortimeo(req); | 1211 | xprt_reset_majortimeo(req); |
1191 | dprintk("RPC: %5u reserved req %p xid %08x\n", task->tk_pid, | 1212 | dprintk("RPC: %5u reserved req %p xid %08x\n", task->tk_pid, |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index ee03d35677d9..17c88928b7db 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -835,6 +835,8 @@ static void xs_close(struct rpc_xprt *xprt) | |||
835 | 835 | ||
836 | dprintk("RPC: xs_close xprt %p\n", xprt); | 836 | dprintk("RPC: xs_close xprt %p\n", xprt); |
837 | 837 | ||
838 | cancel_delayed_work_sync(&transport->connect_worker); | ||
839 | |||
838 | xs_reset_transport(transport); | 840 | xs_reset_transport(transport); |
839 | xprt->reestablish_timeout = 0; | 841 | xprt->reestablish_timeout = 0; |
840 | 842 | ||
@@ -854,14 +856,6 @@ static void xs_tcp_close(struct rpc_xprt *xprt) | |||
854 | xs_tcp_shutdown(xprt); | 856 | xs_tcp_shutdown(xprt); |
855 | } | 857 | } |
856 | 858 | ||
857 | static void xs_local_destroy(struct rpc_xprt *xprt) | ||
858 | { | ||
859 | xs_close(xprt); | ||
860 | xs_free_peer_addresses(xprt); | ||
861 | xprt_free(xprt); | ||
862 | module_put(THIS_MODULE); | ||
863 | } | ||
864 | |||
865 | /** | 859 | /** |
866 | * xs_destroy - prepare to shutdown a transport | 860 | * xs_destroy - prepare to shutdown a transport |
867 | * @xprt: doomed transport | 861 | * @xprt: doomed transport |
@@ -869,13 +863,12 @@ static void xs_local_destroy(struct rpc_xprt *xprt) | |||
869 | */ | 863 | */ |
870 | static void xs_destroy(struct rpc_xprt *xprt) | 864 | static void xs_destroy(struct rpc_xprt *xprt) |
871 | { | 865 | { |
872 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | ||
873 | |||
874 | dprintk("RPC: xs_destroy xprt %p\n", xprt); | 866 | dprintk("RPC: xs_destroy xprt %p\n", xprt); |
875 | 867 | ||
876 | cancel_delayed_work_sync(&transport->connect_worker); | 868 | xs_close(xprt); |
877 | 869 | xs_free_peer_addresses(xprt); | |
878 | xs_local_destroy(xprt); | 870 | xprt_free(xprt); |
871 | module_put(THIS_MODULE); | ||
879 | } | 872 | } |
880 | 873 | ||
881 | static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) | 874 | static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) |
@@ -1511,6 +1504,7 @@ static void xs_tcp_state_change(struct sock *sk) | |||
1511 | transport->tcp_copied = 0; | 1504 | transport->tcp_copied = 0; |
1512 | transport->tcp_flags = | 1505 | transport->tcp_flags = |
1513 | TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; | 1506 | TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; |
1507 | xprt->connect_cookie++; | ||
1514 | 1508 | ||
1515 | xprt_wake_pending_tasks(xprt, -EAGAIN); | 1509 | xprt_wake_pending_tasks(xprt, -EAGAIN); |
1516 | } | 1510 | } |
@@ -1816,6 +1810,10 @@ static inline void xs_reclassify_socket(int family, struct socket *sock) | |||
1816 | } | 1810 | } |
1817 | #endif | 1811 | #endif |
1818 | 1812 | ||
1813 | static void xs_dummy_setup_socket(struct work_struct *work) | ||
1814 | { | ||
1815 | } | ||
1816 | |||
1819 | static struct socket *xs_create_sock(struct rpc_xprt *xprt, | 1817 | static struct socket *xs_create_sock(struct rpc_xprt *xprt, |
1820 | struct sock_xprt *transport, int family, int type, int protocol) | 1818 | struct sock_xprt *transport, int family, int type, int protocol) |
1821 | { | 1819 | { |
@@ -2112,6 +2110,19 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) | |||
2112 | 2110 | ||
2113 | if (!transport->inet) { | 2111 | if (!transport->inet) { |
2114 | struct sock *sk = sock->sk; | 2112 | struct sock *sk = sock->sk; |
2113 | unsigned int keepidle = xprt->timeout->to_initval / HZ; | ||
2114 | unsigned int keepcnt = xprt->timeout->to_retries + 1; | ||
2115 | unsigned int opt_on = 1; | ||
2116 | |||
2117 | /* TCP Keepalive options */ | ||
2118 | kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, | ||
2119 | (char *)&opt_on, sizeof(opt_on)); | ||
2120 | kernel_setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, | ||
2121 | (char *)&keepidle, sizeof(keepidle)); | ||
2122 | kernel_setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, | ||
2123 | (char *)&keepidle, sizeof(keepidle)); | ||
2124 | kernel_setsockopt(sock, SOL_TCP, TCP_KEEPCNT, | ||
2125 | (char *)&keepcnt, sizeof(keepcnt)); | ||
2115 | 2126 | ||
2116 | write_lock_bh(&sk->sk_callback_lock); | 2127 | write_lock_bh(&sk->sk_callback_lock); |
2117 | 2128 | ||
@@ -2151,7 +2162,6 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) | |||
2151 | case 0: | 2162 | case 0: |
2152 | case -EINPROGRESS: | 2163 | case -EINPROGRESS: |
2153 | /* SYN_SENT! */ | 2164 | /* SYN_SENT! */ |
2154 | xprt->connect_cookie++; | ||
2155 | if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO) | 2165 | if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO) |
2156 | xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; | 2166 | xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; |
2157 | } | 2167 | } |
@@ -2498,7 +2508,7 @@ static struct rpc_xprt_ops xs_local_ops = { | |||
2498 | .send_request = xs_local_send_request, | 2508 | .send_request = xs_local_send_request, |
2499 | .set_retrans_timeout = xprt_set_retrans_timeout_def, | 2509 | .set_retrans_timeout = xprt_set_retrans_timeout_def, |
2500 | .close = xs_close, | 2510 | .close = xs_close, |
2501 | .destroy = xs_local_destroy, | 2511 | .destroy = xs_destroy, |
2502 | .print_stats = xs_local_print_stats, | 2512 | .print_stats = xs_local_print_stats, |
2503 | }; | 2513 | }; |
2504 | 2514 | ||
@@ -2655,6 +2665,9 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args) | |||
2655 | xprt->ops = &xs_local_ops; | 2665 | xprt->ops = &xs_local_ops; |
2656 | xprt->timeout = &xs_local_default_timeout; | 2666 | xprt->timeout = &xs_local_default_timeout; |
2657 | 2667 | ||
2668 | INIT_DELAYED_WORK(&transport->connect_worker, | ||
2669 | xs_dummy_setup_socket); | ||
2670 | |||
2658 | switch (sun->sun_family) { | 2671 | switch (sun->sun_family) { |
2659 | case AF_LOCAL: | 2672 | case AF_LOCAL: |
2660 | if (sun->sun_path[0] != '/') { | 2673 | if (sun->sun_path[0] != '/') { |
@@ -2859,8 +2872,8 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) | |||
2859 | if (args->bc_xprt->xpt_bc_xprt) { | 2872 | if (args->bc_xprt->xpt_bc_xprt) { |
2860 | /* | 2873 | /* |
2861 | * This server connection already has a backchannel | 2874 | * This server connection already has a backchannel |
2862 | * export; we can't create a new one, as we wouldn't be | 2875 | * transport; we can't create a new one, as we wouldn't |
2863 | * able to match replies based on xid any more. So, | 2876 | * be able to match replies based on xid any more. So, |
2864 | * reuse the already-existing one: | 2877 | * reuse the already-existing one: |
2865 | */ | 2878 | */ |
2866 | return args->bc_xprt->xpt_bc_xprt; | 2879 | return args->bc_xprt->xpt_bc_xprt; |