Skip to content

Commit 61da886

Browse files
chuckleveramschuma-ntap
authored andcommitted
xprtrdma: Explicitly resetting MRs is no longer necessary
When a memory operation fails, the MR's driver state might not match its hardware state. The only reliable recourse is to dereg the MR. This is done in ->ro_recover_mr, which then attempts to allocate a fresh MR to replace the released MR. Since commit e2ac236 ("xprtrdma: Allocate MRs on demand"), xprtrdma dynamically allocates MRs. It can add more MRs whenever they are needed. That makes it possible to simply release an MR when a memory operation fails, instead of "recovering" it. It will automatically be replaced by the on-demand MR allocator. This commit is a little larger than I wanted, but it replaces ->ro_recover_mr, rb_recovery_lock, rb_recovery_worker, and the rb_stale_mrs list with a generic work queue. Since MRs are no longer orphaned, the mrs_orphaned metric is no longer used. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
1 parent c421ece commit 61da886

File tree

7 files changed

+114
-198
lines changed

7 files changed

+114
-198
lines changed

include/trace/events/rpcrdma.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ DEFINE_MR_EVENT(xprtrdma_localinv);
655655
DEFINE_MR_EVENT(xprtrdma_dma_map);
656656
DEFINE_MR_EVENT(xprtrdma_dma_unmap);
657657
DEFINE_MR_EVENT(xprtrdma_remoteinv);
658-
DEFINE_MR_EVENT(xprtrdma_recover_mr);
658+
DEFINE_MR_EVENT(xprtrdma_mr_recycle);
659659

660660
/**
661661
** Reply events

net/sunrpc/xprtrdma/fmr_ops.c

Lines changed: 56 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -49,46 +49,7 @@ fmr_is_supported(struct rpcrdma_ia *ia)
4949
return true;
5050
}
5151

52-
static int
53-
fmr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr)
54-
{
55-
static struct ib_fmr_attr fmr_attr = {
56-
.max_pages = RPCRDMA_MAX_FMR_SGES,
57-
.max_maps = 1,
58-
.page_shift = PAGE_SHIFT
59-
};
60-
61-
mr->fmr.fm_physaddrs = kcalloc(RPCRDMA_MAX_FMR_SGES,
62-
sizeof(u64), GFP_KERNEL);
63-
if (!mr->fmr.fm_physaddrs)
64-
goto out_free;
65-
66-
mr->mr_sg = kcalloc(RPCRDMA_MAX_FMR_SGES,
67-
sizeof(*mr->mr_sg), GFP_KERNEL);
68-
if (!mr->mr_sg)
69-
goto out_free;
70-
71-
sg_init_table(mr->mr_sg, RPCRDMA_MAX_FMR_SGES);
72-
73-
mr->fmr.fm_mr = ib_alloc_fmr(ia->ri_pd, RPCRDMA_FMR_ACCESS_FLAGS,
74-
&fmr_attr);
75-
if (IS_ERR(mr->fmr.fm_mr))
76-
goto out_fmr_err;
77-
78-
INIT_LIST_HEAD(&mr->mr_list);
79-
return 0;
80-
81-
out_fmr_err:
82-
dprintk("RPC: %s: ib_alloc_fmr returned %ld\n", __func__,
83-
PTR_ERR(mr->fmr.fm_mr));
84-
85-
out_free:
86-
kfree(mr->mr_sg);
87-
kfree(mr->fmr.fm_physaddrs);
88-
return -ENOMEM;
89-
}
90-
91-
static int
52+
static void
9253
__fmr_unmap(struct rpcrdma_mr *mr)
9354
{
9455
LIST_HEAD(l);
@@ -97,13 +58,16 @@ __fmr_unmap(struct rpcrdma_mr *mr)
9758
list_add(&mr->fmr.fm_mr->list, &l);
9859
rc = ib_unmap_fmr(&l);
9960
list_del(&mr->fmr.fm_mr->list);
100-
return rc;
61+
if (rc)
62+
pr_err("rpcrdma: final ib_unmap_fmr for %p failed %i\n",
63+
mr, rc);
10164
}
10265

66+
/* Release an MR.
67+
*/
10368
static void
10469
fmr_op_release_mr(struct rpcrdma_mr *mr)
10570
{
106-
LIST_HEAD(unmap_list);
10771
int rc;
10872

10973
kfree(mr->fmr.fm_physaddrs);
@@ -112,10 +76,7 @@ fmr_op_release_mr(struct rpcrdma_mr *mr)
11276
/* In case this one was left mapped, try to unmap it
11377
* to prevent dealloc_fmr from failing with EBUSY
11478
*/
115-
rc = __fmr_unmap(mr);
116-
if (rc)
117-
pr_err("rpcrdma: final ib_unmap_fmr for %p failed %i\n",
118-
mr, rc);
79+
__fmr_unmap(mr);
11980

12081
rc = ib_dealloc_fmr(mr->fmr.fm_mr);
12182
if (rc)
@@ -125,40 +86,68 @@ fmr_op_release_mr(struct rpcrdma_mr *mr)
12586
kfree(mr);
12687
}
12788

