Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] RPC: separate TCP and UDP transport connection logic

Create separate connection worker functions for managing UDP and TCP
transport sockets. This eliminates several dependencies on "xprt->stream".

Test-plan:
Destructive testing (unplugging the network temporarily). Connectathon with
v2, v3, and v4.

Version: Thu, 11 Aug 2005 16:08:18 -0400

Signed-off-by: Chuck Lever <cel@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

authored by

Chuck Lever and committed by
Trond Myklebust
b0d93ad5 c7b2cae8

+108 -90
+108 -90
net/sunrpc/xprtsock.c
··· 836 836 return err; 837 837 } 838 838 839 - static struct socket *xs_create(struct rpc_xprt *xprt, int proto, int resvport) 840 - { 841 - struct socket *sock; 842 - int type, err; 843 - 844 - dprintk("RPC: xs_create(%s %d)\n", 845 - (proto == IPPROTO_UDP)? "udp" : "tcp", proto); 846 - 847 - type = (proto == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM; 848 - 849 - if ((err = sock_create_kern(PF_INET, type, proto, &sock)) < 0) { 850 - dprintk("RPC: can't create socket (%d).\n", -err); 851 - return NULL; 852 - } 853 - 854 - /* If the caller has the capability, bind to a reserved port */ 855 - if (resvport && xs_bindresvport(xprt, sock) < 0) 856 - goto failed; 857 - 858 - return sock; 859 - 860 - failed: 861 - sock_release(sock); 862 - return NULL; 863 - } 864 - 865 - static void xs_bind(struct rpc_xprt *xprt, struct socket *sock) 866 - { 867 - struct sock *sk = sock->sk; 868 - 869 - if (xprt->inet) 870 - return; 871 - 872 - write_lock_bh(&sk->sk_callback_lock); 873 - sk->sk_user_data = xprt; 874 - xprt->old_data_ready = sk->sk_data_ready; 875 - xprt->old_state_change = sk->sk_state_change; 876 - xprt->old_write_space = sk->sk_write_space; 877 - if (xprt->prot == IPPROTO_UDP) { 878 - sk->sk_data_ready = xs_udp_data_ready; 879 - sk->sk_write_space = xs_udp_write_space; 880 - sk->sk_no_check = UDP_CSUM_NORCV; 881 - xprt_set_connected(xprt); 882 - } else { 883 - tcp_sk(sk)->nonagle = 1; /* disable Nagle's algorithm */ 884 - sk->sk_data_ready = xs_tcp_data_ready; 885 - sk->sk_state_change = xs_tcp_state_change; 886 - sk->sk_write_space = xs_tcp_write_space; 887 - xprt_clear_connected(xprt); 888 - } 889 - 890 - /* Reset to new socket */ 891 - xprt->sock = sock; 892 - xprt->inet = sk; 893 - write_unlock_bh(&sk->sk_callback_lock); 894 - 895 - return; 896 - } 897 - 898 839 /** 899 - * xs_connect_worker - try to connect a socket to a remote endpoint 840 + * xs_udp_connect_worker - set up a UDP socket 900 841 * @args: RPC transport to connect 901 842 * 902 843 * Invoked by a work queue tasklet. 903 844 */ 904 - static void xs_connect_worker(void *args) 845 + static void xs_udp_connect_worker(void *args) 905 846 { 906 - struct rpc_xprt *xprt = (struct rpc_xprt *)args; 847 + struct rpc_xprt *xprt = (struct rpc_xprt *) args; 907 848 struct socket *sock = xprt->sock; 908 - int status = -EIO; 849 + int err, status = -EIO; 909 850 910 851 if (xprt->shutdown || xprt->addr.sin_port == 0) 911 852 goto out; 912 853 913 - dprintk("RPC: xs_connect_worker xprt %p\n", xprt); 854 + dprintk("RPC: xs_udp_connect_worker for xprt %p\n", xprt); 914 855 915 - /* 916 - * Start by resetting any existing state 917 - */ 856 + /* Start by resetting any existing state */ 918 857 xs_close(xprt); 919 - sock = xs_create(xprt, xprt->prot, xprt->resvport); 920 - if (sock == NULL) { 921 - /* couldn't create socket or bind to reserved port; 922 - * this is likely a permanent error, so cause an abort */ 858 + 859 + if ((err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) { 860 + dprintk("RPC: can't create UDP transport socket (%d).\n", -err); 923 861 goto out; 924 862 } 925 - xs_bind(xprt, sock); 926 - xs_set_buffer_size(xprt); 927 863 864 + if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) { 865 + sock_release(sock); 866 + goto out; 867 + } 868 + 869 + if (!xprt->inet) { 870 + struct sock *sk = sock->sk; 871 + 872 + write_lock_bh(&sk->sk_callback_lock); 873 + 874 + sk->sk_user_data = xprt; 875 + xprt->old_data_ready = sk->sk_data_ready; 876 + xprt->old_state_change = sk->sk_state_change; 877 + xprt->old_write_space = sk->sk_write_space; 878 + sk->sk_data_ready = xs_udp_data_ready; 879 + sk->sk_write_space = xs_udp_write_space; 880 + sk->sk_no_check = UDP_CSUM_NORCV; 881 + 882 + xprt_set_connected(xprt); 883 + 884 + /* Reset to new socket */ 885 + xprt->sock = sock; 886 + xprt->inet = sk; 887 + 888 + write_unlock_bh(&sk->sk_callback_lock); 889 + } 890 + xs_set_buffer_size(xprt); 928 891 status = 0; 929 - if (!xprt->stream) 892 + out: 893 + xprt_wake_pending_tasks(xprt, status); 894 + xprt_clear_connecting(xprt); 895 + } 896 + 897 + /** 898 + * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint 899 + * @args: RPC transport to connect 900 + * 901 + * Invoked by a work queue tasklet. 902 + */ 903 + static void xs_tcp_connect_worker(void *args) 904 + { 905 + struct rpc_xprt *xprt = (struct rpc_xprt *)args; 906 + struct socket *sock = xprt->sock; 907 + int err, status = -EIO; 908 + 909 + if (xprt->shutdown || xprt->addr.sin_port == 0) 930 910 goto out; 931 911 932 - /* 933 - * Tell the socket layer to start connecting... 934 - */ 912 + dprintk("RPC: xs_tcp_connect_worker for xprt %p\n", xprt); 913 + 914 + /* Start by resetting any existing socket state */ 915 + xs_close(xprt); 916 + 917 + if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { 918 + dprintk("RPC: can't create TCP transport socket (%d).\n", -err); 919 + goto out; 920 + } 921 + 922 + if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) { 923 + sock_release(sock); 924 + goto out; 925 + } 926 + 927 + if (!xprt->inet) { 928 + struct sock *sk = sock->sk; 929 + 930 + write_lock_bh(&sk->sk_callback_lock); 931 + 932 + sk->sk_user_data = xprt; 933 + xprt->old_data_ready = sk->sk_data_ready; 934 + xprt->old_state_change = sk->sk_state_change; 935 + xprt->old_write_space = sk->sk_write_space; 936 + sk->sk_data_ready = xs_tcp_data_ready; 937 + sk->sk_state_change = xs_tcp_state_change; 938 + sk->sk_write_space = xs_tcp_write_space; 939 + tcp_sk(sk)->nonagle = 1; 940 + 941 + xprt_clear_connected(xprt); 942 + 943 + /* Reset to new socket */ 944 + xprt->sock = sock; 945 + xprt->inet = sk; 946 + 947 + write_unlock_bh(&sk->sk_callback_lock); 948 + } 949 + 950 + /* Tell the socket layer to start connecting... */ 935 951 status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, 936 952 sizeof(xprt->addr), O_NONBLOCK); 937 953 dprintk("RPC: %p connect status %d connected %d sock state %d\n", ··· 975 959 { 976 960 struct rpc_xprt *xprt = task->tk_xprt; 977 961 978 - if (!xprt_test_and_set_connecting(xprt)) { 979 - if (xprt->sock != NULL) { 980 - dprintk("RPC: xs_connect delayed xprt %p\n", xprt); 981 - schedule_delayed_work(&xprt->connect_worker, 962 + if (xprt_test_and_set_connecting(xprt)) 963 + return; 964 + 965 + if (xprt->sock != NULL) { 966 + dprintk("RPC: xs_connect delayed xprt %p\n", xprt); 967 + schedule_delayed_work(&xprt->connect_worker, 982 968 RPC_REESTABLISH_TIMEOUT); 983 - } else { 984 - dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); 985 - schedule_work(&xprt->connect_worker); 986 - /* flush_scheduled_work can sleep... */ 987 - if (!RPC_IS_ASYNC(task)) 988 - flush_scheduled_work(); 989 - } 969 + } else { 970 + dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); 971 + schedule_work(&xprt->connect_worker); 972 + 973 + /* flush_scheduled_work can sleep... */ 974 + if (!RPC_IS_ASYNC(task)) 975 + flush_scheduled_work(); 990 976 } 991 977 } 992 978 ··· 1031 1013 /* XXX: header size can vary due to auth type, IPv6, etc. */ 1032 1014 xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); 1033 1015 1034 - INIT_WORK(&xprt->connect_worker, xs_connect_worker, xprt); 1016 + INIT_WORK(&xprt->connect_worker, xs_udp_connect_worker, xprt); 1035 1017 1036 1018 xprt->ops = &xs_ops; 1037 1019 ··· 1070 1052 xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; 1071 1053 xprt->max_payload = (1U << 31) - 1; 1072 1054 1073 - INIT_WORK(&xprt->connect_worker, xs_connect_worker, xprt); 1055 + INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); 1074 1056 1075 1057 xprt->ops = &xs_ops; 1076 1058