|
@@ -132,6 +132,33 @@ rpcrdma_tail_pullup(struct xdr_buf *buf)
|
|
return tlen;
|
|
return tlen;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Split "vec" on page boundaries into segments. FMR registers pages,
|
|
|
|
+ * not a byte range. Other modes coalesce these segments into a single
|
|
|
|
+ * MR when they can.
|
|
|
|
+ */
|
|
|
|
+static int
|
|
|
|
+rpcrdma_convert_kvec(struct kvec *vec, struct rpcrdma_mr_seg *seg,
|
|
|
|
+ int n, int nsegs)
|
|
|
|
+{
|
|
|
|
+ size_t page_offset;
|
|
|
|
+ u32 remaining;
|
|
|
|
+ char *base;
|
|
|
|
+
|
|
|
|
+ base = vec->iov_base;
|
|
|
|
+ page_offset = offset_in_page(base);
|
|
|
|
+ remaining = vec->iov_len;
|
|
|
|
+ while (remaining && n < nsegs) {
|
|
|
|
+ seg[n].mr_page = NULL;
|
|
|
|
+ seg[n].mr_offset = base;
|
|
|
|
+ seg[n].mr_len = min_t(u32, PAGE_SIZE - page_offset, remaining);
|
|
|
|
+ remaining -= seg[n].mr_len;
|
|
|
|
+ base += seg[n].mr_len;
|
|
|
|
+ ++n;
|
|
|
|
+ page_offset = 0;
|
|
|
|
+ }
|
|
|
|
+ return n;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Chunk assembly from upper layer xdr_buf.
|
|
* Chunk assembly from upper layer xdr_buf.
|
|
*
|
|
*
|
|
@@ -150,11 +177,10 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
|
|
int page_base;
|
|
int page_base;
|
|
struct page **ppages;
|
|
struct page **ppages;
|
|
|
|
|
|
- if (pos == 0 && xdrbuf->head[0].iov_len) {
|
|
|
|
- seg[n].mr_page = NULL;
|
|
|
|
- seg[n].mr_offset = xdrbuf->head[0].iov_base;
|
|
|
|
- seg[n].mr_len = xdrbuf->head[0].iov_len;
|
|
|
|
- ++n;
|
|
|
|
|
|
+ if (pos == 0) {
|
|
|
|
+ n = rpcrdma_convert_kvec(&xdrbuf->head[0], seg, n, nsegs);
|
|
|
|
+ if (n == nsegs)
|
|
|
|
+ return -EIO;
|
|
}
|
|
}
|
|
|
|
|
|
len = xdrbuf->page_len;
|
|
len = xdrbuf->page_len;
|
|
@@ -192,13 +218,9 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
|
|
* xdr pad bytes, saving the server an RDMA operation. */
|
|
* xdr pad bytes, saving the server an RDMA operation. */
|
|
if (xdrbuf->tail[0].iov_len < 4 && xprt_rdma_pad_optimize)
|
|
if (xdrbuf->tail[0].iov_len < 4 && xprt_rdma_pad_optimize)
|
|
return n;
|
|
return n;
|
|
|
|
+ n = rpcrdma_convert_kvec(&xdrbuf->tail[0], seg, n, nsegs);
|
|
if (n == nsegs)
|
|
if (n == nsegs)
|
|
- /* Tail remains, but we're out of segments */
|
|
|
|
return -EIO;
|
|
return -EIO;
|
|
- seg[n].mr_page = NULL;
|
|
|
|
- seg[n].mr_offset = xdrbuf->tail[0].iov_base;
|
|
|
|
- seg[n].mr_len = xdrbuf->tail[0].iov_len;
|
|
|
|
- ++n;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return n;
|
|
return n;
|