diff options
Diffstat (limited to 'net/sunrpc/svcsock.c')
-rw-r--r-- | net/sunrpc/svcsock.c | 172 |
1 files changed, 137 insertions, 35 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 76a380d37de4..ccc5e83cae5d 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/sunrpc/msg_prot.h> | 49 | #include <linux/sunrpc/msg_prot.h> |
50 | #include <linux/sunrpc/svcsock.h> | 50 | #include <linux/sunrpc/svcsock.h> |
51 | #include <linux/sunrpc/stats.h> | 51 | #include <linux/sunrpc/stats.h> |
52 | #include <linux/sunrpc/xprt.h> | ||
52 | 53 | ||
53 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT | 54 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT |
54 | 55 | ||
@@ -153,49 +154,27 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) | |||
153 | } | 154 | } |
154 | 155 | ||
155 | /* | 156 | /* |
156 | * Generic sendto routine | 157 | * send routine intended to be shared by the fore- and back-channel |
157 | */ | 158 | */ |
158 | static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) | 159 | int svc_send_common(struct socket *sock, struct xdr_buf *xdr, |
160 | struct page *headpage, unsigned long headoffset, | ||
161 | struct page *tailpage, unsigned long tailoffset) | ||
159 | { | 162 | { |
160 | struct svc_sock *svsk = | ||
161 | container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); | ||
162 | struct socket *sock = svsk->sk_sock; | ||
163 | int slen; | ||
164 | union { | ||
165 | struct cmsghdr hdr; | ||
166 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; | ||
167 | } buffer; | ||
168 | struct cmsghdr *cmh = &buffer.hdr; | ||
169 | int len = 0; | ||
170 | int result; | 163 | int result; |
171 | int size; | 164 | int size; |
172 | struct page **ppage = xdr->pages; | 165 | struct page **ppage = xdr->pages; |
173 | size_t base = xdr->page_base; | 166 | size_t base = xdr->page_base; |
174 | unsigned int pglen = xdr->page_len; | 167 | unsigned int pglen = xdr->page_len; |
175 | unsigned int flags = MSG_MORE; | 168 | unsigned int flags = MSG_MORE; |
176 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | 169 | int slen; |
170 | int len = 0; | ||
177 | 171 | ||
178 | slen = xdr->len; | 172 | slen = xdr->len; |
179 | 173 | ||
180 | if (rqstp->rq_prot == IPPROTO_UDP) { | ||
181 | struct msghdr msg = { | ||
182 | .msg_name = &rqstp->rq_addr, | ||
183 | .msg_namelen = rqstp->rq_addrlen, | ||
184 | .msg_control = cmh, | ||
185 | .msg_controllen = sizeof(buffer), | ||
186 | .msg_flags = MSG_MORE, | ||
187 | }; | ||
188 | |||
189 | svc_set_cmsg_data(rqstp, cmh); | ||
190 | |||
191 | if (sock_sendmsg(sock, &msg, 0) < 0) | ||
192 | goto out; | ||
193 | } | ||
194 | |||
195 | /* send head */ | 174 | /* send head */ |
196 | if (slen == xdr->head[0].iov_len) | 175 | if (slen == xdr->head[0].iov_len) |
197 | flags = 0; | 176 | flags = 0; |
198 | len = kernel_sendpage(sock, rqstp->rq_respages[0], 0, | 177 | len = kernel_sendpage(sock, headpage, headoffset, |
199 | xdr->head[0].iov_len, flags); | 178 | xdr->head[0].iov_len, flags); |
200 | if (len != xdr->head[0].iov_len) | 179 | if (len != xdr->head[0].iov_len) |
201 | goto out; | 180 | goto out; |
@@ -219,16 +198,58 @@ static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) | |||
219 | base = 0; | 198 | base = 0; |
220 | ppage++; | 199 | ppage++; |
221 | } | 200 | } |
201 | |||
222 | /* send tail */ | 202 | /* send tail */ |
223 | if (xdr->tail[0].iov_len) { | 203 | if (xdr->tail[0].iov_len) { |
224 | result = kernel_sendpage(sock, rqstp->rq_respages[0], | 204 | result = kernel_sendpage(sock, tailpage, tailoffset, |
225 | ((unsigned long)xdr->tail[0].iov_base) | 205 | xdr->tail[0].iov_len, 0); |
226 | & (PAGE_SIZE-1), | ||
227 | xdr->tail[0].iov_len, 0); | ||
228 | |||
229 | if (result > 0) | 206 | if (result > 0) |
230 | len += result; | 207 | len += result; |
231 | } | 208 | } |
209 | |||
210 | out: | ||
211 | return len; | ||
212 | } | ||
213 | |||
214 | |||
215 | /* | ||
216 | * Generic sendto routine | ||
217 | */ | ||
218 | static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) | ||
219 | { | ||
220 | struct svc_sock *svsk = | ||
221 | container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); | ||
222 | struct socket *sock = svsk->sk_sock; | ||
223 | union { | ||
224 | struct cmsghdr hdr; | ||
225 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; | ||
226 | } buffer; | ||
227 | struct cmsghdr *cmh = &buffer.hdr; | ||
228 | int len = 0; | ||
229 | unsigned long tailoff; | ||
230 | unsigned long headoff; | ||
231 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | ||
232 | |||
233 | if (rqstp->rq_prot == IPPROTO_UDP) { | ||
234 | struct msghdr msg = { | ||
235 | .msg_name = &rqstp->rq_addr, | ||
236 | .msg_namelen = rqstp->rq_addrlen, | ||
237 | .msg_control = cmh, | ||
238 | .msg_controllen = sizeof(buffer), | ||
239 | .msg_flags = MSG_MORE, | ||
240 | }; | ||
241 | |||
242 | svc_set_cmsg_data(rqstp, cmh); | ||
243 | |||
244 | if (sock_sendmsg(sock, &msg, 0) < 0) | ||
245 | goto out; | ||
246 | } | ||
247 | |||
248 | tailoff = ((unsigned long)xdr->tail[0].iov_base) & (PAGE_SIZE-1); | ||
249 | headoff = 0; | ||
250 | len = svc_send_common(sock, xdr, rqstp->rq_respages[0], headoff, | ||
251 | rqstp->rq_respages[0], tailoff); | ||
252 | |||
232 | out: | 253 | out: |
233 | dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %s)\n", | 254 | dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %s)\n", |
234 | svsk, xdr->head[0].iov_base, xdr->head[0].iov_len, | 255 | svsk, xdr->head[0].iov_base, xdr->head[0].iov_len, |
@@ -951,6 +972,57 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
951 | return -EAGAIN; | 972 | return -EAGAIN; |
952 | } | 973 | } |
953 | 974 | ||
975 | static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp, | ||
976 | struct rpc_rqst **reqpp, struct kvec *vec) | ||
977 | { | ||
978 | struct rpc_rqst *req = NULL; | ||
979 | u32 *p; | ||
980 | u32 xid; | ||
981 | u32 calldir; | ||
982 | int len; | ||
983 | |||
984 | len = svc_recvfrom(rqstp, vec, 1, 8); | ||
985 | if (len < 0) | ||
986 | goto error; | ||
987 | |||
988 | p = (u32 *)rqstp->rq_arg.head[0].iov_base; | ||
989 | xid = *p++; | ||
990 | calldir = *p; | ||
991 | |||
992 | if (calldir == 0) { | ||
993 | /* REQUEST is the most common case */ | ||
994 | vec[0] = rqstp->rq_arg.head[0]; | ||
995 | } else { | ||
996 | /* REPLY */ | ||
997 | if (svsk->sk_bc_xprt) | ||
998 | req = xprt_lookup_rqst(svsk->sk_bc_xprt, xid); | ||
999 | |||
1000 | if (!req) { | ||
1001 | printk(KERN_NOTICE | ||
1002 | "%s: Got unrecognized reply: " | ||
1003 | "calldir 0x%x sk_bc_xprt %p xid %08x\n", | ||
1004 | __func__, ntohl(calldir), | ||
1005 | svsk->sk_bc_xprt, xid); | ||
1006 | vec[0] = rqstp->rq_arg.head[0]; | ||
1007 | goto out; | ||
1008 | } | ||
1009 | |||
1010 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, | ||
1011 | sizeof(struct xdr_buf)); | ||
1012 | /* copy the xid and call direction */ | ||
1013 | memcpy(req->rq_private_buf.head[0].iov_base, | ||
1014 | rqstp->rq_arg.head[0].iov_base, 8); | ||
1015 | vec[0] = req->rq_private_buf.head[0]; | ||
1016 | } | ||
1017 | out: | ||
1018 | vec[0].iov_base += 8; | ||
1019 | vec[0].iov_len -= 8; | ||
1020 | len = svsk->sk_reclen - 8; | ||
1021 | error: | ||
1022 | *reqpp = req; | ||
1023 | return len; | ||
1024 | } | ||
1025 | |||
954 | /* | 1026 | /* |
955 | * Receive data from a TCP socket. | 1027 | * Receive data from a TCP socket. |
956 | */ | 1028 | */ |
@@ -962,6 +1034,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
962 | int len; | 1034 | int len; |
963 | struct kvec *vec; | 1035 | struct kvec *vec; |
964 | int pnum, vlen; | 1036 | int pnum, vlen; |
1037 | struct rpc_rqst *req = NULL; | ||
965 | 1038 | ||
966 | dprintk("svc: tcp_recv %p data %d conn %d close %d\n", | 1039 | dprintk("svc: tcp_recv %p data %d conn %d close %d\n", |
967 | svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags), | 1040 | svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags), |
@@ -975,9 +1048,27 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
975 | vec = rqstp->rq_vec; | 1048 | vec = rqstp->rq_vec; |
976 | vec[0] = rqstp->rq_arg.head[0]; | 1049 | vec[0] = rqstp->rq_arg.head[0]; |
977 | vlen = PAGE_SIZE; | 1050 | vlen = PAGE_SIZE; |
1051 | |||
1052 | /* | ||
1053 | * We have enough data for the whole tcp record. Let's try and read the | ||
1054 | * first 8 bytes to get the xid and the call direction. We can use this | ||
1055 | * to figure out if this is a call or a reply to a callback. If | ||
1056 | * sk_reclen is < 8 (xid and calldir), then this is a malformed packet. | ||
1057 | * In that case, don't bother with the calldir and just read the data. | ||
1058 | * It will be rejected in svc_process. | ||
1059 | */ | ||
1060 | if (len >= 8) { | ||
1061 | len = svc_process_calldir(svsk, rqstp, &req, vec); | ||
1062 | if (len < 0) | ||
1063 | goto err_again; | ||
1064 | vlen -= 8; | ||
1065 | } | ||
1066 | |||
978 | pnum = 1; | 1067 | pnum = 1; |
979 | while (vlen < len) { | 1068 | while (vlen < len) { |
980 | vec[pnum].iov_base = page_address(rqstp->rq_pages[pnum]); | 1069 | vec[pnum].iov_base = (req) ? |
1070 | page_address(req->rq_private_buf.pages[pnum - 1]) : | ||
1071 | page_address(rqstp->rq_pages[pnum]); | ||
981 | vec[pnum].iov_len = PAGE_SIZE; | 1072 | vec[pnum].iov_len = PAGE_SIZE; |
982 | pnum++; | 1073 | pnum++; |
983 | vlen += PAGE_SIZE; | 1074 | vlen += PAGE_SIZE; |
@@ -989,6 +1080,16 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
989 | if (len < 0) | 1080 | if (len < 0) |
990 | goto err_again; | 1081 | goto err_again; |
991 | 1082 | ||
1083 | /* | ||
1084 | * Account for the 8 bytes we read earlier | ||
1085 | */ | ||
1086 | len += 8; | ||
1087 | |||
1088 | if (req) { | ||
1089 | xprt_complete_rqst(req->rq_task, len); | ||
1090 | len = 0; | ||
1091 | goto out; | ||
1092 | } | ||
992 | dprintk("svc: TCP complete record (%d bytes)\n", len); | 1093 | dprintk("svc: TCP complete record (%d bytes)\n", len); |
993 | rqstp->rq_arg.len = len; | 1094 | rqstp->rq_arg.len = len; |
994 | rqstp->rq_arg.page_base = 0; | 1095 | rqstp->rq_arg.page_base = 0; |
@@ -1002,6 +1103,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1002 | rqstp->rq_xprt_ctxt = NULL; | 1103 | rqstp->rq_xprt_ctxt = NULL; |
1003 | rqstp->rq_prot = IPPROTO_TCP; | 1104 | rqstp->rq_prot = IPPROTO_TCP; |
1004 | 1105 | ||
1106 | out: | ||
1005 | /* Reset TCP read info */ | 1107 | /* Reset TCP read info */ |
1006 | svsk->sk_reclen = 0; | 1108 | svsk->sk_reclen = 0; |
1007 | svsk->sk_tcplen = 0; | 1109 | svsk->sk_tcplen = 0; |