diff options
Diffstat (limited to 'net/sunrpc/svcsock.c')
-rw-r--r-- | net/sunrpc/svcsock.c | 98 |
1 files changed, 50 insertions, 48 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index cc3020d16789..0a148c9d2a5c 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -605,6 +605,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
605 | rqstp->rq_respages = rqstp->rq_pages + 1 + | 605 | rqstp->rq_respages = rqstp->rq_pages + 1 + |
606 | DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); | 606 | DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); |
607 | } | 607 | } |
608 | rqstp->rq_next_page = rqstp->rq_respages+1; | ||
608 | 609 | ||
609 | if (serv->sv_stats) | 610 | if (serv->sv_stats) |
610 | serv->sv_stats->netudpcnt++; | 611 | serv->sv_stats->netudpcnt++; |
@@ -878,9 +879,9 @@ static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst | |||
878 | { | 879 | { |
879 | unsigned int i, len, npages; | 880 | unsigned int i, len, npages; |
880 | 881 | ||
881 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 882 | if (svsk->sk_datalen == 0) |
882 | return 0; | 883 | return 0; |
883 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 884 | len = svsk->sk_datalen; |
884 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 885 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
885 | for (i = 0; i < npages; i++) { | 886 | for (i = 0; i < npages; i++) { |
886 | if (rqstp->rq_pages[i] != NULL) | 887 | if (rqstp->rq_pages[i] != NULL) |
@@ -897,9 +898,9 @@ static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
897 | { | 898 | { |
898 | unsigned int i, len, npages; | 899 | unsigned int i, len, npages; |
899 | 900 | ||
900 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 901 | if (svsk->sk_datalen == 0) |
901 | return; | 902 | return; |
902 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 903 | len = svsk->sk_datalen; |
903 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 904 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
904 | for (i = 0; i < npages; i++) { | 905 | for (i = 0; i < npages; i++) { |
905 | svsk->sk_pages[i] = rqstp->rq_pages[i]; | 906 | svsk->sk_pages[i] = rqstp->rq_pages[i]; |
@@ -911,9 +912,9 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) | |||
911 | { | 912 | { |
912 | unsigned int i, len, npages; | 913 | unsigned int i, len, npages; |
913 | 914 | ||
914 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 915 | if (svsk->sk_datalen == 0) |
915 | goto out; | 916 | goto out; |
916 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 917 | len = svsk->sk_datalen; |
917 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 918 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
918 | for (i = 0; i < npages; i++) { | 919 | for (i = 0; i < npages; i++) { |
919 | BUG_ON(svsk->sk_pages[i] == NULL); | 920 | BUG_ON(svsk->sk_pages[i] == NULL); |
@@ -922,13 +923,12 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) | |||
922 | } | 923 | } |
923 | out: | 924 | out: |
924 | svsk->sk_tcplen = 0; | 925 | svsk->sk_tcplen = 0; |
926 | svsk->sk_datalen = 0; | ||
925 | } | 927 | } |
926 | 928 | ||
927 | /* | 929 | /* |
928 | * Receive data. | 930 | * Receive fragment record header. |
929 | * 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. |
930 | * Otherwise try to gobble up as much as possible up to the complete | ||
931 | * record length. | ||
932 | */ | 932 | */ |
933 | 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) |
934 | { | 934 | { |
@@ -954,32 +954,16 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
954 | return -EAGAIN; | 954 | return -EAGAIN; |
955 | } | 955 | } |
956 | 956 | ||
957 | svsk->sk_reclen = ntohl(svsk->sk_reclen); | 957 | dprintk("svc: TCP record, %d bytes\n", svc_sock_reclen(svsk)); |
958 | if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) { | 958 | if (svc_sock_reclen(svsk) + svsk->sk_datalen > |
959 | /* FIXME: technically, a record can be fragmented, | 959 | serv->sv_max_mesg) { |
960 | * and non-terminal fragments will not have the top | 960 | net_notice_ratelimited("RPC: fragment too large: %d\n", |
961 | * bit set in the fragment length header. | 961 | svc_sock_reclen(svsk)); |
962 | * But apparently no known nfs clients send fragmented | ||
963 | * records. */ | ||
964 | net_notice_ratelimited("RPC: multiple fragments per record not supported\n"); | ||
965 | goto err_delete; | ||
966 | } | ||
967 | |||
968 | svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK; | ||
969 | dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen); | ||
970 | if (svsk->sk_reclen > serv->sv_max_mesg) { | ||
971 | net_notice_ratelimited("RPC: fragment too large: 0x%08lx\n", | ||
972 | (unsigned long)svsk->sk_reclen); | ||
973 | goto err_delete; | 962 | goto err_delete; |
974 | } | 963 | } |
975 | } | 964 | } |
976 | 965 | ||
977 | if (svsk->sk_reclen < 8) | 966 | return svc_sock_reclen(svsk); |
978 | goto err_delete; /* client is nuts. */ | ||
979 | |||
980 | len = svsk->sk_reclen; | ||
981 | |||
982 | return len; | ||
983 | error: | 967 | error: |
984 | dprintk("RPC: TCP recv_record got %d\n", len); | 968 | dprintk("RPC: TCP recv_record got %d\n", len); |
985 | return len; | 969 | return len; |
@@ -1023,7 +1007,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
1023 | if (dst->iov_len < src->iov_len) | 1007 | if (dst->iov_len < src->iov_len) |
1024 | return -EAGAIN; /* whatever; just giving up. */ | 1008 | return -EAGAIN; /* whatever; just giving up. */ |
1025 | memcpy(dst->iov_base, src->iov_base, src->iov_len); | 1009 | memcpy(dst->iov_base, src->iov_base, src->iov_len); |
1026 | xprt_complete_rqst(req->rq_task, svsk->sk_reclen); | 1010 | xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); |
1027 | rqstp->rq_arg.len = 0; | 1011 | rqstp->rq_arg.len = 0; |
1028 | return 0; | 1012 | return 0; |
1029 | } | 1013 | } |
@@ -1042,6 +1026,17 @@ static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) | |||
1042 | return i; | 1026 | return i; |
1043 | } | 1027 | } |
1044 | 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 | } | ||
1045 | 1040 | ||
1046 | /* | 1041 | /* |
1047 | * Receive data from a TCP socket. | 1042 | * Receive data from a TCP socket. |
@@ -1068,29 +1063,39 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1068 | goto error; | 1063 | goto error; |
1069 | 1064 | ||
1070 | base = svc_tcp_restore_pages(svsk, rqstp); | 1065 | base = svc_tcp_restore_pages(svsk, rqstp); |
1071 | want = svsk->sk_reclen - base; | 1066 | want = svc_sock_reclen(svsk) - (svsk->sk_tcplen - sizeof(rpc_fraghdr)); |
1072 | 1067 | ||
1073 | vec = rqstp->rq_vec; | 1068 | vec = rqstp->rq_vec; |
1074 | 1069 | ||
1075 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], | 1070 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], |
1076 | svsk->sk_reclen); | 1071 | svsk->sk_datalen + want); |
1077 | 1072 | ||
1078 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; | 1073 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; |
1074 | rqstp->rq_next_page = rqstp->rq_respages + 1; | ||
1079 | 1075 | ||
1080 | /* Now receive data */ | 1076 | /* Now receive data */ |
1081 | len = svc_partial_recvfrom(rqstp, vec, pnum, want, base); | 1077 | len = svc_partial_recvfrom(rqstp, vec, pnum, want, base); |
1082 | if (len >= 0) | 1078 | if (len >= 0) { |
1083 | svsk->sk_tcplen += len; | 1079 | svsk->sk_tcplen += len; |
1084 | if (len != want) { | 1080 | svsk->sk_datalen += len; |
1081 | } | ||
1082 | if (len != want || !svc_sock_final_rec(svsk)) { | ||
1085 | svc_tcp_save_pages(svsk, rqstp); | 1083 | svc_tcp_save_pages(svsk, rqstp); |
1086 | if (len < 0 && len != -EAGAIN) | 1084 | if (len < 0 && len != -EAGAIN) |
1087 | goto err_other; | 1085 | goto err_delete; |
1088 | dprintk("svc: incomplete TCP record (%d of %d)\n", | 1086 | if (len == want) |
1089 | 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)); | ||
1090 | goto err_noclose; | 1092 | goto err_noclose; |
1091 | } | 1093 | } |
1092 | 1094 | ||
1093 | 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; | ||
1094 | rqstp->rq_arg.page_base = 0; | 1099 | rqstp->rq_arg.page_base = 0; |
1095 | 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) { |
1096 | rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; | 1101 | rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; |
@@ -1107,11 +1112,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1107 | len = receive_cb_reply(svsk, rqstp); | 1112 | len = receive_cb_reply(svsk, rqstp); |
1108 | 1113 | ||
1109 | /* Reset TCP read info */ | 1114 | /* Reset TCP read info */ |
1110 | svsk->sk_reclen = 0; | 1115 | svsk->sk_datalen = 0; |
1111 | svsk->sk_tcplen = 0; | 1116 | svc_tcp_fragment_received(svsk); |
1112 | /* If we have more data, signal svc_xprt_enqueue() to try again */ | ||
1113 | if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) | ||
1114 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | ||
1115 | 1117 | ||
1116 | if (len < 0) | 1118 | if (len < 0) |
1117 | goto error; | 1119 | goto error; |
@@ -1120,15 +1122,14 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1120 | if (serv->sv_stats) | 1122 | if (serv->sv_stats) |
1121 | serv->sv_stats->nettcpcnt++; | 1123 | serv->sv_stats->nettcpcnt++; |
1122 | 1124 | ||
1123 | dprintk("svc: TCP complete record (%d bytes)\n", rqstp->rq_arg.len); | ||
1124 | return rqstp->rq_arg.len; | 1125 | return rqstp->rq_arg.len; |
1125 | 1126 | ||
1126 | error: | 1127 | error: |
1127 | if (len != -EAGAIN) | 1128 | if (len != -EAGAIN) |
1128 | goto err_other; | 1129 | goto err_delete; |
1129 | dprintk("RPC: TCP recvfrom got EAGAIN\n"); | 1130 | dprintk("RPC: TCP recvfrom got EAGAIN\n"); |
1130 | return 0; | 1131 | return 0; |
1131 | err_other: | 1132 | err_delete: |
1132 | printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", | 1133 | printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", |
1133 | svsk->sk_xprt.xpt_server->sv_name, -len); | 1134 | svsk->sk_xprt.xpt_server->sv_name, -len); |
1134 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); | 1135 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); |
@@ -1305,6 +1306,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) | |||
1305 | 1306 | ||
1306 | svsk->sk_reclen = 0; | 1307 | svsk->sk_reclen = 0; |
1307 | svsk->sk_tcplen = 0; | 1308 | svsk->sk_tcplen = 0; |
1309 | svsk->sk_datalen = 0; | ||
1308 | memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); | 1310 | memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); |
1309 | 1311 | ||
1310 | tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; | 1312 | tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; |