diff options
-rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index a345cadad4dd..f9f13a32ddb8 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | |||
@@ -364,6 +364,56 @@ rdma_rcl_chunk_count(struct rpcrdma_read_chunk *ch) | |||
364 | return count; | 364 | return count; |
365 | } | 365 | } |
366 | 366 | ||
367 | /* If there was additional inline content, append it to the end of arg.pages. | ||
368 | * Tail copy has to be done after the reader function has determined how many | ||
369 | * pages are needed for RDMA READ. | ||
370 | */ | ||
371 | static int | ||
372 | rdma_copy_tail(struct svc_rqst *rqstp, struct svc_rdma_op_ctxt *head, | ||
373 | u32 position, u32 byte_count, u32 page_offset, int page_no) | ||
374 | { | ||
375 | char *srcp, *destp; | ||
376 | int ret; | ||
377 | |||
378 | ret = 0; | ||
379 | srcp = head->arg.head[0].iov_base + position; | ||
380 | byte_count = head->arg.head[0].iov_len - position; | ||
381 | if (byte_count > PAGE_SIZE) { | ||
382 | dprintk("svcrdma: large tail unsupported\n"); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | /* Fit as much of the tail on the current page as possible */ | ||
387 | if (page_offset != PAGE_SIZE) { | ||
388 | destp = page_address(rqstp->rq_arg.pages[page_no]); | ||
389 | destp += page_offset; | ||
390 | while (byte_count--) { | ||
391 | *destp++ = *srcp++; | ||
392 | page_offset++; | ||
393 | if (page_offset == PAGE_SIZE && byte_count) | ||
394 | goto more; | ||
395 | } | ||
396 | goto done; | ||
397 | } | ||
398 | |||
399 | more: | ||
400 | /* Fit the rest on the next page */ | ||
401 | page_no++; | ||
402 | destp = page_address(rqstp->rq_arg.pages[page_no]); | ||
403 | while (byte_count--) | ||
404 | *destp++ = *srcp++; | ||
405 | |||
406 | rqstp->rq_respages = &rqstp->rq_arg.pages[page_no+1]; | ||
407 | rqstp->rq_next_page = rqstp->rq_respages + 1; | ||
408 | |||
409 | done: | ||
410 | byte_count = head->arg.head[0].iov_len - position; | ||
411 | head->arg.page_len += byte_count; | ||
412 | head->arg.len += byte_count; | ||
413 | head->arg.buflen += byte_count; | ||
414 | return 1; | ||
415 | } | ||
416 | |||
367 | static int rdma_read_chunks(struct svcxprt_rdma *xprt, | 417 | static int rdma_read_chunks(struct svcxprt_rdma *xprt, |
368 | struct rpcrdma_msg *rmsgp, | 418 | struct rpcrdma_msg *rmsgp, |
369 | struct svc_rqst *rqstp, | 419 | struct svc_rqst *rqstp, |
@@ -440,9 +490,14 @@ static int rdma_read_chunks(struct svcxprt_rdma *xprt, | |||
440 | head->arg.page_len += pad; | 490 | head->arg.page_len += pad; |
441 | head->arg.len += pad; | 491 | head->arg.len += pad; |
442 | head->arg.buflen += pad; | 492 | head->arg.buflen += pad; |
493 | page_offset += pad; | ||
443 | } | 494 | } |
444 | 495 | ||
445 | ret = 1; | 496 | ret = 1; |
497 | if (position && position < head->arg.head[0].iov_len) | ||
498 | ret = rdma_copy_tail(rqstp, head, position, | ||
499 | byte_count, page_offset, page_no); | ||
500 | head->arg.head[0].iov_len = position; | ||
446 | head->position = position; | 501 | head->position = position; |
447 | 502 | ||
448 | err: | 503 | err: |