Skip to content

Commit b432e6b

Browse files
tom95858J. Bruce Fields
authored andcommitted
svcrdma: Change DMA mapping logic to avoid the page_address kernel API
There was logic in the send path that assumed that a page containing data to send to the client has a KVA. This is not always the case and can result in data corruption when page_address returns zero and we end up DMA mapping zero. This patch changes the bus mapping logic to avoid page_address() where necessary and converts all calls from ib_dma_map_single to ib_dma_map_page in order to keep the map/unmap calls symmetric. Signed-off-by: Tom Tucker <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent ecec6e3 commit b432e6b

File tree

3 files changed

+78
-38
lines changed

3 files changed

+78
-38
lines changed

net/sunrpc/xprtrdma/svc_rdma_recvfrom.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,9 +263,9 @@ static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
263263
frmr->page_list_len = PAGE_ALIGN(byte_count) >> PAGE_SHIFT;
264264
for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
265265
frmr->page_list->page_list[page_no] =
266-
ib_dma_map_single(xprt->sc_cm_id->device,
267-
page_address(rqstp->rq_arg.pages[page_no]),
268-
PAGE_SIZE, DMA_FROM_DEVICE);
266+
ib_dma_map_page(xprt->sc_cm_id->device,
267+
rqstp->rq_arg.pages[page_no], 0,
268+
PAGE_SIZE, DMA_FROM_DEVICE);
269269
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
270270
frmr->page_list->page_list[page_no]))
271271
goto fatal_err;
@@ -309,17 +309,21 @@ static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
309309
int count)
310310
{
311311
int i;
312+
unsigned long off;
312313

313314
ctxt->count = count;
314315
ctxt->direction = DMA_FROM_DEVICE;
315316
for (i = 0; i < count; i++) {
316317
ctxt->sge[i].length = 0; /* in case map fails */
317318
if (!frmr) {
319+
BUG_ON(0 == virt_to_page(vec[i].iov_base));
320+
off = (unsigned long)vec[i].iov_base & ~PAGE_MASK;
318321
ctxt->sge[i].addr =
319-
ib_dma_map_single(xprt->sc_cm_id->device,
320-
vec[i].iov_base,
321-
vec[i].iov_len,
322-
DMA_FROM_DEVICE);
322+
ib_dma_map_page(xprt->sc_cm_id->device,
323+
virt_to_page(vec[i].iov_base),
324+
off,
325+
vec[i].iov_len,
326+
DMA_FROM_DEVICE);
323327
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
324328
ctxt->sge[i].addr))
325329
return -EINVAL;

net/sunrpc/xprtrdma/svc_rdma_sendto.c

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@
7070
* on extra page for the RPCRMDA header.
7171
*/
7272
static int fast_reg_xdr(struct svcxprt_rdma *xprt,
73-
struct xdr_buf *xdr,
74-
struct svc_rdma_req_map *vec)
73+
struct xdr_buf *xdr,
74+
struct svc_rdma_req_map *vec)
7575
{
7676
int sge_no;
7777
u32 sge_bytes;
@@ -96,21 +96,25 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
9696
vec->count = 2;
9797
sge_no++;
9898

99-
/* Build the FRMR */
99+
/* Map the XDR head */
100100
frmr->kva = frva;
101101
frmr->direction = DMA_TO_DEVICE;
102102
frmr->access_flags = 0;
103103
frmr->map_len = PAGE_SIZE;
104104
frmr->page_list_len = 1;
105+
page_off = (unsigned long)xdr->head[0].iov_base & ~PAGE_MASK;
105106
frmr->page_list->page_list[page_no] =
106-
ib_dma_map_single(xprt->sc_cm_id->device,
107-
(void *)xdr->head[0].iov_base,
108-
PAGE_SIZE, DMA_TO_DEVICE);
107+
ib_dma_map_page(xprt->sc_cm_id->device,
108+
virt_to_page(xdr->head[0].iov_base),
109+
page_off,
110+
PAGE_SIZE - page_off,
111+
DMA_TO_DEVICE);
109112
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
110113
frmr->page_list->page_list[page_no]))
111114
goto fatal_err;
112115
atomic_inc(&xprt->sc_dma_used);
113116

