aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2017-03-16 12:27:46 -0400
committerDavid Howells <dhowells@redhat.com>2017-03-16 12:27:46 -0400
commit2f5705a5c805e7f761f2228820656bb9363a3d8c (patch)
tree5515c858d10018e6e566a3e62d947c1d14d49d01
parent6a0e3999e5cb3daa0468073fcdee0767422a4056 (diff)
afs: Use a bvec rather than a kvec in afs_send_pages()
Use a bvec rather than a kvec in afs_send_pages() as we don't then have to call kmap() in advance. This allows us to pass the array of contiguous pages that we extracted through to rxrpc in one go rather than passing a single page at a time. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--fs/afs/rxrpc.c97
1 files changed, 52 insertions, 45 deletions
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 419ef05dcb5e..bf45307ff201 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -259,67 +259,74 @@ void afs_flat_call_destructor(struct afs_call *call)
259 call->buffer = NULL; 259 call->buffer = NULL;
260} 260}
261 261
262#define AFS_BVEC_MAX 8
263
264/*
265 * Load the given bvec with the next few pages.
266 */
267static void afs_load_bvec(struct afs_call *call, struct msghdr *msg,
268 struct bio_vec *bv, pgoff_t first, pgoff_t last,
269 unsigned offset)
270{
271 struct page *pages[AFS_BVEC_MAX];
272 unsigned int nr, n, i, to, bytes = 0;
273
274 nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX);
275 n = find_get_pages_contig(call->mapping, first, nr, pages);
276 ASSERTCMP(n, ==, nr);
277
278 msg->msg_flags |= MSG_MORE;
279 for (i = 0; i < nr; i++) {
280 to = PAGE_SIZE;
281 if (first + i >= last) {
282 to = call->last_to;
283 msg->msg_flags &= ~MSG_MORE;
284 }
285 bv[i].bv_page = pages[i];
286 bv[i].bv_len = to - offset;
287 bv[i].bv_offset = offset;
288 bytes += to - offset;
289 offset = 0;
290 }
291
292 iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC, bv, nr, bytes);
293}
294
262/* 295/*
263 * attach the data from a bunch of pages on an inode to a call 296 * attach the data from a bunch of pages on an inode to a call
264 */ 297 */
265static int afs_send_pages(struct afs_call *call, struct msghdr *msg) 298static int afs_send_pages(struct afs_call *call, struct msghdr *msg)
266{ 299{
267 struct page *pages[8]; 300 struct bio_vec bv[AFS_BVEC_MAX];
268 unsigned count, n, loop, offset, to; 301 unsigned int bytes, nr, loop, offset;
269 pgoff_t first = call->first, last = call->last; 302 pgoff_t first = call->first, last = call->last;
270 int ret; 303 int ret;
271 304
272 _enter("");
273
274 offset = call->first_offset; 305 offset = call->first_offset;
275 call->first_offset = 0; 306 call->first_offset = 0;
276 307
277 do { 308 do {
278 _debug("attach %lx-%lx", first, last); 309 afs_load_bvec(call, msg, bv, first, last, offset);
279 310 offset = 0;
280 count = last - first + 1; 311 bytes = msg->msg_iter.count;
281 if (count > ARRAY_SIZE(pages)) 312 nr = msg->msg_iter.nr_segs;
282 count = ARRAY_SIZE(pages); 313
283 n = find_get_pages_contig(call->mapping, first, count, pages); 314 /* Have to change the state *before* sending the last
284 ASSERTCMP(n, ==, count); 315 * packet as RxRPC might give us the reply before it
285 316 * returns from sending the request.
286 loop = 0; 317 */
287 do { 318 if (first + nr >= last)
288 struct bio_vec bvec = {.bv_page = pages[loop], 319 call->state = AFS_CALL_AWAIT_REPLY;
289 .bv_offset = offset}; 320 ret = rxrpc_kernel_send_data(afs_socket, call->rxcall,
290 msg->msg_flags = 0; 321 msg, bytes);
291 to = PAGE_SIZE; 322 for (loop = 0; loop < nr; loop++)
292 if (first + loop >= last) 323 put_page(bv[loop].bv_page);
293 to = call->last_to;
294 else
295 msg->msg_flags = MSG_MORE;
296 bvec.bv_len = to - offset;
297 offset = 0;
298
299 _debug("- range %u-%u%s",
300 offset, to, msg->msg_flags ? " [more]" : "");
301 iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC,
302 &bvec, 1, to - offset);
303
304 /* have to change the state *before* sending the last
305 * packet as RxRPC might give us the reply before it
306 * returns from sending the request */
307 if (first + loop >= last)
308 call->state = AFS_CALL_AWAIT_REPLY;
309 ret = rxrpc_kernel_send_data(afs_socket, call->rxcall,
310 msg, to - offset);
311 if (ret < 0)
312 break;
313 } while (++loop < count);
314 first += count;
315
316 for (loop = 0; loop < count; loop++)
317 put_page(pages[loop]);
318 if (ret < 0) 324 if (ret < 0)
319 break; 325 break;
326
327 first += nr;
320 } while (first <= last); 328 } while (first <= last);
321 329
322 _leave(" = %d", ret);
323 return ret; 330 return ret;
324} 331}
325 332