aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/xprtsock.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/xprtsock.c')
-rw-r--r--net/sunrpc/xprtsock.c140
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
171static inline int xs_send_head(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, unsigned int len) 171static 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
191static int xs_send_tail(struct socket *sock, struct xdr_buf *xdr, unsigned int base, unsigned int len) 188static 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 */
213static inline int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base) 228static 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;
272copy_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 }
281out: 267out:
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/**