diff options
Diffstat (limited to 'net/sunrpc/svcsock.c')
-rw-r--r-- | net/sunrpc/svcsock.c | 106 |
1 files changed, 56 insertions, 50 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 03827cef1fa7..0f679df7d072 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", |
@@ -461,7 +465,7 @@ static int svc_udp_get_dest_address4(struct svc_rqst *rqstp, | |||
461 | } | 465 | } |
462 | 466 | ||
463 | /* | 467 | /* |
464 | * See net/ipv6/datagram.c : datagram_recv_ctl | 468 | * See net/ipv6/datagram.c : ip6_datagram_recv_ctl |
465 | */ | 469 | */ |
466 | static int svc_udp_get_dest_address6(struct svc_rqst *rqstp, | 470 | static int svc_udp_get_dest_address6(struct svc_rqst *rqstp, |
467 | struct cmsghdr *cmh) | 471 | struct cmsghdr *cmh) |
@@ -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; |