128-
/* Reset of a single FMR.
89+
/* MRs are dynamically allocated, so simply clean up and release the MR.
90+
* A replacement MR will subsequently be allocated on demand.
12991
*/
13092
static void
131-
fmr_op_recover_mr(struct rpcrdma_mr *mr)
93+
fmr_mr_recycle_worker(struct work_struct *work)
13294
{
95+
struct rpcrdma_mr *mr = container_of(work, struct rpcrdma_mr, mr_recycle);
13396
struct rpcrdma_xprt *r_xprt = mr->mr_xprt;
134-
int rc;
13597

136-
/* ORDER: invalidate first */
137-
rc = __fmr_unmap(mr);
138-
if (rc)
139-
goto out_release;
140-
141-
/* ORDER: then DMA unmap */
142-
rpcrdma_mr_unmap_and_put(mr);
143-
144-
r_xprt->rx_stats.mrs_recovered++;
145-
return;
146-
147-
out_release:
148-
pr_err("rpcrdma: FMR reset failed (%d), %p released\n", rc, mr);
149-
r_xprt->rx_stats.mrs_orphaned++;
98+
trace_xprtrdma_mr_recycle(mr);
15099

151100
trace_xprtrdma_dma_unmap(mr);
152101
ib_dma_unmap_sg(r_xprt->rx_ia.ri_device,
153102
mr->mr_sg, mr->mr_nents, mr->mr_dir);
154103

155104
spin_lock(&r_xprt->rx_buf.rb_mrlock);
156105
list_del(&mr->mr_all);
106+
r_xprt->rx_stats.mrs_recycled++;
157107
spin_unlock(&r_xprt->rx_buf.rb_mrlock);
158-
159108
fmr_op_release_mr(mr);
160109
}
161110

111+
static int
112+
fmr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr)
113+
{
114+
static struct ib_fmr_attr fmr_attr = {
115+
.max_pages = RPCRDMA_MAX_FMR_SGES,
116+
.max_maps = 1,
117+
.page_shift = PAGE_SHIFT
118+
};
119+
120+
mr->fmr.fm_physaddrs = kcalloc(RPCRDMA_MAX_FMR_SGES,
121+
sizeof(u64), GFP_KERNEL);
122+
if (!mr->fmr.fm_physaddrs)
123+
goto out_free;
124+
125+
mr->mr_sg = kcalloc(RPCRDMA_MAX_FMR_SGES,
126+
sizeof(*mr->mr_sg), GFP_KERNEL);
127+
if (!mr->mr_sg)
128+
goto out_free;
129+
130+
sg_init_table(mr->mr_sg, RPCRDMA_MAX_FMR_SGES);
131+
132+
mr->fmr.fm_mr = ib_alloc_fmr(ia->ri_pd, RPCRDMA_FMR_ACCESS_FLAGS,
133+
&fmr_attr);
134+
if (IS_ERR(mr->fmr.fm_mr))
135+
goto out_fmr_err;
136+
137+
INIT_LIST_HEAD(&mr->mr_list);
138+
INIT_WORK(&mr->mr_recycle, fmr_mr_recycle_worker);
139+
return 0;
140+
141+
out_fmr_err:
142+
dprintk("RPC: %s: ib_alloc_fmr returned %ld\n", __func__,
143+
PTR_ERR(mr->fmr.fm_mr));
144+
145+
out_free:
146+
kfree(mr->mr_sg);
147+
kfree(mr->fmr.fm_physaddrs);
148+
return -ENOMEM;
149+
}
150+
162151
/* On success, sets:
163152
* ep->rep_attr.cap.max_send_wr
164153
* ep->rep_attr.cap.max_recv_wr
@@ -312,7 +301,7 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs)
312301
r_xprt->rx_stats.local_inv_needed++;
313302
rc = ib_unmap_fmr(&unmap_list);
314303
if (rc)
315-
goto out_reset;
304+
goto out_release;
316305

317306
/* ORDER: Now DMA unmap all of the req's MRs, and return
318307
* them to the free MW list.
@@ -325,21 +314,20 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs)
325314

326315
return;
327316

328-
out_reset:
317+
out_release:
329318
pr_err("rpcrdma: ib_unmap_fmr failed (%i)\n", rc);
330319

331320
while (!list_empty(mrs)) {
332321
mr = rpcrdma_mr_pop(mrs);
333322
list_del(&mr->fmr.fm_mr->list);
334-
fmr_op_recover_mr(mr);
323+
rpcrdma_mr_recycle(mr);
335324
}
336325
}
337326

338327
const struct rpcrdma_memreg_ops rpcrdma_fmr_memreg_ops = {
339328
.ro_map = fmr_op_map,
340329
.ro_send = fmr_op_send,
341330
.ro_unmap_sync = fmr_op_unmap_sync,
342-
.ro_recover_mr = fmr_op_recover_mr,
343331
.ro_open = fmr_op_open,
344332
.ro_maxpages = fmr_op_maxpages,
345333
.ro_init_mr = fmr_op_init_mr,

0 commit comments

Comments
 (0)