diff options
author | Tom Talpey <tmtalpey@gmail.com> | 2009-03-11 14:37:55 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-03-11 14:37:55 -0400 |
commit | b38ab40ad58c1fc43ea590d6342f6a6763ac8fb6 (patch) | |
tree | f2e701eff6bed88f1085a95a9a240db105776831 /net/sunrpc | |
parent | b1e1e158779f1d99c2cc18e466f6bf9099fc0853 (diff) |
XPRTRDMA: correct an rpc/rdma inline send marshaling error
Certain client rpc's which contain both lengthy page-contained
metadata and a non-empty xdr_tail buffer require careful handling
to avoid overlapped memory copying. Rearranging of existing rpcrdma
marshaling code avoids it; this fixes an NFSv4 symlink creation error
detected with connectathon basic/test8 to multiple servers.
Signed-off-by: Tom Talpey <tmtalpey@gmail.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/xprtrdma/rpc_rdma.c | 26 |
1 files changed, 14 insertions, 12 deletions
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 14106d26bb95..e5e28d1946a4 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c | |||
@@ -310,6 +310,19 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) | |||
310 | __func__, pad, destp, rqst->rq_slen, curlen); | 310 | __func__, pad, destp, rqst->rq_slen, curlen); |
311 | 311 | ||
312 | copy_len = rqst->rq_snd_buf.page_len; | 312 | copy_len = rqst->rq_snd_buf.page_len; |
313 | |||
314 | if (rqst->rq_snd_buf.tail[0].iov_len) { | ||
315 | curlen = rqst->rq_snd_buf.tail[0].iov_len; | ||
316 | if (destp + copy_len != rqst->rq_snd_buf.tail[0].iov_base) { | ||
317 | memmove(destp + copy_len, | ||
318 | rqst->rq_snd_buf.tail[0].iov_base, curlen); | ||
319 | r_xprt->rx_stats.pullup_copy_count += curlen; | ||
320 | } | ||
321 | dprintk("RPC: %s: tail destp 0x%p len %d\n", | ||
322 | __func__, destp + copy_len, curlen); | ||
323 | rqst->rq_svec[0].iov_len += curlen; | ||
324 | } | ||
325 | |||
313 | r_xprt->rx_stats.pullup_copy_count += copy_len; | 326 | r_xprt->rx_stats.pullup_copy_count += copy_len; |
314 | npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT; | 327 | npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT; |
315 | for (i = 0; copy_len && i < npages; i++) { | 328 | for (i = 0; copy_len && i < npages; i++) { |
@@ -332,17 +345,6 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) | |||
332 | destp += curlen; | 345 | destp += curlen; |
333 | copy_len -= curlen; | 346 | copy_len -= curlen; |
334 | } | 347 | } |
335 | if (rqst->rq_snd_buf.tail[0].iov_len) { | ||
336 | curlen = rqst->rq_snd_buf.tail[0].iov_len; | ||
337 | if (destp != rqst->rq_snd_buf.tail[0].iov_base) { | ||
338 | memcpy(destp, | ||
339 | rqst->rq_snd_buf.tail[0].iov_base, curlen); | ||
340 | r_xprt->rx_stats.pullup_copy_count += curlen; | ||
341 | } | ||
342 | dprintk("RPC: %s: tail destp 0x%p len %d curlen %d\n", | ||
343 | __func__, destp, copy_len, curlen); | ||
344 | rqst->rq_svec[0].iov_len += curlen; | ||
345 | } | ||
346 | /* header now contains entire send message */ | 348 | /* header now contains entire send message */ |
347 | return pad; | 349 | return pad; |
348 | } | 350 | } |
@@ -656,7 +658,7 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) | |||
656 | if (curlen > rqst->rq_rcv_buf.tail[0].iov_len) | 658 | if (curlen > rqst->rq_rcv_buf.tail[0].iov_len) |
657 | curlen = rqst->rq_rcv_buf.tail[0].iov_len; | 659 | curlen = rqst->rq_rcv_buf.tail[0].iov_len; |
658 | if (rqst->rq_rcv_buf.tail[0].iov_base != srcp) | 660 | if (rqst->rq_rcv_buf.tail[0].iov_base != srcp) |
659 | memcpy(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen); | 661 | memmove(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen); |
660 | dprintk("RPC: %s: tail srcp 0x%p len %d curlen %d\n", | 662 | dprintk("RPC: %s: tail srcp 0x%p len %d curlen %d\n", |
661 | __func__, srcp, copy_len, curlen); | 663 | __func__, srcp, copy_len, curlen); |
662 | rqst->rq_rcv_buf.tail[0].iov_len = curlen; | 664 | rqst->rq_rcv_buf.tail[0].iov_len = curlen; |