diff options
Diffstat (limited to 'fs/afs/rxrpc.c')
-rw-r--r-- | fs/afs/rxrpc.c | 80 |
1 files changed, 76 insertions, 4 deletions
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 222c1a3abbb8..04189c47d6a0 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c | |||
@@ -237,6 +237,70 @@ void afs_flat_call_destructor(struct afs_call *call) | |||
237 | } | 237 | } |
238 | 238 | ||
239 | /* | 239 | /* |
240 | * attach the data from a bunch of pages on an inode to a call | ||
241 | */ | ||
242 | int afs_send_pages(struct afs_call *call, struct msghdr *msg, struct kvec *iov) | ||
243 | { | ||
244 | struct page *pages[8]; | ||
245 | unsigned count, n, loop, offset, to; | ||
246 | pgoff_t first = call->first, last = call->last; | ||
247 | int ret; | ||
248 | |||
249 | _enter(""); | ||
250 | |||
251 | offset = call->first_offset; | ||
252 | call->first_offset = 0; | ||
253 | |||
254 | do { | ||
255 | _debug("attach %lx-%lx", first, last); | ||
256 | |||
257 | count = last - first + 1; | ||
258 | if (count > ARRAY_SIZE(pages)) | ||
259 | count = ARRAY_SIZE(pages); | ||
260 | n = find_get_pages_contig(call->mapping, first, count, pages); | ||
261 | ASSERTCMP(n, ==, count); | ||
262 | |||
263 | loop = 0; | ||
264 | do { | ||
265 | msg->msg_flags = 0; | ||
266 | to = PAGE_SIZE; | ||
267 | if (first + loop >= last) | ||
268 | to = call->last_to; | ||
269 | else | ||
270 | msg->msg_flags = MSG_MORE; | ||
271 | iov->iov_base = kmap(pages[loop]) + offset; | ||
272 | iov->iov_len = to - offset; | ||
273 | offset = 0; | ||
274 | |||
275 | _debug("- range %u-%u%s", | ||
276 | offset, to, msg->msg_flags ? " [more]" : ""); | ||
277 | msg->msg_iov = (struct iovec *) iov; | ||
278 | msg->msg_iovlen = 1; | ||
279 | |||
280 | /* have to change the state *before* sending the last | ||
281 | * packet as RxRPC might give us the reply before it | ||
282 | * returns from sending the request */ | ||
283 | if (first + loop >= last) | ||
284 | call->state = AFS_CALL_AWAIT_REPLY; | ||
285 | ret = rxrpc_kernel_send_data(call->rxcall, msg, | ||
286 | to - offset); | ||
287 | kunmap(pages[loop]); | ||
288 | if (ret < 0) | ||
289 | break; | ||
290 | } while (++loop < count); | ||
291 | first += count; | ||
292 | |||
293 | for (loop = 0; loop < count; loop++) | ||
294 | put_page(pages[loop]); | ||
295 | if (ret < 0) | ||
296 | break; | ||
297 | } while (first < last); | ||
298 | |||
299 | _leave(" = %d", ret); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | /* | ||
240 | * initiate a call | 304 | * initiate a call |
241 | */ | 305 | */ |
242 | int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | 306 | int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, |
@@ -253,8 +317,9 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
253 | ASSERT(call->type != NULL); | 317 | ASSERT(call->type != NULL); |
254 | ASSERT(call->type->name != NULL); | 318 | ASSERT(call->type->name != NULL); |
255 | 319 | ||
256 | _debug("MAKE %p{%s} [%d]", | 320 | _debug("____MAKE %p{%s,%x} [%d]____", |
257 | call, call->type->name, atomic_read(&afs_outstanding_calls)); | 321 | call, call->type->name, key_serial(call->key), |
322 | atomic_read(&afs_outstanding_calls)); | ||
258 | 323 | ||
259 | call->wait_mode = wait_mode; | 324 | call->wait_mode = wait_mode; |
260 | INIT_WORK(&call->async_work, afs_process_async_call); | 325 | INIT_WORK(&call->async_work, afs_process_async_call); |
@@ -289,16 +354,23 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
289 | msg.msg_iovlen = 1; | 354 | msg.msg_iovlen = 1; |
290 | msg.msg_control = NULL; | 355 | msg.msg_control = NULL; |
291 | msg.msg_controllen = 0; | 356 | msg.msg_controllen = 0; |
292 | msg.msg_flags = 0; | 357 | msg.msg_flags = (call->send_pages ? MSG_MORE : 0); |
293 | 358 | ||
294 | /* have to change the state *before* sending the last packet as RxRPC | 359 | /* have to change the state *before* sending the last packet as RxRPC |
295 | * might give us the reply before it returns from sending the | 360 | * might give us the reply before it returns from sending the |
296 | * request */ | 361 | * request */ |
297 | call->state = AFS_CALL_AWAIT_REPLY; | 362 | if (!call->send_pages) |
363 | call->state = AFS_CALL_AWAIT_REPLY; | ||
298 | ret = rxrpc_kernel_send_data(rxcall, &msg, call->request_size); | 364 | ret = rxrpc_kernel_send_data(rxcall, &msg, call->request_size); |
299 | if (ret < 0) | 365 | if (ret < 0) |
300 | goto error_do_abort; | 366 | goto error_do_abort; |
301 | 367 | ||
368 | if (call->send_pages) { | ||
369 | ret = afs_send_pages(call, &msg, iov); | ||
370 | if (ret < 0) | ||
371 | goto error_do_abort; | ||
372 | } | ||
373 | |||
302 | /* at this point, an async call may no longer exist as it may have | 374 | /* at this point, an async call may no longer exist as it may have |
303 | * already completed */ | 375 | * already completed */ |
304 | return wait_mode->wait(call); | 376 | return wait_mode->wait(call); |