117+
/* Map the XDR page list */
114118
page_off = xdr->page_base;
115119
page_bytes = xdr->page_len + page_off;
116120
if (!page_bytes)
@@ -128,9 +132,9 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
128132
page_bytes -= sge_bytes;
129133

130134
frmr->page_list->page_list[page_no] =
131-
ib_dma_map_single(xprt->sc_cm_id->device,
132-
page_address(page),
133-
PAGE_SIZE, DMA_TO_DEVICE);
135+
ib_dma_map_page(xprt->sc_cm_id->device,
136+
page, page_off,
137+
sge_bytes, DMA_TO_DEVICE);
134138
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
135139
frmr->page_list->page_list[page_no]))
136140
goto fatal_err;
@@ -166,8 +170,10 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
166170
vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
167171

168172
frmr->page_list->page_list[page_no] =
169-
ib_dma_map_single(xprt->sc_cm_id->device, va, PAGE_SIZE,
170-
DMA_TO_DEVICE);
173+
ib_dma_map_page(xprt->sc_cm_id->device, virt_to_page(va),
174+
page_off,
175+
PAGE_SIZE,
176+
DMA_TO_DEVICE);
171177
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
172178
frmr->page_list->page_list[page_no]))
173179
goto fatal_err;
@@ -245,6 +251,35 @@ static int map_xdr(struct svcxprt_rdma *xprt,
245251
return 0;
246252
}
247253

