diff options
Diffstat (limited to 'net/sunrpc/xprtsock.c')
-rw-r--r-- | net/sunrpc/xprtsock.c | 140 |
1 files changed, 65 insertions, 75 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 757fc91ef25d..25620851d4bf 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -168,37 +168,52 @@ static void xs_free_peer_addresses(struct rpc_xprt *xprt) | |||
168 | 168 | ||
169 | #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) | 169 | #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) |
170 | 170 | ||
171 | static inline int xs_send_head(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, unsigned int len) | 171 | static int xs_send_kvec(struct socket *sock, struct sockaddr *addr, int addrlen, struct kvec *vec, unsigned int base, int more) |
172 | { | 172 | { |
173 | struct kvec iov = { | ||
174 | .iov_base = xdr->head[0].iov_base + base, | ||
175 | .iov_len = len - base, | ||
176 | }; | ||
177 | struct msghdr msg = { | 173 | struct msghdr msg = { |
178 | .msg_name = addr, | 174 | .msg_name = addr, |
179 | .msg_namelen = addrlen, | 175 | .msg_namelen = addrlen, |
180 | .msg_flags = XS_SENDMSG_FLAGS, | 176 | .msg_flags = XS_SENDMSG_FLAGS | (more ? MSG_MORE : 0), |
177 | }; | ||
178 | struct kvec iov = { | ||
179 | .iov_base = vec->iov_base + base, | ||
180 | .iov_len = vec->iov_len - base, | ||
181 | }; | 181 | }; |
182 | 182 | ||
183 | if (xdr->len > len) | 183 | if (iov.iov_len != 0) |
184 | msg.msg_flags |= MSG_MORE; | ||
185 | |||
186 | if (likely(iov.iov_len)) | ||
187 | return kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); | 184 | return kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); |
188 | return kernel_sendmsg(sock, &msg, NULL, 0, 0); | 185 | return kernel_sendmsg(sock, &msg, NULL, 0, 0); |
189 | } | 186 | } |
190 | 187 | ||
191 | static int xs_send_tail(struct socket *sock, struct xdr_buf *xdr, unsigned int base, unsigned int len) | 188 | static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned int base, int more) |
192 | { | 189 | { |
193 | struct kvec iov = { | 190 | struct page **ppage; |
194 | .iov_base = xdr->tail[0].iov_base + base, | 191 | unsigned int remainder; |
195 | .iov_len = len - base, | 192 | int err, sent = 0; |
196 | }; | 193 | |
197 | struct msghdr msg = { | 194 | remainder = xdr->page_len - base; |
198 | .msg_flags = XS_SENDMSG_FLAGS, | 195 | base += xdr->page_base; |
199 | }; | 196 | ppage = xdr->pages + (base >> PAGE_SHIFT); |
197 | base &= ~PAGE_MASK; | ||
198 | for(;;) { | ||
199 | unsigned int len = min_t(unsigned int, PAGE_SIZE - base, remainder); | ||
200 | int flags = XS_SENDMSG_FLAGS; | ||
200 | 201 | ||
201 | return kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); | 202 | remainder -= len; |
203 | if (remainder != 0 || more) | ||
204 | flags |= MSG_MORE; | ||
205 | err = sock->ops->sendpage(sock, *ppage, base, len, flags); | ||
206 | if (remainder == 0 || err != len) | ||
207 | break; | ||
208 | sent += err; | ||
209 | ppage++; | ||
210 | base = 0; | ||
211 | } | ||
212 | if (sent == 0) | ||
213 | return err; | ||
214 | if (err > 0) | ||
215 | sent += err; | ||
216 | return sent; | ||
202 | } | 217 | } |
203 | 218 | ||
204 | /** | 219 | /** |
@@ -210,76 +225,51 @@ static int xs_send_tail(struct socket *sock, struct xdr_buf *xdr, unsigned int b | |||
210 | * @base: starting position in the buffer | 225 | * @base: starting position in the buffer |
211 | * | 226 | * |
212 | */ | 227 | */ |
213 | static inline int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base) | 228 | static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base) |
214 | { | 229 | { |
215 | struct page **ppage = xdr->pages; | 230 | unsigned int remainder = xdr->len - base; |
216 | unsigned int len, pglen = xdr->page_len; | 231 | int err, sent = 0; |
217 | int err, ret = 0; | ||
218 | 232 | ||
219 | if (unlikely(!sock)) | 233 | if (unlikely(!sock)) |
220 | return -ENOTCONN; | 234 | return -ENOTCONN; |
221 | 235 | ||
222 | clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); | 236 | clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); |
237 | if (base != 0) { | ||
238 | addr = NULL; | ||
239 | addrlen = 0; | ||
240 | } | ||
223 | 241 | ||
224 | len = xdr->head[0].iov_len; | 242 | if (base < xdr->head[0].iov_len || addr != NULL) { |
225 | if (base < len || (addr != NULL && base == 0)) { | 243 | unsigned int len = xdr->head[0].iov_len - base; |
226 | err = xs_send_head(sock, addr, addrlen, xdr, base, len); | 244 | remainder -= len; |
227 | if (ret == 0) | 245 | err = xs_send_kvec(sock, addr, addrlen, &xdr->head[0], base, remainder != 0); |
228 | ret = err; | 246 | if (remainder == 0 || err != len) |
229 | else if (err > 0) | ||
230 | ret += err; | ||
231 | if (err != (len - base)) | ||
232 | goto out; | 247 | goto out; |
248 | sent += err; | ||
233 | base = 0; | 249 | base = 0; |
234 | } else | 250 | } else |
235 | base -= len; | 251 | base -= xdr->head[0].iov_len; |
236 | |||
237 | if (unlikely(pglen == 0)) | ||
238 | goto copy_tail; | ||
239 | if (unlikely(base >= pglen)) { | ||
240 | base -= pglen; | ||
241 | goto copy_tail; | ||
242 | } | ||
243 | if (base || xdr->page_base) { | ||
244 | pglen -= base; | ||
245 | base += xdr->page_base; | ||
246 | ppage += base >> PAGE_CACHE_SHIFT; | ||
247 | base &= ~PAGE_CACHE_MASK; | ||
248 | } | ||
249 | |||
250 | do { | ||
251 | int flags = XS_SENDMSG_FLAGS; | ||
252 | 252 | ||
253 | len = PAGE_CACHE_SIZE; | 253 | if (base < xdr->page_len) { |
254 | if (base) | 254 | unsigned int len = xdr->page_len - base; |
255 | len -= base; | 255 | remainder -= len; |
256 | if (pglen < len) | 256 | err = xs_send_pagedata(sock, xdr, base, remainder != 0); |
257 | len = pglen; | 257 | if (remainder == 0 || err != len) |
258 | |||
259 | if (pglen != len || xdr->tail[0].iov_len != 0) | ||
260 | flags |= MSG_MORE; | ||
261 | |||
262 | err = kernel_sendpage(sock, *ppage, base, len, flags); | ||
263 | if (ret == 0) | ||
264 | ret = err; | ||
265 | else if (err > 0) | ||
266 | ret += err; | ||
267 | if (err != len) | ||
268 | goto out; | 258 | goto out; |
259 | sent += err; | ||
269 | base = 0; | 260 | base = 0; |
270 | ppage++; | 261 | } else |
271 | } while ((pglen -= len) != 0); | 262 | base -= xdr->page_len; |
272 | copy_tail: | 263 | |
273 | len = xdr->tail[0].iov_len; | 264 | if (base >= xdr->tail[0].iov_len) |
274 | if (base < len) { | 265 | return sent; |
275 | err = xs_send_tail(sock, xdr, base, len); | 266 | err = xs_send_kvec(sock, NULL, 0, &xdr->tail[0], base, 0); |
276 | if (ret == 0) | ||
277 | ret = err; | ||
278 | else if (err > 0) | ||
279 | ret += err; | ||
280 | } | ||
281 | out: | 267 | out: |
282 | return ret; | 268 | if (sent == 0) |
269 | return err; | ||
270 | if (err > 0) | ||
271 | sent += err; | ||
272 | return sent; | ||
283 | } | 273 | } |
284 | 274 | ||
285 | /** | 275 | /** |