diff options
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/svcsock.c | 50 |
1 files changed, 25 insertions, 25 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 2b09e2306bfa..38ec968ca1c6 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -949,20 +949,11 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
949 | return -EAGAIN; | 949 | return -EAGAIN; |
950 | } | 950 | } |
951 | 951 | ||
952 | if (!(svc_sock_final_rec(svsk))) { | ||
953 | /* FIXME: technically, a record can be fragmented, | ||
954 | * and non-terminal fragments will not have the top | ||
955 | * bit set in the fragment length header. | ||
956 | * But apparently no known nfs clients send fragmented | ||
957 | * records. */ | ||
958 | net_notice_ratelimited("RPC: multiple fragments per record not supported\n"); | ||
959 | goto err_delete; | ||
960 | } | ||
961 | |||
962 | dprintk("svc: TCP record, %d bytes\n", svc_sock_reclen(svsk)); | 952 | dprintk("svc: TCP record, %d bytes\n", svc_sock_reclen(svsk)); |
963 | if (svc_sock_reclen(svsk) > serv->sv_max_mesg) { | 953 | if (svc_sock_reclen(svsk) + svsk->sk_datalen > |
954 | serv->sv_max_mesg) { | ||
964 | net_notice_ratelimited("RPC: fragment too large: 0x%08lx\n", | 955 | net_notice_ratelimited("RPC: fragment too large: 0x%08lx\n", |
965 | (unsigned long)svc_sock_reclen(svsk)); | 956 | (unsigned long)svsk->sk_reclen); |
966 | goto err_delete; | 957 | goto err_delete; |
967 | } | 958 | } |
968 | } | 959 | } |
@@ -1030,6 +1021,17 @@ static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) | |||
1030 | return i; | 1021 | return i; |
1031 | } | 1022 | } |
1032 | 1023 | ||
1024 | static void svc_tcp_fragment_received(struct svc_sock *svsk) | ||
1025 | { | ||
1026 | /* If we have more data, signal svc_xprt_enqueue() to try again */ | ||
1027 | if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) | ||
1028 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | ||
1029 | dprintk("svc: TCP %s record (%d bytes)\n", | ||
1030 | svc_sock_final_rec(svsk) ? "final" : "nonfinal", | ||
1031 | svc_sock_reclen(svsk)); | ||
1032 | svsk->sk_tcplen = 0; | ||
1033 | svsk->sk_reclen = 0; | ||
1034 | } | ||
1033 | 1035 | ||
1034 | /* | 1036 | /* |
1035 | * Receive data from a TCP socket. | 1037 | * Receive data from a TCP socket. |
@@ -1056,12 +1058,12 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1056 | goto error; | 1058 | goto error; |
1057 | 1059 | ||
1058 | base = svc_tcp_restore_pages(svsk, rqstp); | 1060 | base = svc_tcp_restore_pages(svsk, rqstp); |
1059 | want = svc_sock_reclen(svsk) - base; | 1061 | want = svc_sock_reclen(svsk) - (svsk->sk_tcplen - sizeof(rpc_fraghdr)); |
1060 | 1062 | ||
1061 | vec = rqstp->rq_vec; | 1063 | vec = rqstp->rq_vec; |
1062 | 1064 | ||
1063 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], | 1065 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], |
1064 | svc_sock_reclen(svsk)); | 1066 | svsk->sk_datalen + want); |
1065 | 1067 | ||
1066 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; | 1068 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; |
1067 | 1069 | ||
@@ -1071,20 +1073,23 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1071 | svsk->sk_tcplen += len; | 1073 | svsk->sk_tcplen += len; |
1072 | svsk->sk_datalen += len; | 1074 | svsk->sk_datalen += len; |
1073 | } | 1075 | } |
1074 | if (len != want) { | 1076 | if (len != want || !svc_sock_final_rec(svsk)) { |
1075 | svc_tcp_save_pages(svsk, rqstp); | 1077 | svc_tcp_save_pages(svsk, rqstp); |
1076 | if (len < 0 && len != -EAGAIN) | 1078 | if (len < 0 && len != -EAGAIN) |
1077 | goto err_delete; | 1079 | goto err_delete; |
1078 | dprintk("svc: incomplete TCP record (%d of %d)\n", | 1080 | if (len == want) |
1079 | svsk->sk_tcplen - sizeof(rpc_fraghdr), | 1081 | svc_tcp_fragment_received(svsk); |
1080 | svc_sock_reclen(svsk)); | 1082 | else |
1083 | dprintk("svc: incomplete TCP record (%ld of %d)\n", | ||
1084 | svsk->sk_tcplen - sizeof(rpc_fraghdr), | ||
1085 | svc_sock_reclen(svsk)); | ||
1081 | goto err_noclose; | 1086 | goto err_noclose; |
1082 | } | 1087 | } |
1083 | 1088 | ||
1084 | if (svc_sock_reclen(svsk) < 8) | 1089 | if (svc_sock_reclen(svsk) < 8) |
1085 | goto err_delete; /* client is nuts. */ | 1090 | goto err_delete; /* client is nuts. */ |
1086 | 1091 | ||
1087 | rqstp->rq_arg.len = svc_sock_reclen(svsk); | 1092 | rqstp->rq_arg.len = svsk->sk_datalen; |
1088 | rqstp->rq_arg.page_base = 0; | 1093 | rqstp->rq_arg.page_base = 0; |
1089 | if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { | 1094 | if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { |
1090 | rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; | 1095 | rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; |
@@ -1101,12 +1106,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1101 | len = receive_cb_reply(svsk, rqstp); | 1106 | len = receive_cb_reply(svsk, rqstp); |
1102 | 1107 | ||
1103 | /* Reset TCP read info */ | 1108 | /* Reset TCP read info */ |
1104 | svsk->sk_reclen = 0; | ||
1105 | svsk->sk_tcplen = 0; | ||
1106 | svsk->sk_datalen = 0; | 1109 | svsk->sk_datalen = 0; |
1107 | /* If we have more data, signal svc_xprt_enqueue() to try again */ | 1110 | svc_tcp_fragment_received(svsk); |
1108 | if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) | ||
1109 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | ||
1110 | 1111 | ||
1111 | if (len < 0) | 1112 | if (len < 0) |
1112 | goto error; | 1113 | goto error; |
@@ -1115,7 +1116,6 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1115 | if (serv->sv_stats) | 1116 | if (serv->sv_stats) |
1116 | serv->sv_stats->nettcpcnt++; | 1117 | serv->sv_stats->nettcpcnt++; |
1117 | 1118 | ||
1118 | dprintk("svc: TCP complete record (%d bytes)\n", rqstp->rq_arg.len); | ||
1119 | return rqstp->rq_arg.len; | 1119 | return rqstp->rq_arg.len; |
1120 | 1120 | ||
1121 | error: | 1121 | error: |