diff options
Diffstat (limited to 'net/sunrpc/clnt.c')
-rw-r--r-- | net/sunrpc/clnt.c | 147 |
1 files changed, 102 insertions, 45 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f17e6153b688..702ede309b06 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/net/sunrpc/rpcclnt.c | 2 | * linux/net/sunrpc/clnt.c |
3 | * | 3 | * |
4 | * This file contains the high-level RPC interface. | 4 | * This file contains the high-level RPC interface. |
5 | * It is modeled as a finite state machine to support both synchronous | 5 | * It is modeled as a finite state machine to support both synchronous |
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
28 | #include <linux/mm.h> | 28 | #include <linux/mm.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/in.h> | ||
31 | #include <linux/utsname.h> | 30 | #include <linux/utsname.h> |
32 | 31 | ||
33 | #include <linux/sunrpc/clnt.h> | 32 | #include <linux/sunrpc/clnt.h> |
@@ -53,6 +52,7 @@ static void call_allocate(struct rpc_task *task); | |||
53 | static void call_encode(struct rpc_task *task); | 52 | static void call_encode(struct rpc_task *task); |
54 | static void call_decode(struct rpc_task *task); | 53 | static void call_decode(struct rpc_task *task); |
55 | static void call_bind(struct rpc_task *task); | 54 | static void call_bind(struct rpc_task *task); |
55 | static void call_bind_status(struct rpc_task *task); | ||
56 | static void call_transmit(struct rpc_task *task); | 56 | static void call_transmit(struct rpc_task *task); |
57 | static void call_status(struct rpc_task *task); | 57 | static void call_status(struct rpc_task *task); |
58 | static void call_refresh(struct rpc_task *task); | 58 | static void call_refresh(struct rpc_task *task); |
@@ -517,15 +517,8 @@ void | |||
517 | rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) | 517 | rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) |
518 | { | 518 | { |
519 | struct rpc_xprt *xprt = clnt->cl_xprt; | 519 | struct rpc_xprt *xprt = clnt->cl_xprt; |
520 | 520 | if (xprt->ops->set_buffer_size) | |
521 | xprt->sndsize = 0; | 521 | xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); |
522 | if (sndsize) | ||
523 | xprt->sndsize = sndsize + RPC_SLACK_SPACE; | ||
524 | xprt->rcvsize = 0; | ||
525 | if (rcvsize) | ||
526 | xprt->rcvsize = rcvsize + RPC_SLACK_SPACE; | ||
527 | if (xprt_connected(xprt)) | ||
528 | xprt_sock_setbufsize(xprt); | ||
529 | } | 522 | } |
530 | 523 | ||
531 | /* | 524 | /* |
@@ -685,13 +678,11 @@ call_allocate(struct rpc_task *task) | |||
685 | static void | 678 | static void |
686 | call_encode(struct rpc_task *task) | 679 | call_encode(struct rpc_task *task) |
687 | { | 680 | { |
688 | struct rpc_clnt *clnt = task->tk_client; | ||
689 | struct rpc_rqst *req = task->tk_rqstp; | 681 | struct rpc_rqst *req = task->tk_rqstp; |
690 | struct xdr_buf *sndbuf = &req->rq_snd_buf; | 682 | struct xdr_buf *sndbuf = &req->rq_snd_buf; |
691 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 683 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
692 | unsigned int bufsiz; | 684 | unsigned int bufsiz; |
693 | kxdrproc_t encode; | 685 | kxdrproc_t encode; |
694 | int status; | ||
695 | u32 *p; | 686 | u32 *p; |
696 | 687 | ||
697 | dprintk("RPC: %4d call_encode (status %d)\n", | 688 | dprintk("RPC: %4d call_encode (status %d)\n", |
@@ -719,11 +710,15 @@ call_encode(struct rpc_task *task) | |||
719 | rpc_exit(task, -EIO); | 710 | rpc_exit(task, -EIO); |
720 | return; | 711 | return; |
721 | } | 712 | } |
722 | if (encode && (status = rpcauth_wrap_req(task, encode, req, p, | 713 | if (encode == NULL) |
723 | task->tk_msg.rpc_argp)) < 0) { | 714 | return; |
724 | printk(KERN_WARNING "%s: can't encode arguments: %d\n", | 715 | |
725 | clnt->cl_protname, -status); | 716 | task->tk_status = rpcauth_wrap_req(task, encode, req, p, |
726 | rpc_exit(task, status); | 717 | task->tk_msg.rpc_argp); |
718 | if (task->tk_status == -ENOMEM) { | ||
719 | /* XXX: Is this sane? */ | ||
720 | rpc_delay(task, 3*HZ); | ||
721 | task->tk_status = -EAGAIN; | ||
727 | } | 722 | } |
728 | } | 723 | } |
729 | 724 | ||
@@ -734,43 +729,95 @@ static void | |||
734 | call_bind(struct rpc_task *task) | 729 | call_bind(struct rpc_task *task) |
735 | { | 730 | { |
736 | struct rpc_clnt *clnt = task->tk_client; | 731 | 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 | 732 | ||
742 | task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_connect; | 733 | dprintk("RPC: %4d call_bind (status %d)\n", |
734 | task->tk_pid, task->tk_status); | ||
743 | 735 | ||
736 | task->tk_action = call_connect; | ||
744 | if (!clnt->cl_port) { | 737 | if (!clnt->cl_port) { |
745 | task->tk_action = call_connect; | 738 | task->tk_action = call_bind_status; |
746 | task->tk_timeout = RPC_CONNECT_TIMEOUT; | 739 | task->tk_timeout = task->tk_xprt->bind_timeout; |
747 | rpc_getport(task, clnt); | 740 | rpc_getport(task, clnt); |
748 | } | 741 | } |
749 | } | 742 | } |
750 | 743 | ||
751 | /* | 744 | /* |
752 | * 4a. Connect to the RPC server (TCP case) | 745 | * 4a. Sort out bind result |
746 | */ | ||
747 | static void | ||
748 | call_bind_status(struct rpc_task *task) | ||
749 | { | ||
750 | int status = -EACCES; | ||
751 | |||
752 | if (task->tk_status >= 0) { | ||
753 | dprintk("RPC: %4d call_bind_status (status %d)\n", | ||
754 | task->tk_pid, task->tk_status); | ||
755 | task->tk_status = 0; | ||
756 | task->tk_action = call_connect; | ||
757 | return; | ||
758 | } | ||
759 | |||
760 | switch (task->tk_status) { | ||
761 | case -EACCES: | ||
762 | dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n", | ||
763 | task->tk_pid); | ||
764 | rpc_delay(task, 3*HZ); | ||
765 | goto retry_bind; | ||
766 | case -ETIMEDOUT: | ||
767 | dprintk("RPC: %4d rpcbind request timed out\n", | ||
768 | task->tk_pid); | ||
769 | if (RPC_IS_SOFT(task)) { | ||
770 | status = -EIO; | ||
771 | break; | ||
772 | } | ||
773 | goto retry_bind; | ||
774 | case -EPFNOSUPPORT: | ||
775 | dprintk("RPC: %4d remote rpcbind service unavailable\n", | ||
776 | task->tk_pid); | ||
777 | break; | ||
778 | case -EPROTONOSUPPORT: | ||
779 | dprintk("RPC: %4d remote rpcbind version 2 unavailable\n", | ||
780 | task->tk_pid); | ||
781 | break; | ||
782 | default: | ||
783 | dprintk("RPC: %4d unrecognized rpcbind error (%d)\n", | ||
784 | task->tk_pid, -task->tk_status); | ||
785 | status = -EIO; | ||
786 | break; | ||
787 | } | ||
788 | |||
789 | rpc_exit(task, status); | ||
790 | return; | ||
791 | |||
792 | retry_bind: | ||
793 | task->tk_status = 0; | ||
794 | task->tk_action = call_bind; | ||
795 | return; | ||
796 | } | ||
797 | |||
798 | /* | ||
799 | * 4b. Connect to the RPC server | ||
753 | */ | 800 | */ |
754 | static void | 801 | static void |
755 | call_connect(struct rpc_task *task) | 802 | call_connect(struct rpc_task *task) |
756 | { | 803 | { |
757 | struct rpc_clnt *clnt = task->tk_client; | 804 | struct rpc_xprt *xprt = task->tk_xprt; |
758 | 805 | ||
759 | dprintk("RPC: %4d call_connect status %d\n", | 806 | dprintk("RPC: %4d call_connect xprt %p %s connected\n", |
760 | task->tk_pid, task->tk_status); | 807 | task->tk_pid, xprt, |
808 | (xprt_connected(xprt) ? "is" : "is not")); | ||
761 | 809 | ||
762 | if (xprt_connected(clnt->cl_xprt)) { | 810 | task->tk_action = call_transmit; |
763 | task->tk_action = call_transmit; | 811 | if (!xprt_connected(xprt)) { |
764 | return; | 812 | task->tk_action = call_connect_status; |
813 | if (task->tk_status < 0) | ||
814 | return; | ||
815 | xprt_connect(task); | ||
765 | } | 816 | } |
766 | task->tk_action = call_connect_status; | ||
767 | if (task->tk_status < 0) | ||
768 | return; | ||
769 | xprt_connect(task); | ||
770 | } | 817 | } |
771 | 818 | ||
772 | /* | 819 | /* |
773 | * 4b. Sort out connect result | 820 | * 4c. Sort out connect result |
774 | */ | 821 | */ |
775 | static void | 822 | static void |
776 | call_connect_status(struct rpc_task *task) | 823 | call_connect_status(struct rpc_task *task) |
@@ -778,6 +825,9 @@ call_connect_status(struct rpc_task *task) | |||
778 | struct rpc_clnt *clnt = task->tk_client; | 825 | struct rpc_clnt *clnt = task->tk_client; |
779 | int status = task->tk_status; | 826 | int status = task->tk_status; |
780 | 827 | ||
828 | dprintk("RPC: %5u call_connect_status (status %d)\n", | ||
829 | task->tk_pid, task->tk_status); | ||
830 | |||
781 | task->tk_status = 0; | 831 | task->tk_status = 0; |
782 | if (status >= 0) { | 832 | if (status >= 0) { |
783 | clnt->cl_stats->netreconn++; | 833 | clnt->cl_stats->netreconn++; |
@@ -785,17 +835,19 @@ call_connect_status(struct rpc_task *task) | |||
785 | return; | 835 | return; |
786 | } | 836 | } |
787 | 837 | ||
788 | /* Something failed: we may have to rebind */ | 838 | /* Something failed: remote service port may have changed */ |
789 | if (clnt->cl_autobind) | 839 | if (clnt->cl_autobind) |
790 | clnt->cl_port = 0; | 840 | clnt->cl_port = 0; |
841 | |||
791 | switch (status) { | 842 | switch (status) { |
792 | case -ENOTCONN: | 843 | case -ENOTCONN: |
793 | case -ETIMEDOUT: | 844 | case -ETIMEDOUT: |
794 | case -EAGAIN: | 845 | case -EAGAIN: |
795 | task->tk_action = (clnt->cl_port == 0) ? call_bind : call_connect; | 846 | task->tk_action = call_bind; |
796 | break; | 847 | break; |
797 | default: | 848 | default: |
798 | rpc_exit(task, -EIO); | 849 | rpc_exit(task, -EIO); |
850 | break; | ||
799 | } | 851 | } |
800 | } | 852 | } |
801 | 853 | ||
@@ -815,10 +867,12 @@ call_transmit(struct rpc_task *task) | |||
815 | if (task->tk_status != 0) | 867 | if (task->tk_status != 0) |
816 | return; | 868 | return; |
817 | /* Encode here so that rpcsec_gss can use correct sequence number. */ | 869 | /* Encode here so that rpcsec_gss can use correct sequence number. */ |
818 | if (!task->tk_rqstp->rq_bytes_sent) | 870 | if (task->tk_rqstp->rq_bytes_sent == 0) { |
819 | call_encode(task); | 871 | call_encode(task); |
820 | if (task->tk_status < 0) | 872 | /* Did the encode result in an error condition? */ |
821 | return; | 873 | if (task->tk_status != 0) |
874 | goto out_nosend; | ||
875 | } | ||
822 | xprt_transmit(task); | 876 | xprt_transmit(task); |
823 | if (task->tk_status < 0) | 877 | if (task->tk_status < 0) |
824 | return; | 878 | return; |
@@ -826,6 +880,10 @@ call_transmit(struct rpc_task *task) | |||
826 | task->tk_action = NULL; | 880 | task->tk_action = NULL; |
827 | rpc_wake_up_task(task); | 881 | rpc_wake_up_task(task); |
828 | } | 882 | } |
883 | return; | ||
884 | out_nosend: | ||
885 | /* release socket write lock before attempting to handle error */ | ||
886 | xprt_abort_transmit(task); | ||
829 | } | 887 | } |
830 | 888 | ||
831 | /* | 889 | /* |
@@ -1020,13 +1078,12 @@ static u32 * | |||
1020 | call_header(struct rpc_task *task) | 1078 | call_header(struct rpc_task *task) |
1021 | { | 1079 | { |
1022 | struct rpc_clnt *clnt = task->tk_client; | 1080 | struct rpc_clnt *clnt = task->tk_client; |
1023 | struct rpc_xprt *xprt = clnt->cl_xprt; | ||
1024 | struct rpc_rqst *req = task->tk_rqstp; | 1081 | struct rpc_rqst *req = task->tk_rqstp; |
1025 | u32 *p = req->rq_svec[0].iov_base; | 1082 | u32 *p = req->rq_svec[0].iov_base; |
1026 | 1083 | ||
1027 | /* FIXME: check buffer size? */ | 1084 | /* FIXME: check buffer size? */ |
1028 | if (xprt->stream) | 1085 | |
1029 | *p++ = 0; /* fill in later */ | 1086 | p = xprt_skip_transport_header(task->tk_xprt, p); |
1030 | *p++ = req->rq_xid; /* XID */ | 1087 | *p++ = req->rq_xid; /* XID */ |
1031 | *p++ = htonl(RPC_CALL); /* CALL */ | 1088 | *p++ = htonl(RPC_CALL); /* CALL */ |
1032 | *p++ = htonl(RPC_VERSION); /* RPC version */ | 1089 | *p++ = htonl(RPC_VERSION); /* RPC version */ |