diff options
author | Chuck Lever <cel@citi.umich.edu> | 2005-08-11 16:25:11 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-09-23 12:38:04 -0400 |
commit | da35187801732397a7e05fb9e77f3700cc35f5db (patch) | |
tree | 61307975e36112fd85b98d0df824386e209a5049 /net/sunrpc/clnt.c | |
parent | 23475d66bd8600e0c5353f86c1b74f68df27bdb5 (diff) |
[PATCH] RPC: proper soft timeout behavior for rpcbind
Implement a best practice: for soft mounts, an rpcbind timeout should
cause an RPC request to fail.
This also provides an FSM hook for retrying an rpcbind with a different
rpcbind protocol version. We'll use this later to try multiple rpcbind
protocol versions when binding. To enable this, expose the RPC error
code returned during a portmap request to the FSM so it can make some
decision about how to report, retry, or fail the request.
Test-plan:
Hundreds of passes with connectathon NFSv3 locking suite, on the client
and server.
Version: Thu, 11 Aug 2005 16:01:53 -0400
Signed-off-by: Chuck Lever <cel@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/clnt.c')
-rw-r--r-- | net/sunrpc/clnt.c | 97 |
1 files changed, 77 insertions, 20 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f17e6153b688..2d3cf0a52d82 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -53,6 +53,7 @@ static void call_allocate(struct rpc_task *task); | |||
53 | static void call_encode(struct rpc_task *task); | 53 | static void call_encode(struct rpc_task *task); |
54 | static void call_decode(struct rpc_task *task); | 54 | static void call_decode(struct rpc_task *task); |
55 | static void call_bind(struct rpc_task *task); | 55 | static void call_bind(struct rpc_task *task); |
56 | static void call_bind_status(struct rpc_task *task); | ||
56 | static void call_transmit(struct rpc_task *task); | 57 | static void call_transmit(struct rpc_task *task); |
57 | static void call_status(struct rpc_task *task); | 58 | static void call_status(struct rpc_task *task); |
58 | static void call_refresh(struct rpc_task *task); | 59 | static void call_refresh(struct rpc_task *task); |
@@ -734,43 +735,94 @@ static void | |||
734 | call_bind(struct rpc_task *task) | 735 | call_bind(struct rpc_task *task) |
735 | { | 736 | { |
736 | struct rpc_clnt *clnt = task->tk_client; | 737 | struct rpc_clnt *clnt = task->tk_client; |
737 | struct rpc_xprt *xprt = clnt->cl_xprt; | ||
738 | |||
739 | dprintk("RPC: %4d call_bind xprt %p %s connected\n", task->tk_pid, | ||
740 | xprt, (xprt_connected(xprt) ? "is" : "is not")); | ||
741 | 738 | ||
742 | task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_connect; | 739 | dprintk("RPC: %4d call_bind (status %d)\n", |
740 | task->tk_pid, task->tk_status); | ||
743 | 741 | ||
742 | task->tk_action = call_connect; | ||
744 | if (!clnt->cl_port) { | 743 | if (!clnt->cl_port) { |
745 | task->tk_action = call_connect; | 744 | task->tk_action = call_bind_status; |
746 | task->tk_timeout = RPC_CONNECT_TIMEOUT; | 745 | task->tk_timeout = RPC_CONNECT_TIMEOUT; |
747 | rpc_getport(task, clnt); | 746 | rpc_getport(task, clnt); |
748 | } | 747 | } |
749 | } | 748 | } |
750 | 749 | ||
751 | /* | 750 | /* |
752 | * 4a. Connect to the RPC server (TCP case) | 751 | * 4a. Sort out bind result |
752 | */ | ||
753 | static void | ||
754 | call_bind_status(struct rpc_task *task) | ||
755 | { | ||
756 | int status = -EACCES; | ||
757 | |||
758 | if (task->tk_status >= 0) { | ||
759 | dprintk("RPC: %4d call_bind_status (status %d)\n", | ||
760 | task->tk_pid, task->tk_status); | ||
761 | task->tk_status = 0; | ||
762 | task->tk_action = call_connect; | ||
763 | return; | ||
764 | } | ||
765 | |||
766 | switch (task->tk_status) { | ||
767 | case -EACCES: | ||
768 | dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n", | ||
769 | task->tk_pid); | ||
770 | break; | ||
771 | case -ETIMEDOUT: | ||
772 | dprintk("RPC: %4d rpcbind request timed out\n", | ||
773 | task->tk_pid); | ||
774 | if (RPC_IS_SOFT(task)) { | ||
775 | status = -EIO; | ||
776 | break; | ||
777 | } | ||
778 | goto retry_bind; | ||
779 | case -EPFNOSUPPORT: | ||
780 | dprintk("RPC: %4d remote rpcbind service unavailable\n", | ||
781 | task->tk_pid); | ||
782 | break; | ||
783 | case -EPROTONOSUPPORT: | ||
784 | dprintk("RPC: %4d remote rpcbind version 2 unavailable\n", | ||
785 | task->tk_pid); | ||
786 | break; | ||
787 | default: | ||
788 | dprintk("RPC: %4d unrecognized rpcbind error (%d)\n", | ||
789 | task->tk_pid, -task->tk_status); | ||
790 | status = -EIO; | ||
791 | break; | ||
792 | } | ||
793 | |||
794 | rpc_exit(task, status); | ||
795 | return; | ||
796 | |||
797 | retry_bind: | ||
798 | task->tk_status = 0; | ||
799 | task->tk_action = call_bind; | ||
800 | return; | ||
801 | } | ||
802 | |||
803 | /* | ||
804 | * 4b. Connect to the RPC server | ||
753 | */ | 805 | */ |
754 | static void | 806 | static void |
755 | call_connect(struct rpc_task *task) | 807 | call_connect(struct rpc_task *task) |
756 | { | 808 | { |
757 | struct rpc_clnt *clnt = task->tk_client; | 809 | struct rpc_xprt *xprt = task->tk_xprt; |
758 | 810 | ||
759 | dprintk("RPC: %4d call_connect status %d\n", | 811 | dprintk("RPC: %4d call_connect xprt %p %s connected\n", |
760 | task->tk_pid, task->tk_status); | 812 | task->tk_pid, xprt, |
813 | (xprt_connected(xprt) ? "is" : "is not")); | ||
761 | 814 | ||
762 | if (xprt_connected(clnt->cl_xprt)) { | 815 | task->tk_action = call_transmit; |
763 | task->tk_action = call_transmit; | 816 | if (!xprt_connected(xprt)) { |
764 | return; | 817 | task->tk_action = call_connect_status; |
818 | if (task->tk_status < 0) | ||
819 | return; | ||
820 | xprt_connect(task); | ||
765 | } | 821 | } |
766 | task->tk_action = call_connect_status; | ||
767 | if (task->tk_status < 0) | ||
768 | return; | ||
769 | xprt_connect(task); | ||
770 | } | 822 | } |
771 | 823 | ||
772 | /* | 824 | /* |
773 | * 4b. Sort out connect result | 825 | * 4c. Sort out connect result |
774 | */ | 826 | */ |
775 | static void | 827 | static void |
776 | call_connect_status(struct rpc_task *task) | 828 | call_connect_status(struct rpc_task *task) |
@@ -778,6 +830,9 @@ call_connect_status(struct rpc_task *task) | |||
778 | struct rpc_clnt *clnt = task->tk_client; | 830 | struct rpc_clnt *clnt = task->tk_client; |
779 | int status = task->tk_status; | 831 | int status = task->tk_status; |
780 | 832 | ||
833 | dprintk("RPC: %5u call_connect_status (status %d)\n", | ||
834 | task->tk_pid, task->tk_status); | ||
835 | |||
781 | task->tk_status = 0; | 836 | task->tk_status = 0; |
782 | if (status >= 0) { | 837 | if (status >= 0) { |
783 | clnt->cl_stats->netreconn++; | 838 | clnt->cl_stats->netreconn++; |
@@ -785,17 +840,19 @@ call_connect_status(struct rpc_task *task) | |||
785 | return; | 840 | return; |
786 | } | 841 | } |
787 | 842 | ||
788 | /* Something failed: we may have to rebind */ | 843 | /* Something failed: remote service port may have changed */ |
789 | if (clnt->cl_autobind) | 844 | if (clnt->cl_autobind) |
790 | clnt->cl_port = 0; | 845 | clnt->cl_port = 0; |
846 | |||
791 | switch (status) { | 847 | switch (status) { |
792 | case -ENOTCONN: | 848 | case -ENOTCONN: |
793 | case -ETIMEDOUT: | 849 | case -ETIMEDOUT: |
794 | case -EAGAIN: | 850 | case -EAGAIN: |
795 | task->tk_action = (clnt->cl_port == 0) ? call_bind : call_connect; | 851 | task->tk_action = call_bind; |
796 | break; | 852 | break; |
797 | default: | 853 | default: |
798 | rpc_exit(task, -EIO); | 854 | rpc_exit(task, -EIO); |
855 | break; | ||
799 | } | 856 | } |
800 | } | 857 | } |
801 | 858 | ||