diff options
author | David Howells <dhowells@redhat.com> | 2017-03-16 12:27:46 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2017-03-16 12:27:46 -0400 |
commit | 2f5705a5c805e7f761f2228820656bb9363a3d8c (patch) | |
tree | 5515c858d10018e6e566a3e62d947c1d14d49d01 | |
parent | 6a0e3999e5cb3daa0468073fcdee0767422a4056 (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.c | 97 |
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 | */ | ||
267 | static 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 | */ |
265 | static int afs_send_pages(struct afs_call *call, struct msghdr *msg) | 298 | static 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 | ||