diff options
Diffstat (limited to 'net/sunrpc/svcsock.c')
| -rw-r--r-- | net/sunrpc/svcsock.c | 104 |
1 files changed, 55 insertions, 49 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 03827cef1fa7..0a148c9d2a5c 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -84,7 +84,11 @@ static struct lock_class_key svc_slock_key[2]; | |||
| 84 | static void svc_reclassify_socket(struct socket *sock) | 84 | static void svc_reclassify_socket(struct socket *sock) |
| 85 | { | 85 | { |
| 86 | struct sock *sk = sock->sk; | 86 | struct sock *sk = sock->sk; |
| 87 | BUG_ON(sock_owned_by_user(sk)); | 87 | |
| 88 | WARN_ON_ONCE(sock_owned_by_user(sk)); | ||
| 89 | if (sock_owned_by_user(sk)) | ||
| 90 | return; | ||
| 91 | |||
| 88 | switch (sk->sk_family) { | 92 | switch (sk->sk_family) { |
| 89 | case AF_INET: | 93 | case AF_INET: |
| 90 | sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD", | 94 | sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD", |
| @@ -601,6 +605,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 601 | rqstp->rq_respages = rqstp->rq_pages + 1 + | 605 | rqstp->rq_respages = rqstp->rq_pages + 1 + |
| 602 | DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); | 606 | DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); |
| 603 | } | 607 | } |
| 608 | rqstp->rq_next_page = rqstp->rq_respages+1; | ||
| 604 | 609 | ||
| 605 | if (serv->sv_stats) | 610 | if (serv->sv_stats) |
| 606 | serv->sv_stats->netudpcnt++; | 611 | serv->sv_stats->netudpcnt++; |
| @@ -874,9 +879,9 @@ static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst | |||
| 874 | { | 879 | { |
| 875 | unsigned int i, len, npages; | 880 | unsigned int i, len, npages; |
| 876 | 881 | ||
| 877 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 882 | if (svsk->sk_datalen == 0) |
| 878 | return 0; | 883 | return 0; |
| 879 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 884 | len = svsk->sk_datalen; |
| 880 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 885 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
| 881 | for (i = 0; i < npages; i++) { | 886 | for (i = 0; i < npages; i++) { |
| 882 | if (rqstp->rq_pages[i] != NULL) | 887 | if (rqstp->rq_pages[i] != NULL) |
| @@ -893,9 +898,9 @@ static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
| 893 | { | 898 | { |
| 894 | unsigned int i, len, npages; | 899 | unsigned int i, len, npages; |
| 895 | 900 | ||
| 896 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 901 | if (svsk->sk_datalen == 0) |
| 897 | return; | 902 | return; |
| 898 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 903 | len = svsk->sk_datalen; |
| 899 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 904 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
| 900 | for (i = 0; i < npages; i++) { | 905 | for (i = 0; i < npages; i++) { |
| 901 | svsk->sk_pages[i] = rqstp->rq_pages[i]; | 906 | svsk->sk_pages[i] = rqstp->rq_pages[i]; |
| @@ -907,9 +912,9 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) | |||
| 907 | { | 912 | { |
| 908 | unsigned int i, len, npages; | 913 | unsigned int i, len, npages; |
| 909 | 914 | ||
| 910 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 915 | if (svsk->sk_datalen == 0) |
| 911 | goto out; | 916 | goto out; |
| 912 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 917 | len = svsk->sk_datalen; |
| 913 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 918 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
| 914 | for (i = 0; i < npages; i++) { | 919 | for (i = 0; i < npages; i++) { |
| 915 | BUG_ON(svsk->sk_pages[i] == NULL); | 920 | BUG_ON(svsk->sk_pages[i] == NULL); |
| @@ -918,13 +923,12 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) | |||
| 918 | } | 923 | } |
| 919 | out: | 924 | out: |
| 920 | svsk->sk_tcplen = 0; | 925 | svsk->sk_tcplen = 0; |
| 926 | svsk->sk_datalen = 0; | ||
| 921 | } | 927 | } |
| 922 | 928 | ||
| 923 | /* | 929 | /* |
| 924 | * Receive data. | 930 | * Receive fragment record header. |
| 925 | * If we haven't gotten the record length yet, get the next four bytes. | 931 | * If we haven't gotten the record length yet, get the next four bytes. |
| 926 | * Otherwise try to gobble up as much as possible up to the complete | ||
| 927 | * record length. | ||
| 928 | */ | 932 | */ |
| 929 | static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | 933 | static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) |
| 930 | { | 934 | { |
| @@ -950,32 +954,16 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
| 950 | return -EAGAIN; | 954 | return -EAGAIN; |
| 951 | } | 955 | } |
| 952 | 956 | ||
| 953 | svsk->sk_reclen = ntohl(svsk->sk_reclen); | 957 | dprintk("svc: TCP record, %d bytes\n", svc_sock_reclen(svsk)); |
| 954 | if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) { | 958 | if (svc_sock_reclen(svsk) + svsk->sk_datalen > |
| 955 | /* FIXME: technically, a record can be fragmented, | 959 | serv->sv_max_mesg) { |
| 956 | * and non-terminal fragments will not have the top | 960 | net_notice_ratelimited("RPC: fragment too large: %d\n", |
| 957 | * bit set in the fragment length header. | 961 | svc_sock_reclen(svsk)); |
| 958 | * But apparently no known nfs clients send fragmented | ||
| 959 | * records. */ | ||
| 960 | net_notice_ratelimited("RPC: multiple fragments per record not supported\n"); | ||
| 961 | goto err_delete; | ||
| 962 | } | ||
| 963 | |||
| 964 | svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK; | ||
| 965 | dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen); | ||
| 966 | if (svsk->sk_reclen > serv->sv_max_mesg) { | ||
| 967 | net_notice_ratelimited("RPC: fragment too large: 0x%08lx\n", | ||
| 968 | (unsigned long)svsk->sk_reclen); | ||
| 969 | goto err_delete; | 962 | goto err_delete; |
| 970 | } | 963 | } |
| 971 | } | 964 | } |
| 972 | 965 | ||
| 973 | if (svsk->sk_reclen < 8) | 966 | return svc_sock_reclen(svsk); |
| 974 | goto err_delete; /* client is nuts. */ | ||
| 975 | |||
| 976 | len = svsk->sk_reclen; | ||
| 977 | |||
| 978 | return len; | ||
| 979 | error: | 967 | error: |
| 980 | dprintk("RPC: TCP recv_record got %d\n", len); | 968 | dprintk("RPC: TCP recv_record got %d\n", len); |
| 981 | return len; | 969 | return len; |
| @@ -1019,7 +1007,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
| 1019 | if (dst->iov_len < src->iov_len) | 1007 | if (dst->iov_len < src->iov_len) |
| 1020 | return -EAGAIN; /* whatever; just giving up. */ | 1008 | return -EAGAIN; /* whatever; just giving up. */ |
| 1021 | memcpy(dst->iov_base, src->iov_base, src->iov_len); | 1009 | memcpy(dst->iov_base, src->iov_base, src->iov_len); |
| 1022 | xprt_complete_rqst(req->rq_task, svsk->sk_reclen); | 1010 | xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); |
| 1023 | rqstp->rq_arg.len = 0; | 1011 | rqstp->rq_arg.len = 0; |
| 1024 | return 0; | 1012 | return 0; |
| 1025 | } | 1013 | } |
| @@ -1038,6 +1026,17 @@ static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) | |||
| 1038 | return i; | 1026 | return i; |
| 1039 | } | 1027 | } |
| 1040 | 1028 | ||
| 1029 | static void svc_tcp_fragment_received(struct svc_sock *svsk) | ||
| 1030 | { | ||
| 1031 | /* If we have more data, signal svc_xprt_enqueue() to try again */ | ||
| 1032 | if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) | ||
| 1033 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | ||
| 1034 | dprintk("svc: TCP %s record (%d bytes)\n", | ||
| 1035 | svc_sock_final_rec(svsk) ? "final" : "nonfinal", | ||
| 1036 | svc_sock_reclen(svsk)); | ||
| 1037 | svsk->sk_tcplen = 0; | ||
| 1038 | svsk->sk_reclen = 0; | ||
| 1039 | } | ||
| 1041 | 1040 | ||
| 1042 | /* | 1041 | /* |
| 1043 | * Receive data from a TCP socket. | 1042 | * Receive data from a TCP socket. |
| @@ -1064,29 +1063,39 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1064 | goto error; | 1063 | goto error; |
| 1065 | 1064 | ||
| 1066 | base = svc_tcp_restore_pages(svsk, rqstp); | 1065 | base = svc_tcp_restore_pages(svsk, rqstp); |
| 1067 | want = svsk->sk_reclen - base; | 1066 | want = svc_sock_reclen(svsk) - (svsk->sk_tcplen - sizeof(rpc_fraghdr)); |
| 1068 | 1067 | ||
| 1069 | vec = rqstp->rq_vec; | 1068 | vec = rqstp->rq_vec; |
| 1070 | 1069 | ||
| 1071 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], | 1070 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], |
| 1072 | svsk->sk_reclen); | 1071 | svsk->sk_datalen + want); |
| 1073 | 1072 | ||
| 1074 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; | 1073 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; |
| 1074 | rqstp->rq_next_page = rqstp->rq_respages + 1; | ||
| 1075 | 1075 | ||
| 1076 | /* Now receive data */ | 1076 | /* Now receive data */ |
| 1077 | len = svc_partial_recvfrom(rqstp, vec, pnum, want, base); | 1077 | len = svc_partial_recvfrom(rqstp, vec, pnum, want, base); |
| 1078 | if (len >= 0) | 1078 | if (len >= 0) { |
| 1079 | svsk->sk_tcplen += len; | 1079 | svsk->sk_tcplen += len; |
| 1080 | if (len != want) { | 1080 | svsk->sk_datalen += len; |
| 1081 | } | ||
| 1082 | if (len != want || !svc_sock_final_rec(svsk)) { | ||
| 1081 | svc_tcp_save_pages(svsk, rqstp); | 1083 | svc_tcp_save_pages(svsk, rqstp); |
| 1082 | if (len < 0 && len != -EAGAIN) | 1084 | if (len < 0 && len != -EAGAIN) |
| 1083 | goto err_other; | 1085 | goto err_delete; |
| 1084 | dprintk("svc: incomplete TCP record (%d of %d)\n", | 1086 | if (len == want) |
| 1085 | svsk->sk_tcplen, svsk->sk_reclen); | 1087 | svc_tcp_fragment_received(svsk); |
| 1088 | else | ||
| 1089 | dprintk("svc: incomplete TCP record (%d of %d)\n", | ||
| 1090 | (int)(svsk->sk_tcplen - sizeof(rpc_fraghdr)), | ||
| 1091 | svc_sock_reclen(svsk)); | ||
| 1086 | goto err_noclose; | 1092 | goto err_noclose; |
| 1087 | } | 1093 | } |
| 1088 | 1094 | ||
| 1089 | rqstp->rq_arg.len = svsk->sk_reclen; | 1095 | if (svc_sock_reclen(svsk) < 8) |
| 1096 | goto err_delete; /* client is nuts. */ | ||
| 1097 | |||
| 1098 | rqstp->rq_arg.len = svsk->sk_datalen; | ||
| 1090 | rqstp->rq_arg.page_base = 0; | 1099 | rqstp->rq_arg.page_base = 0; |
| 1091 | if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { | 1100 | if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { |
| 1092 | rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; | 1101 | rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; |
| @@ -1103,11 +1112,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1103 | len = receive_cb_reply(svsk, rqstp); | 1112 | len = receive_cb_reply(svsk, rqstp); |
| 1104 | 1113 | ||
| 1105 | /* Reset TCP read info */ | 1114 | /* Reset TCP read info */ |
| 1106 | svsk->sk_reclen = 0; | 1115 | svsk->sk_datalen = 0; |
| 1107 | svsk->sk_tcplen = 0; | 1116 | svc_tcp_fragment_received(svsk); |
| 1108 | /* If we have more data, signal svc_xprt_enqueue() to try again */ | ||
| 1109 | if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) | ||
| 1110 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | ||
| 1111 | 1117 | ||
| 1112 | if (len < 0) | 1118 | if (len < 0) |
| 1113 | goto error; | 1119 | goto error; |
| @@ -1116,15 +1122,14 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1116 | if (serv->sv_stats) | 1122 | if (serv->sv_stats) |
| 1117 | serv->sv_stats->nettcpcnt++; | 1123 | serv->sv_stats->nettcpcnt++; |
| 1118 | 1124 | ||
| 1119 | dprintk("svc: TCP complete record (%d bytes)\n", rqstp->rq_arg.len); | ||
| 1120 | return rqstp->rq_arg.len; | 1125 | return rqstp->rq_arg.len; |
| 1121 | 1126 | ||
| 1122 | error: | 1127 | error: |
| 1123 | if (len != -EAGAIN) | 1128 | if (len != -EAGAIN) |
| 1124 | goto err_other; | 1129 | goto err_delete; |
| 1125 | dprintk("RPC: TCP recvfrom got EAGAIN\n"); | 1130 | dprintk("RPC: TCP recvfrom got EAGAIN\n"); |
| 1126 | return 0; | 1131 | return 0; |
| 1127 | err_other: | 1132 | err_delete: |
| 1128 | printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", | 1133 | printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", |
| 1129 | svsk->sk_xprt.xpt_server->sv_name, -len); | 1134 | svsk->sk_xprt.xpt_server->sv_name, -len); |
| 1130 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); | 1135 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); |
| @@ -1301,6 +1306,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) | |||
| 1301 | 1306 | ||
| 1302 | svsk->sk_reclen = 0; | 1307 | svsk->sk_reclen = 0; |
| 1303 | svsk->sk_tcplen = 0; | 1308 | svsk->sk_tcplen = 0; |
| 1309 | svsk->sk_datalen = 0; | ||
| 1304 | memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); | 1310 | memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); |
| 1305 | 1311 | ||
| 1306 | tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; | 1312 | tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; |
