diff options
Diffstat (limited to 'net/sunrpc/svcsock.c')
| -rw-r--r-- | net/sunrpc/svcsock.c | 144 |
1 files changed, 112 insertions, 32 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 40b502b11442..a4fafcbc6ea0 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -387,6 +387,33 @@ static int svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, | |||
| 387 | return len; | 387 | return len; |
| 388 | } | 388 | } |
| 389 | 389 | ||
| 390 | static int svc_partial_recvfrom(struct svc_rqst *rqstp, | ||
| 391 | struct kvec *iov, int nr, | ||
| 392 | int buflen, unsigned int base) | ||
| 393 | { | ||
| 394 | size_t save_iovlen; | ||
| 395 | void __user *save_iovbase; | ||
| 396 | unsigned int i; | ||
| 397 | int ret; | ||
| 398 | |||
| 399 | if (base == 0) | ||
| 400 | return svc_recvfrom(rqstp, iov, nr, buflen); | ||
| 401 | |||
| 402 | for (i = 0; i < nr; i++) { | ||
| 403 | if (iov[i].iov_len > base) | ||
| 404 | break; | ||
| 405 | base -= iov[i].iov_len; | ||
| 406 | } | ||
| 407 | save_iovlen = iov[i].iov_len; | ||
| 408 | save_iovbase = iov[i].iov_base; | ||
| 409 | iov[i].iov_len -= base; | ||
| 410 | iov[i].iov_base += base; | ||
| 411 | ret = svc_recvfrom(rqstp, &iov[i], nr - i, buflen); | ||
| 412 | iov[i].iov_len = save_iovlen; | ||
| 413 | iov[i].iov_base = save_iovbase; | ||
| 414 | return ret; | ||
| 415 | } | ||
| 416 | |||
| 390 | /* | 417 | /* |
| 391 | * Set socket snd and rcv buffer lengths | 418 | * Set socket snd and rcv buffer lengths |
| 392 | */ | 419 | */ |
| @@ -884,6 +911,56 @@ failed: | |||
| 884 | return NULL; | 911 | return NULL; |
| 885 | } | 912 | } |
| 886 | 913 | ||
| 914 | static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst *rqstp) | ||
| 915 | { | ||
| 916 | unsigned int i, len, npages; | ||
| 917 | |||
| 918 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | ||
| 919 | return 0; | ||
| 920 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | ||
| 921 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
| 922 | for (i = 0; i < npages; i++) { | ||
| 923 | if (rqstp->rq_pages[i] != NULL) | ||
| 924 | put_page(rqstp->rq_pages[i]); | ||
| 925 | BUG_ON(svsk->sk_pages[i] == NULL); | ||
| 926 | rqstp->rq_pages[i] = svsk->sk_pages[i]; | ||
| 927 | svsk->sk_pages[i] = NULL; | ||
| 928 | } | ||
| 929 | rqstp->rq_arg.head[0].iov_base = page_address(rqstp->rq_pages[0]); | ||
| 930 | return len; | ||
| 931 | } | ||
| 932 | |||
| 933 | static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp) | ||
| 934 | { | ||
| 935 | unsigned int i, len, npages; | ||
| 936 | |||
| 937 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | ||
| 938 | return; | ||
| 939 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | ||
| 940 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
| 941 | for (i = 0; i < npages; i++) { | ||
| 942 | svsk->sk_pages[i] = rqstp->rq_pages[i]; | ||
| 943 | rqstp->rq_pages[i] = NULL; | ||
| 944 | } | ||
| 945 | } | ||
| 946 | |||
| 947 | static void svc_tcp_clear_pages(struct svc_sock *svsk) | ||
| 948 | { | ||
| 949 | unsigned int i, len, npages; | ||
| 950 | |||
| 951 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | ||
| 952 | goto out; | ||
| 953 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | ||
| 954 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
| 955 | for (i = 0; i < npages; i++) { | ||
| 956 | BUG_ON(svsk->sk_pages[i] == NULL); | ||
| 957 | put_page(svsk->sk_pages[i]); | ||
| 958 | svsk->sk_pages[i] = NULL; | ||
| 959 | } | ||
| 960 | out: | ||
| 961 | svsk->sk_tcplen = 0; | ||
| 962 | } | ||
| 963 | |||
| 887 | /* | 964 | /* |
| 888 | * Receive data. | 965 | * Receive data. |
| 889 | * If we haven't gotten the record length yet, get the next four bytes. | 966 | * If we haven't gotten the record length yet, get the next four bytes. |
| @@ -928,7 +1005,7 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
| 928 | if (len < want) { | 1005 | if (len < want) { |
| 929 | dprintk("svc: short recvfrom while reading record " | 1006 | dprintk("svc: short recvfrom while reading record " |
| 930 | "length (%d of %d)\n", len, want); | 1007 | "length (%d of %d)\n", len, want); |
| 931 | goto err_again; /* record header not complete */ | 1008 | return -EAGAIN; |
| 932 | } | 1009 | } |
| 933 | 1010 | ||
| 934 | svsk->sk_reclen = ntohl(svsk->sk_reclen); | 1011 | svsk->sk_reclen = ntohl(svsk->sk_reclen); |
| @@ -958,26 +1035,14 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
| 958 | if (svsk->sk_reclen < 8) | 1035 | if (svsk->sk_reclen < 8) |
| 959 | goto err_delete; /* client is nuts. */ | 1036 | goto err_delete; /* client is nuts. */ |
| 960 | 1037 | ||
| 961 | /* Check whether enough data is available */ | ||
| 962 | len = svc_recv_available(svsk); | ||
| 963 | if (len < 0) | ||
| 964 | goto error; | ||
| 965 | |||
| 966 | if (len < svsk->sk_reclen) { | ||
| 967 | dprintk("svc: incomplete TCP record (%d of %d)\n", | ||
| 968 | len, svsk->sk_reclen); | ||
| 969 | goto err_again; /* record not complete */ | ||
| 970 | } | ||
| 971 | len = svsk->sk_reclen; | 1038 | len = svsk->sk_reclen; |
| 972 | 1039 | ||
| 973 | return len; | 1040 | return len; |
| 974 | error: | 1041 | error: |
| 975 | if (len == -EAGAIN) | 1042 | dprintk("RPC: TCP recv_record got %d\n", len); |
| 976 | dprintk("RPC: TCP recv_record got EAGAIN\n"); | ||
| 977 | return len; | 1043 | return len; |
| 978 | err_delete: | 1044 | err_delete: |
| 979 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); | 1045 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); |
| 980 | err_again: | ||
| 981 | return -EAGAIN; | 1046 | return -EAGAIN; |
| 982 | } | 1047 | } |
| 983 | 1048 | ||
| @@ -1035,6 +1100,7 @@ static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) | |||
| 1035 | return i; | 1100 | return i; |
| 1036 | } | 1101 | } |
| 1037 | 1102 | ||
| 1103 | |||
| 1038 | /* | 1104 | /* |
| 1039 | * Receive data from a TCP socket. | 1105 | * Receive data from a TCP socket. |
| 1040 | */ | 1106 | */ |
| @@ -1045,6 +1111,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1045 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; | 1111 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; |
| 1046 | int len; | 1112 | int len; |
| 1047 | struct kvec *vec; | 1113 | struct kvec *vec; |
| 1114 | unsigned int want, base; | ||
| 1048 | __be32 *p; | 1115 | __be32 *p; |
| 1049 | __be32 calldir; | 1116 | __be32 calldir; |
| 1050 | int pnum; | 1117 | int pnum; |
| @@ -1058,6 +1125,9 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1058 | if (len < 0) | 1125 | if (len < 0) |
| 1059 | goto error; | 1126 | goto error; |
| 1060 | 1127 | ||
| 1128 | base = svc_tcp_restore_pages(svsk, rqstp); | ||
| 1129 | want = svsk->sk_reclen - base; | ||
| 1130 | |||
| 1061 | vec = rqstp->rq_vec; | 1131 | vec = rqstp->rq_vec; |
| 1062 | 1132 | ||
| 1063 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], | 1133 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], |
| @@ -1066,11 +1136,18 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1066 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; | 1136 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; |
| 1067 | 1137 | ||
| 1068 | /* Now receive data */ | 1138 | /* Now receive data */ |
| 1069 | len = svc_recvfrom(rqstp, vec, pnum, svsk->sk_reclen); | 1139 | len = svc_partial_recvfrom(rqstp, vec, pnum, want, base); |
| 1070 | if (len < 0) | 1140 | if (len >= 0) |
| 1071 | goto err_again; | 1141 | svsk->sk_tcplen += len; |
| 1142 | if (len != want) { | ||
| 1143 | if (len < 0 && len != -EAGAIN) | ||
| 1144 | goto err_other; | ||
| 1145 | svc_tcp_save_pages(svsk, rqstp); | ||
| 1146 | dprintk("svc: incomplete TCP record (%d of %d)\n", | ||
| 1147 | svsk->sk_tcplen, svsk->sk_reclen); | ||
| 1148 | goto err_noclose; | ||
| 1149 | } | ||
| 1072 | 1150 | ||
| 1073 | dprintk("svc: TCP complete record (%d bytes)\n", svsk->sk_reclen); | ||
| 1074 | rqstp->rq_arg.len = svsk->sk_reclen; | 1151 | rqstp->rq_arg.len = svsk->sk_reclen; |
| 1075 | rqstp->rq_arg.page_base = 0; | 1152 | rqstp->rq_arg.page_base = 0; |
| 1076 | if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { | 1153 | if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { |
| @@ -1087,7 +1164,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1087 | if (calldir) { | 1164 | if (calldir) { |
| 1088 | len = receive_cb_reply(svsk, rqstp); | 1165 | len = receive_cb_reply(svsk, rqstp); |
| 1089 | if (len < 0) | 1166 | if (len < 0) |
| 1090 | goto err_again; | 1167 | goto error; |
| 1091 | } | 1168 | } |
| 1092 | 1169 | ||
| 1093 | /* Reset TCP read info */ | 1170 | /* Reset TCP read info */ |
| @@ -1102,20 +1179,20 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 1102 | if (serv->sv_stats) | 1179 | if (serv->sv_stats) |
| 1103 | serv->sv_stats->nettcpcnt++; | 1180 | serv->sv_stats->nettcpcnt++; |
| 1104 | 1181 | ||
| 1182 | dprintk("svc: TCP complete record (%d bytes)\n", rqstp->rq_arg.len); | ||
| 1105 | return rqstp->rq_arg.len; | 1183 | return rqstp->rq_arg.len; |
| 1106 | 1184 | ||
| 1107 | err_again: | ||
| 1108 | if (len == -EAGAIN) { | ||
| 1109 | dprintk("RPC: TCP recvfrom got EAGAIN\n"); | ||
| 1110 | return len; | ||
| 1111 | } | ||
| 1112 | error: | 1185 | error: |
| 1113 | if (len != -EAGAIN) { | 1186 | if (len != -EAGAIN) |
| 1114 | printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", | 1187 | goto err_other; |
| 1115 | svsk->sk_xprt.xpt_server->sv_name, -len); | 1188 | dprintk("RPC: TCP recvfrom got EAGAIN\n"); |
| 1116 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); | ||
| 1117 | } | ||
| 1118 | return -EAGAIN; | 1189 | return -EAGAIN; |
| 1190 | err_other: | ||
| 1191 | printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", | ||
| 1192 | svsk->sk_xprt.xpt_server->sv_name, -len); | ||
| 1193 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); | ||
| 1194 | err_noclose: | ||
| 1195 | return -EAGAIN; /* record not complete */ | ||
| 1119 | } | 1196 | } |
| 1120 | 1197 | ||
| 1121 | /* | 1198 | /* |
| @@ -1286,6 +1363,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) | |||
| 1286 | 1363 | ||
| 1287 | svsk->sk_reclen = 0; | 1364 | svsk->sk_reclen = 0; |
| 1288 | svsk->sk_tcplen = 0; | 1365 | svsk->sk_tcplen = 0; |
| 1366 | memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); | ||
| 1289 | 1367 | ||
| 1290 | tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; | 1368 | tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; |
| 1291 | 1369 | ||
| @@ -1544,8 +1622,10 @@ static void svc_tcp_sock_detach(struct svc_xprt *xprt) | |||
| 1544 | 1622 | ||
| 1545 | svc_sock_detach(xprt); | 1623 | svc_sock_detach(xprt); |
| 1546 | 1624 | ||
| 1547 | if (!test_bit(XPT_LISTENER, &xprt->xpt_flags)) | 1625 | if (!test_bit(XPT_LISTENER, &xprt->xpt_flags)) { |
| 1626 | svc_tcp_clear_pages(svsk); | ||
| 1548 | kernel_sock_shutdown(svsk->sk_sock, SHUT_RDWR); | 1627 | kernel_sock_shutdown(svsk->sk_sock, SHUT_RDWR); |
| 1628 | } | ||
| 1549 | } | 1629 | } |
| 1550 | 1630 | ||
| 1551 | /* | 1631 | /* |