254+
static dma_addr_t dma_map_xdr(struct svcxprt_rdma *xprt,
255+
struct xdr_buf *xdr,
256+
u32 xdr_off, size_t len, int dir)
257+
{
258+
struct page *page;
259+
dma_addr_t dma_addr;
260+
if (xdr_off < xdr->head[0].iov_len) {
261+
/* This offset is in the head */
262+
xdr_off += (unsigned long)xdr->head[0].iov_base & ~PAGE_MASK;
263+
page = virt_to_page(xdr->head[0].iov_base);
264+
} else {
265+
xdr_off -= xdr->head[0].iov_len;
266+
if (xdr_off < xdr->page_len) {
267+
/* This offset is in the page list */
268+
page = xdr->pages[xdr_off >> PAGE_SHIFT];
269+
xdr_off &= ~PAGE_MASK;
270+
} else {
271+
/* This offset is in the tail */
272+
xdr_off -= xdr->page_len;
273+
xdr_off += (unsigned long)
274+
xdr->tail[0].iov_base & ~PAGE_MASK;
275+
page = virt_to_page(xdr->tail[0].iov_base);
276+
}
277+
}
278+
dma_addr = ib_dma_map_page(xprt->sc_cm_id->device, page, xdr_off,
279+
min_t(size_t, PAGE_SIZE, len), dir);
280+
return dma_addr;
281+
}
282+
248283
/* Assumptions:
249284
* - We are using FRMR
250285
* - or -
@@ -293,10 +328,9 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
293328
sge[sge_no].length = sge_bytes;
294329
if (!vec->frmr) {
295330
sge[sge_no].addr =
296-
ib_dma_map_single(xprt->sc_cm_id->device,
297-
(void *)
298-
vec->sge[xdr_sge_no].iov_base + sge_off,
299-
sge_bytes, DMA_TO_DEVICE);
331+
dma_map_xdr(xprt, &rqstp->rq_res, xdr_off,
332+
sge_bytes, DMA_TO_DEVICE);
333+
xdr_off += sge_bytes;
300334
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
301335
sge[sge_no].addr))
302336
goto err;
@@ -494,7 +528,8 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
494528
* In all three cases, this function prepares the RPCRDMA header in
495529
* sge[0], the 'type' parameter indicates the type to place in the
496530
* RPCRDMA header, and the 'byte_count' field indicates how much of
497-
* the XDR to include in this RDMA_SEND.
531+
* the XDR to include in this RDMA_SEND. NB: The offset of the payload
532+
* to send is zero in the XDR.
498533
*/
499534
static int send_reply(struct svcxprt_rdma *rdma,
500535
struct svc_rqst *rqstp,
@@ -536,23 +571,24 @@ static int send_reply(struct svcxprt_rdma *rdma,
536571
ctxt->sge[0].lkey = rdma->sc_dma_lkey;
537572
ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
538573
ctxt->sge[0].addr =
539-
ib_dma_map_single(rdma->sc_cm_id->device, page_address(page),
540-
ctxt->sge[0].length, DMA_TO_DEVICE);
574+
ib_dma_map_page(rdma->sc_cm_id->device, page, 0,
575+
ctxt->sge[0].length, DMA_TO_DEVICE);
541576
if (ib_dma_mapping_error(rdma->sc_cm_id->device, ctxt->sge[0].addr))
542577
goto err;
543578
atomic_inc(&rdma->sc_dma_used);
544579

545580
ctxt->direction = DMA_TO_DEVICE;
546581

547-
/* Determine how many of our SGE are to be transmitted */
582+
/* Map the payload indicated by 'byte_count' */
548583
for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
584+
int xdr_off = 0;
549585
sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
550586
byte_count -= sge_bytes;
551587
if (!vec->frmr) {
552588
ctxt->sge[sge_no].addr =
553-
ib_dma_map_single(rdma->sc_cm_id->device,
554-
vec->sge[sge_no].iov_base,
555-
sge_bytes, DMA_TO_DEVICE);
589+
dma_map_xdr(rdma, &rqstp->rq_res, xdr_off,
590+
sge_bytes, DMA_TO_DEVICE);
591+
xdr_off += sge_bytes;
556592
if (ib_dma_mapping_error(rdma->sc_cm_id->device,
557593
ctxt->sge[sge_no].addr))
558594
goto err;

net/sunrpc/xprtrdma/svc_rdma_transport.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
121121
*/
122122
if (ctxt->sge[i].lkey == xprt->sc_dma_lkey) {
123123
atomic_dec(&xprt->sc_dma_used);
124-
ib_dma_unmap_single(xprt->sc_cm_id->device,
124+
ib_dma_unmap_page(xprt->sc_cm_id->device,
125125
ctxt->sge[i].addr,
126126
ctxt->sge[i].length,
127127
ctxt->direction);
@@ -503,8 +503,8 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
503503
BUG_ON(sge_no >= xprt->sc_max_sge);
504504
page = svc_rdma_get_page();
505505
ctxt->pages[sge_no] = page;
506-
pa = ib_dma_map_single(xprt->sc_cm_id->device,
507-
page_address(page), PAGE_SIZE,
506+
pa = ib_dma_map_page(xprt->sc_cm_id->device,
507+
page, 0, PAGE_SIZE,
508508
DMA_FROM_DEVICE);
509509
if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
510510
goto err_put_ctxt;
@@ -800,8 +800,8 @@ static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
800800
if (ib_dma_mapping_error(frmr->mr->device, addr))
801801
continue;
802802
atomic_dec(&xprt->sc_dma_used);
803-
ib_dma_unmap_single(frmr->mr->device, addr, PAGE_SIZE,
804-
frmr->direction);
803+
ib_dma_unmap_page(frmr->mr->device, addr, PAGE_SIZE,
804+
frmr->direction);
805805
}
806806
}
807807

@@ -1276,7 +1276,7 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
12761276
atomic_read(&xprt->sc_sq_count) <
12771277
xprt->sc_sq_depth);
12781278
if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
1279-
return 0;
1279+
return -ENOTCONN;
12801280
continue;
12811281
}
12821282
/* Take a transport ref for each WR posted */
@@ -1322,8 +1322,8 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
13221322
length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
13231323

13241324
/* Prepare SGE for local address */
1325-
sge.addr = ib_dma_map_single(xprt->sc_cm_id->device,
1326-
page_address(p), PAGE_SIZE, DMA_FROM_DEVICE);
1325+
sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
1326+
p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
13271327
if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
13281328
put_page(p);
13291329
return;
@@ -1350,7 +1350,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
13501350
if (ret) {
13511351
dprintk("svcrdma: Error %d posting send for protocol error\n",
13521352
ret);
1353-
ib_dma_unmap_single(xprt->sc_cm_id->device,
1353+
ib_dma_unmap_page(xprt->sc_cm_id->device,
13541354
sge.addr, PAGE_SIZE,
13551355
DMA_FROM_DEVICE);
13561356
svc_rdma_put_context(ctxt, 1);

0 commit comments

Comments
 (0)