Skip to content

Commit 54cbd6b

Browse files
chuckleveramschuma-ntap
authored andcommitted
xprtrdma: Delay DMA mapping Send and Receive buffers
Currently, each regbuf is allocated and DMA mapped at the same time. This is done during transport creation. When a device driver is unloaded, every DMA-mapped buffer in use by a transport has to be unmapped, and then remapped to the new device if the driver is loaded again. Remapping will have to be done _after_ the connect worker has set up the new device. But there's an ordering problem: call_allocate, which invokes xprt_rdma_allocate which calls rpcrdma_alloc_regbuf to allocate Send buffers, happens _before_ the connect worker can run to set up the new device. Instead, at transport creation, allocate each buffer, but leave it unmapped. Once the RPC carries these buffers into ->send_request, by which time a transport connection should have been established, check to see that the RPC's buffers have been DMA mapped. If not, map them there. When device driver unplug support is added, it will simply unmap all the transport's regbufs, but it doesn't have to deallocate the underlying memory. Signed-off-by: Chuck Lever <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent 99ef4db commit 54cbd6b

File tree

4 files changed

+78
-26
lines changed

4 files changed

+78
-26
lines changed

net/sunrpc/xprtrdma/backchannel.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,16 +230,24 @@ int rpcrdma_bc_marshal_reply(struct rpc_rqst *rqst)
230230
__func__, (int)rpclen, rqst->rq_svec[0].iov_base);
231231
#endif
232232

233+
if (!rpcrdma_dma_map_regbuf(&r_xprt->rx_ia, req->rl_rdmabuf))
234+
goto out_map;
233235
req->rl_send_iov[0].addr = rdmab_addr(req->rl_rdmabuf);
234236
req->rl_send_iov[0].length = RPCRDMA_HDRLEN_MIN;
235237
req->rl_send_iov[0].lkey = rdmab_lkey(req->rl_rdmabuf);
236238

239+
if (!rpcrdma_dma_map_regbuf(&r_xprt->rx_ia, req->rl_sendbuf))
240+
goto out_map;
237241
req->rl_send_iov[1].addr = rdmab_addr(req->rl_sendbuf);
238242
req->rl_send_iov[1].length = rpclen;
239243
req->rl_send_iov[1].lkey = rdmab_lkey(req->rl_sendbuf);
240244

241245
req->rl_niovs = 2;
242246
return 0;
247+
248+
out_map:
249+
pr_err("rpcrdma: failed to DMA map a Send buffer\n");
250+
return -EIO;
243251
}
244252

245253
/**

net/sunrpc/xprtrdma/rpc_rdma.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,8 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
681681
transfertypes[rtype], transfertypes[wtype],
682682
hdrlen, rpclen);
683683

684+
if (!rpcrdma_dma_map_regbuf(&r_xprt->rx_ia, req->rl_rdmabuf))
685+
goto out_map;
684686
req->rl_send_iov[0].addr = rdmab_addr(req->rl_rdmabuf);
685687
req->rl_send_iov[0].length = hdrlen;
686688
req->rl_send_iov[0].lkey = rdmab_lkey(req->rl_rdmabuf);
@@ -689,6 +691,8 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
689691
if (rtype == rpcrdma_areadch)
690692
return 0;
691693

694+
if (!rpcrdma_dma_map_regbuf(&r_xprt->rx_ia, req->rl_sendbuf))
695+
goto out_map;
692696
req->rl_send_iov[1].addr = rdmab_addr(req->rl_sendbuf);
693697
req->rl_send_iov[1].length = rpclen;
694698
req->rl_send_iov[1].lkey = rdmab_lkey(req->rl_sendbuf);
@@ -704,6 +708,11 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst)
704708
out_unmap:
705709
r_xprt->rx_ia.ri_ops->ro_unmap_safe(r_xprt, req, false);
706710
return PTR_ERR(iptr);
711+
712+
out_map:
713+
pr_err("rpcrdma: failed to DMA map a Send buffer\n");
714+
iptr = ERR_PTR(-EIO);
715+
goto out_unmap;
707716
}
708717

709718
/*

net/sunrpc/xprtrdma/verbs.c

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,9 +1179,8 @@ rpcrdma_recv_buffer_put(struct rpcrdma_rep *rep)
11791179
* @direction: direction of data movement
11801180
* @flags: GFP flags
11811181
*
1182-
* Returns an ERR_PTR, or a pointer to a regbuf, which is a
1183-
* contiguous memory region that is DMA mapped persistently, and
1184-
* is registered for local I/O.
1182+
* Returns an ERR_PTR, or a pointer to a regbuf, a buffer that
1183+
* can be persistently DMA-mapped for I/O.
11851184
*
11861185
* xprtrdma uses a regbuf for posting an outgoing RDMA SEND, or for
11871186
* receiving the payload of RDMA RECV operations. During Long Calls
@@ -1192,32 +1191,50 @@ rpcrdma_alloc_regbuf(struct rpcrdma_ia *ia, size_t size,
11921191
enum dma_data_direction direction, gfp_t flags)
11931192
{
11941193
struct rpcrdma_regbuf *rb;
1195-
struct ib_sge *iov;
11961194

11971195
rb = kmalloc(sizeof(*rb) + size, flags);
11981196
if (rb == NULL)
1199-
goto out;
1197+
return ERR_PTR(-ENOMEM);
12001198

1199+
rb->rg_device = NULL;
12011200
rb->rg_direction = direction;
1202-
iov = &rb->rg_iov;
1203-
iov->length = size;
1204-
iov->lkey = ia->ri_pd->local_dma_lkey;
1205-
1206-
if (direction != DMA_NONE) {
1207-
iov->addr = ib_dma_map_single(ia->ri_device,
1208-
(void *)rb->rg_base,
1209-
rdmab_length(rb),
1210-
rb->rg_direction);
1211-
if (ib_dma_mapping_error(ia->ri_device, iov->addr))
1212-
goto out_free;
1213-
}
1201+
rb->rg_iov.length = size;
12141202

12151203
return rb;
1204+
}
12161205

1217-
out_free:
1218-
kfree(rb);
1219-
out:
1220-
return ERR_PTR(-ENOMEM);
1206+
/**
1207+
* __rpcrdma_map_regbuf - DMA-map a regbuf
1208+
* @ia: controlling rpcrdma_ia
1209+
* @rb: regbuf to be mapped
1210+
*/
1211+
bool
1212+
__rpcrdma_dma_map_regbuf(struct rpcrdma_ia *ia, struct rpcrdma_regbuf *rb)
1213+
{
1214+
if (rb->rg_direction == DMA_NONE)
1215+
return false;
1216+
1217+
rb->rg_iov.addr = ib_dma_map_single(ia->ri_device,
1218+
(void *)rb->rg_base,
1219+
rdmab_length(rb),
1220+
rb->rg_direction);
1221+
if (ib_dma_mapping_error(ia->ri_device, rdmab_addr(rb)))
1222+
return false;
1223+
1224+
rb->rg_device = ia->ri_device;
1225+
rb->rg_iov.lkey = ia->ri_pd->local_dma_lkey;
1226+
return true;
1227+
}
1228+
1229+
static void
1230+
rpcrdma_dma_unmap_regbuf(struct rpcrdma_regbuf *rb)
1231+
{
1232+
if (!rpcrdma_regbuf_is_mapped(rb))
1233+
return;
1234+
1235+
ib_dma_unmap_single(rb->rg_device, rdmab_addr(rb),
1236+
rdmab_length(rb), rb->rg_direction);
1237+
rb->rg_device = NULL;
12211238
}
12221239

12231240
/**
@@ -1231,11 +1248,7 @@ rpcrdma_free_regbuf(struct rpcrdma_ia *ia, struct rpcrdma_regbuf *rb)
12311248
if (!rb)
12321249
return;
12331250

1234-
if (rb->rg_direction != DMA_NONE) {
1235-
ib_dma_unmap_single(ia->ri_device, rdmab_addr(rb),
1236-
rdmab_length(rb), rb->rg_direction);
1237-
}
1238-
1251+
rpcrdma_dma_unmap_regbuf(rb);
12391252
kfree(rb);
12401253
}
12411254

@@ -1307,11 +1320,17 @@ rpcrdma_ep_post_recv(struct rpcrdma_ia *ia,
13071320
recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov;
13081321
recv_wr.num_sge = 1;
13091322

1323+
if (!rpcrdma_dma_map_regbuf(ia, rep->rr_rdmabuf))
1324+
goto out_map;
13101325
rc = ib_post_recv(ia->ri_id->qp, &recv_wr, &recv_wr_fail);
13111326
if (rc)
13121327
goto out_postrecv;
13131328
return 0;
13141329

1330+
out_map:
1331+
pr_err("rpcrdma: failed to DMA map the Receive buffer\n");
1332+
return -EIO;
1333+
13151334
out_postrecv:
13161335
pr_err("rpcrdma: ib_post_recv returned %i\n", rc);
13171336
return -ENOTCONN;

net/sunrpc/xprtrdma/xprt_rdma.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ struct rpcrdma_ep {
113113

114114
struct rpcrdma_regbuf {
115115
struct ib_sge rg_iov;
116+
struct ib_device *rg_device;
116117
enum dma_data_direction rg_direction;
117118
__be32 rg_base[0] __attribute__ ((aligned(256)));
118119
};
@@ -480,9 +481,24 @@ void rpcrdma_defer_mr_recovery(struct rpcrdma_mw *);
480481
struct rpcrdma_regbuf *rpcrdma_alloc_regbuf(struct rpcrdma_ia *,
481482
size_t, enum dma_data_direction,
482483
gfp_t);
484+
bool __rpcrdma_dma_map_regbuf(struct rpcrdma_ia *, struct rpcrdma_regbuf *);
483485
void rpcrdma_free_regbuf(struct rpcrdma_ia *,
484486
struct rpcrdma_regbuf *);
485487

488+
static inline bool
489+
rpcrdma_regbuf_is_mapped(struct rpcrdma_regbuf *rb)
490+
{
491+
return rb->rg_device != NULL;
492+
}
493+
494+
static inline bool
495+
rpcrdma_dma_map_regbuf(struct rpcrdma_ia *ia, struct rpcrdma_regbuf *rb)
496+
{
497+
if (likely(rpcrdma_regbuf_is_mapped(rb)))
498+
return true;
499+
return __rpcrdma_dma_map_regbuf(ia, rb);
500+
}
501+
486502
int rpcrdma_ep_post_extra_recv(struct rpcrdma_xprt *, unsigned int);
487503

488504
int rpcrdma_alloc_wq(void);

0 commit comments

Comments
 (0)