aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-02-24 14:25:33 -0500
committerJ. Bruce Fields <bfields@redhat.com>2011-04-07 14:36:40 -0400
commit31d68ef65c7d49def19c1bae4e01b87d66cf5a56 (patch)
treee55082c9573cb189f352c5fa9eb1c9d0ef5cf2d0 /net
parent586c52cc61b5b84c70102208b78269ef5924bf49 (diff)
SUNRPC: Don't wait for full record to receive tcp data
Ensure that we immediately read and buffer data from the incoming TCP stream so that we grow the receive window quickly, and don't deadlock on large READ or WRITE requests. Also do some minor exit cleanup. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/svcsock.c144
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
390static 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
914static 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
933static 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
947static 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 }
960out:
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: 1041error:
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: 1044err_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
1107err_again:
1108 if (len == -EAGAIN) {
1109 dprintk("RPC: TCP recvfrom got EAGAIN\n");
1110 return len;
1111 }
1112error: 1185error:
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;
1190err_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);
1194err_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/*