aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2012-12-03 15:50:38 -0500
committerJ. Bruce Fields <bfields@redhat.com>2012-12-04 07:49:24 -0500
commit836fbadb96a8308e6283eee5c7b3bdae818b58ca (patch)
treebeb0b70d57d7ac98adbc1931483f2c2ff5d0325f /net
parent8af345f58ac9b350bb23c1457c613381d9f00472 (diff)
svcrpc: support multiple-fragment rpc's
Over TCP, RPC's are preceded by a single 4-byte field telling you how long the rpc is (in bytes). The spec also allows you to send an RPC in multiple such records (the high bit of the length field is used to tell you whether this is the final record). We've survived for years without supporting this because in practice the clients we care about don't use it. But the userland rpc libraries do, and every now and then an experimental client will run into this. (Most recently I noticed it while trying to write a pynfs check.) And we're really on the wrong side of the spec here--let's fix this. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/svcsock.c50
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
1024static 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
1121error: 1121error: