|
|
@@ -740,8 +740,16 @@ rpcrdma_count_chunks(struct rpcrdma_rep *rep, int wrchunk, __be32 **iptrp)
|
|
|
return total_len;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Scatter inline received data back into provided iov's.
|
|
|
+/**
|
|
|
+ * rpcrdma_inline_fixup - Scatter inline received data into rqst's iovecs
|
|
|
+ * @rqst: controlling RPC request
|
|
|
+ * @srcp: points to RPC message payload in receive buffer
|
|
|
+ * @copy_len: remaining length of receive buffer content
|
|
|
+ * @pad: Write chunk pad bytes needed (zero for pure inline)
|
|
|
+ *
|
|
|
+ * The upper layer has set the maximum number of bytes it can
|
|
|
+ * receive in each component of rq_rcv_buf. These values are set in
|
|
|
+ * the head.iov_len, page_len, tail.iov_len, and buflen fields.
|
|
|
*/
|
|
|
static void
|
|
|
rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
|
|
|
@@ -751,17 +759,19 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
|
|
|
struct page **ppages;
|
|
|
int page_base;
|
|
|
|
|
|
+ /* The head iovec is redirected to the RPC reply message
|
|
|
+ * in the receive buffer, to avoid a memcopy.
|
|
|
+ */
|
|
|
+ rqst->rq_rcv_buf.head[0].iov_base = srcp;
|
|
|
+
|
|
|
+ /* The contents of the receive buffer that follow
|
|
|
+ * head.iov_len bytes are copied into the page list.
|
|
|
+ */
|
|
|
curlen = rqst->rq_rcv_buf.head[0].iov_len;
|
|
|
- if (curlen > copy_len) { /* write chunk header fixup */
|
|
|
+ if (curlen > copy_len)
|
|
|
curlen = copy_len;
|
|
|
- rqst->rq_rcv_buf.head[0].iov_len = curlen;
|
|
|
- }
|
|
|
-
|
|
|
dprintk("RPC: %s: srcp 0x%p len %d hdrlen %d\n",
|
|
|
__func__, srcp, copy_len, curlen);
|
|
|
-
|
|
|
- /* Shift pointer for first receive segment only */
|
|
|
- rqst->rq_rcv_buf.head[0].iov_base = srcp;
|
|
|
srcp += curlen;
|
|
|
copy_len -= curlen;
|
|
|
|
|
|
@@ -798,28 +808,23 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
|
|
|
break;
|
|
|
page_base = 0;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (copy_len && rqst->rq_rcv_buf.tail[0].iov_len) {
|
|
|
- curlen = copy_len;
|
|
|
- if (curlen > rqst->rq_rcv_buf.tail[0].iov_len)
|
|
|
- curlen = rqst->rq_rcv_buf.tail[0].iov_len;
|
|
|
- if (rqst->rq_rcv_buf.tail[0].iov_base != srcp)
|
|
|
- memmove(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen);
|
|
|
- dprintk("RPC: %s: tail srcp 0x%p len %d curlen %d\n",
|
|
|
- __func__, srcp, copy_len, curlen);
|
|
|
- rqst->rq_rcv_buf.tail[0].iov_len = curlen;
|
|
|
- copy_len -= curlen; ++i;
|
|
|
- } else
|
|
|
- rqst->rq_rcv_buf.tail[0].iov_len = 0;
|
|
|
-
|
|
|
- if (pad) {
|
|
|
- /* implicit padding on terminal chunk */
|
|
|
- unsigned char *p = rqst->rq_rcv_buf.tail[0].iov_base;
|
|
|
- while (pad--)
|
|
|
- p[rqst->rq_rcv_buf.tail[0].iov_len++] = 0;
|
|
|
+ /* Implicit padding for the last segment in a Write
|
|
|
+ * chunk is inserted inline at the front of the tail
|
|
|
+ * iovec. The upper layer ignores the content of
|
|
|
+ * the pad. Simply ensure inline content in the tail
|
|
|
+ * that follows the Write chunk is properly aligned.
|
|
|
+ */
|
|
|
+ if (pad)
|
|
|
+ srcp -= pad;
|
|
|
}
|
|
|
|
|
|
+ /* The tail iovec is redirected to the remaining data
|
|
|
+ * in the receive buffer, to avoid a memcopy.
|
|
|
+ */
|
|
|
+ if (copy_len || pad)
|
|
|
+ rqst->rq_rcv_buf.tail[0].iov_base = srcp;
|
|
|
+
|
|
|
if (copy_len)
|
|
|
dprintk("RPC: %s: %d bytes in"
|
|
|
" %d extra segments (%d lost)\n",
|