aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2018-10-01 14:25:25 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2018-10-02 15:48:12 -0400
commit61da886bf74e738995d359fa14d77f72d14cfb87 (patch)
tree2618cc1783b1cde279f0cb6bab4f687795fef935 /net
parentc421ece68f6952d4cc48ee81ebfc61ef0b83ad3b (diff)
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 e2ac236c0b651 ("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>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/xprtrdma/fmr_ops.c124
-rw-r--r--net/sunrpc/xprtrdma/frwr_ops.c130
-rw-r--r--net/sunrpc/xprtrdma/rpc_rdma.c2
-rw-r--r--net/sunrpc/xprtrdma/transport.c2
-rw-r--r--net/sunrpc/xprtrdma/verbs.c38
-rw-r--r--net/sunrpc/xprtrdma/xprt_rdma.h14
6 files changed, 113 insertions, 197 deletions
diff --git a/net/sunrpc/xprtrdma/fmr_ops.c b/net/sunrpc/xprtrdma/fmr_ops.c
index db589a23682b..f1cf3a36a992 100644
--- a/net/sunrpc/xprtrdma/fmr_ops.c
+++ b/net/sunrpc/xprtrdma/fmr_ops.c
@@ -49,46 +49,7 @@ fmr_is_supported(struct rpcrdma_ia *ia)
49 return true; 49 return true;
50} 50}
51 51
52static int 52static void
53fmr_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
81out_fmr_err:
82 dprintk("RPC: %s: ib_alloc_fmr returned %ld\n", __func__,
83 PTR_ERR(mr->fmr.fm_mr));
84
85out_free:
86 kfree(mr->mr_sg);
87 kfree(mr->fmr.fm_physaddrs);
88 return -ENOMEM;
89}
90
91static int
92__fmr_unmap(struct rpcrdma_mr *mr) 53__fmr_unmap(struct rpcrdma_mr *mr)
93{ 54{
94 LIST_HEAD(l); 55 LIST_HEAD(l);
@@ -97,13 +58,16 @@ __fmr_unmap(struct rpcrdma_mr *mr)
97 list_add(&mr->fmr.fm_mr->list, &l); 58 list_add(&mr->fmr.fm_mr->list, &l);
98 rc = ib_unmap_fmr(&l); 59 rc = ib_unmap_fmr(&l);
99 list_del(&mr->fmr.fm_mr->list); 60 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);
101} 64}
102 65
66/* Release an MR.
67 */
103static void 68static void
104fmr_op_release_mr(struct rpcrdma_mr *mr) 69fmr_op_release_mr(struct rpcrdma_mr *mr)
105{ 70{
106 LIST_HEAD(unmap_list);
107 int rc; 71 int rc;
108 72
109 kfree(mr->fmr.fm_physaddrs); 73 kfree(mr->fmr.fm_physaddrs);
@@ -112,10 +76,7 @@ fmr_op_release_mr(struct rpcrdma_mr *mr)
112 /* In case this one was left mapped, try to unmap it 76 /* In case this one was left mapped, try to unmap it
113 * to prevent dealloc_fmr from failing with EBUSY 77 * to prevent dealloc_fmr from failing with EBUSY
114 */ 78 */
115 rc = __fmr_unmap(mr); 79 __fmr_unmap(mr);
116 if (rc)
117 pr_err("rpcrdma: final ib_unmap_fmr for %p failed %i\n",
118 mr, rc);
119 80
120 rc = ib_dealloc_fmr(mr->fmr.fm_mr); 81 rc = ib_dealloc_fmr(mr->fmr.fm_mr);
121 if (rc) 82 if (rc)
@@ -125,28 +86,16 @@ fmr_op_release_mr(struct rpcrdma_mr *mr)
125 kfree(mr); 86 kfree(mr);
126} 87}
127 88
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.
129 */ 91 */
130static void 92static void
131fmr_op_recover_mr(struct rpcrdma_mr *mr) 93fmr_mr_recycle_worker(struct work_struct *work)
132{ 94{
95 struct rpcrdma_mr *mr = container_of(work, struct rpcrdma_mr, mr_recycle);
133 struct rpcrdma_xprt *r_xprt = mr->mr_xprt; 96 struct rpcrdma_xprt *r_xprt = mr->mr_xprt;
134 int rc;
135 97
136 /* ORDER: invalidate first */ 98 trace_xprtrdma_mr_recycle(mr);
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
147out_release:
148 pr_err("rpcrdma: FMR reset failed (%d), %p released\n", rc, mr);
149 r_xprt->rx_stats.mrs_orphaned++;
150 99
151 trace_xprtrdma_dma_unmap(mr); 100 trace_xprtrdma_dma_unmap(mr);
152 ib_dma_unmap_sg(r_xprt->rx_ia.ri_device, 101 ib_dma_unmap_sg(r_xprt->rx_ia.ri_device,
@@ -154,11 +103,51 @@ out_release:
154 103
155 spin_lock(&r_xprt->rx_buf.rb_mrlock); 104 spin_lock(&r_xprt->rx_buf.rb_mrlock);
156 list_del(&mr->mr_all); 105 list_del(&mr->mr_all);
106 r_xprt->rx_stats.mrs_recycled++;
157 spin_unlock(&r_xprt->rx_buf.rb_mrlock); 107 spin_unlock(&r_xprt->rx_buf.rb_mrlock);
158
159 fmr_op_release_mr(mr); 108 fmr_op_release_mr(mr);
160} 109}
161 110
111static int
112fmr_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
141out_fmr_err:
142 dprintk("RPC: %s: ib_alloc_fmr returned %ld\n", __func__,
143 PTR_ERR(mr->fmr.fm_mr));
144
145out_free:
146 kfree(mr->mr_sg);
147 kfree(mr->fmr.fm_physaddrs);
148 return -ENOMEM;
149}
150
162/* On success, sets: 151/* On success, sets:
163 * ep->rep_attr.cap.max_send_wr 152 * ep->rep_attr.cap.max_send_wr
164 * ep->rep_attr.cap.max_recv_wr 153 * ep->rep_attr.cap.max_recv_wr
@@ -312,7 +301,7 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs)
312 r_xprt->rx_stats.local_inv_needed++; 301 r_xprt->rx_stats.local_inv_needed++;
313 rc = ib_unmap_fmr(&unmap_list); 302 rc = ib_unmap_fmr(&unmap_list);
314 if (rc) 303 if (rc)
315 goto out_reset; 304 goto out_release;
316 305
317 /* ORDER: Now DMA unmap all of the req's MRs, and return 306 /* ORDER: Now DMA unmap all of the req's MRs, and return
318 * them to the free MW list. 307 * them to the free MW list.
@@ -325,13 +314,13 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs)
325 314
326 return; 315 return;
327 316
328out_reset: 317out_release:
329 pr_err("rpcrdma: ib_unmap_fmr failed (%i)\n", rc); 318 pr_err("rpcrdma: ib_unmap_fmr failed (%i)\n", rc);
330 319
331 while (!list_empty(mrs)) { 320 while (!list_empty(mrs)) {
332 mr = rpcrdma_mr_pop(mrs); 321 mr = rpcrdma_mr_pop(mrs);
333 list_del(&mr->fmr.fm_mr->list); 322 list_del(&mr->fmr.fm_mr->list);
334 fmr_op_recover_mr(mr); 323 rpcrdma_mr_recycle(mr);
335 } 324 }
336} 325}
337 326
@@ -339,7 +328,6 @@ const struct rpcrdma_memreg_ops rpcrdma_fmr_memreg_ops = {
339 .ro_map = fmr_op_map, 328 .ro_map = fmr_op_map,
340 .ro_send = fmr_op_send, 329 .ro_send = fmr_op_send,
341 .ro_unmap_sync = fmr_op_unmap_sync, 330 .ro_unmap_sync = fmr_op_unmap_sync,
342 .ro_recover_mr = fmr_op_recover_mr,
343 .ro_open = fmr_op_open, 331 .ro_open = fmr_op_open,
344 .ro_maxpages = fmr_op_maxpages, 332 .ro_maxpages = fmr_op_maxpages,
345 .ro_init_mr = fmr_op_init_mr, 333 .ro_init_mr = fmr_op_init_mr,
diff --git a/net/sunrpc/xprtrdma/frwr_ops.c b/net/sunrpc/xprtrdma/frwr_ops.c
index 1cc4db515c85..6594627e3c7d 100644
--- a/net/sunrpc/xprtrdma/frwr_ops.c
+++ b/net/sunrpc/xprtrdma/frwr_ops.c
@@ -97,6 +97,44 @@ out_not_supported:
97 return false; 97 return false;
98} 98}
99 99
100static void
101frwr_op_release_mr(struct rpcrdma_mr *mr)
102{
103 int rc;
104
105 rc = ib_dereg_mr(mr->frwr.fr_mr);
106 if (rc)
107 pr_err("rpcrdma: final ib_dereg_mr for %p returned %i\n",
108 mr, rc);
109 kfree(mr->mr_sg);
110 kfree(mr);
111}
112
113/* MRs are dynamically allocated, so simply clean up and release the MR.
114 * A replacement MR will subsequently be allocated on demand.
115 */
116static void
117frwr_mr_recycle_worker(struct work_struct *work)
118{
119 struct rpcrdma_mr *mr = container_of(work, struct rpcrdma_mr, mr_recycle);
120 enum rpcrdma_frwr_state state = mr->frwr.fr_state;
121 struct rpcrdma_xprt *r_xprt = mr->mr_xprt;
122
123 trace_xprtrdma_mr_recycle(mr);
124
125 if (state != FRWR_FLUSHED_LI) {
126 trace_xprtrdma_dma_unmap(mr);
127 ib_dma_unmap_sg(r_xprt->rx_ia.ri_device,
128 mr->mr_sg, mr->mr_nents, mr->mr_dir);
129 }
130
131 spin_lock(&r_xprt->rx_buf.rb_mrlock);
132 list_del(&mr->mr_all);
133 r_xprt->rx_stats.mrs_recycled++;
134 spin_unlock(&r_xprt->rx_buf.rb_mrlock);
135 frwr_op_release_mr(mr);
136}
137
100static int 138static int
101frwr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr) 139frwr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr)
102{ 140{
@@ -113,6 +151,7 @@ frwr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr)
113 goto out_list_err; 151 goto out_list_err;
114 152
115 INIT_LIST_HEAD(&mr->mr_list); 153 INIT_LIST_HEAD(&mr->mr_list);
154 INIT_WORK(&mr->mr_recycle, frwr_mr_recycle_worker);
116 sg_init_table(mr->mr_sg, depth); 155 sg_init_table(mr->mr_sg, depth);
117 init_completion(&frwr->fr_linv_done); 156 init_completion(&frwr->fr_linv_done);
118 return 0; 157 return 0;
@@ -131,79 +170,6 @@ out_list_err:
131 return rc; 170 return rc;
132} 171}
133 172
134static void
135frwr_op_release_mr(struct rpcrdma_mr *mr)
136{
137 int rc;
138
139 rc = ib_dereg_mr(mr->frwr.fr_mr);
140 if (rc)
141 pr_err("rpcrdma: final ib_dereg_mr for %p returned %i\n",
142 mr, rc);
143 kfree(mr->mr_sg);
144 kfree(mr);
145}
146
147static int
148__frwr_mr_reset(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr)
149{
150 struct rpcrdma_frwr *frwr = &mr->frwr;
151 int rc;
152
153 rc = ib_dereg_mr(frwr->fr_mr);
154 if (rc) {
155 pr_warn("rpcrdma: ib_dereg_mr status %d, frwr %p orphaned\n",
156 rc, mr);
157 return rc;
158 }
159
160 frwr->fr_mr = ib_alloc_mr(ia->ri_pd, ia->ri_mrtype,
161 ia->ri_max_frwr_depth);
162 if (IS_ERR(frwr->fr_mr)) {
163 pr_warn("rpcrdma: ib_alloc_mr status %ld, frwr %p orphaned\n",
164 PTR_ERR(frwr->fr_mr), mr);
165 return PTR_ERR(frwr->fr_mr);
166 }
167
168 dprintk("RPC: %s: recovered FRWR %p\n", __func__, frwr);
169 frwr->fr_state = FRWR_IS_INVALID;
170 return 0;
171}
172
173/* Reset of a single FRWR. Generate a fresh rkey by replacing the MR.
174 */
175static void
176frwr_op_recover_mr(struct rpcrdma_mr *mr)
177{
178 enum rpcrdma_frwr_state state = mr->frwr.fr_state;
179 struct rpcrdma_xprt *r_xprt = mr->mr_xprt;
180 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
181 int rc;
182
183 rc = __frwr_mr_reset(ia, mr);
184 if (state != FRWR_FLUSHED_LI) {
185 trace_xprtrdma_dma_unmap(mr);
186 ib_dma_unmap_sg(ia->ri_device,
187 mr->mr_sg, mr->mr_nents, mr->mr_dir);
188 }
189 if (rc)
190 goto out_release;
191
192 rpcrdma_mr_put(mr);
193 r_xprt->rx_stats.mrs_recovered++;
194 return;
195
196out_release:
197 pr_err("rpcrdma: FRWR reset failed %d, %p released\n", rc, mr);
198 r_xprt->rx_stats.mrs_orphaned++;
199
200 spin_lock(&r_xprt->rx_buf.rb_mrlock);
201 list_del(&mr->mr_all);
202 spin_unlock(&r_xprt->rx_buf.rb_mrlock);
203
204 frwr_op_release_mr(mr);
205}
206
207/* On success, sets: 173/* On success, sets:
208 * ep->rep_attr.cap.max_send_wr 174 * ep->rep_attr.cap.max_send_wr
209 * ep->rep_attr.cap.max_recv_wr 175 * ep->rep_attr.cap.max_recv_wr
@@ -385,7 +351,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
385 mr = NULL; 351 mr = NULL;
386 do { 352 do {
387 if (mr) 353 if (mr)
388 rpcrdma_mr_defer_recovery(mr); 354 rpcrdma_mr_recycle(mr);
389 mr = rpcrdma_mr_get(r_xprt); 355 mr = rpcrdma_mr_get(r_xprt);
390 if (!mr) 356 if (!mr)
391 return ERR_PTR(-EAGAIN); 357 return ERR_PTR(-EAGAIN);
@@ -452,7 +418,7 @@ out_dmamap_err:
452out_mapmr_err: 418out_mapmr_err:
453 pr_err("rpcrdma: failed to map mr %p (%d/%d)\n", 419 pr_err("rpcrdma: failed to map mr %p (%d/%d)\n",
454 frwr->fr_mr, n, mr->mr_nents); 420 frwr->fr_mr, n, mr->mr_nents);
455 rpcrdma_mr_defer_recovery(mr); 421 rpcrdma_mr_recycle(mr);
456 return ERR_PTR(-EIO); 422 return ERR_PTR(-EIO);
457} 423}
458 424
@@ -571,7 +537,7 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs)
571 if (bad_wr != first) 537 if (bad_wr != first)
572 wait_for_completion(&frwr->fr_linv_done); 538 wait_for_completion(&frwr->fr_linv_done);
573 if (rc) 539 if (rc)
574 goto reset_mrs; 540 goto out_release;
575 541
576 /* ORDER: Now DMA unmap all of the MRs, and return 542 /* ORDER: Now DMA unmap all of the MRs, and return
577 * them to the free MR list. 543 * them to the free MR list.
@@ -583,22 +549,21 @@ unmap:
583 } 549 }
584 return; 550 return;
585 551
586reset_mrs: 552out_release:
587 pr_err("rpcrdma: FRWR invalidate ib_post_send returned %i\n", rc); 553 pr_err("rpcrdma: FRWR invalidate ib_post_send returned %i\n", rc);
588 554
589 /* Find and reset the MRs in the LOCAL_INV WRs that did not 555 /* Unmap and release the MRs in the LOCAL_INV WRs that did not
590 * get posted. 556 * get posted.
591 */ 557 */
592 while (bad_wr) { 558 while (bad_wr) {
593 frwr = container_of(bad_wr, struct rpcrdma_frwr, 559 frwr = container_of(bad_wr, struct rpcrdma_frwr,
594 fr_invwr); 560 fr_invwr);
595 mr = container_of(frwr, struct rpcrdma_mr, frwr); 561 mr = container_of(frwr, struct rpcrdma_mr, frwr);
596
597 __frwr_mr_reset(ia, mr);
598
599 bad_wr = bad_wr->next; 562 bad_wr = bad_wr->next;
563
564 list_del(&mr->mr_list);
565 frwr_op_release_mr(mr);
600 } 566 }
601 goto unmap;
602} 567}
603 568
604const struct rpcrdma_memreg_ops rpcrdma_frwr_memreg_ops = { 569const struct rpcrdma_memreg_ops rpcrdma_frwr_memreg_ops = {
@@ -606,7 +571,6 @@ const struct rpcrdma_memreg_ops rpcrdma_frwr_memreg_ops = {
606 .ro_send = frwr_op_send, 571 .ro_send = frwr_op_send,
607 .ro_reminv = frwr_op_reminv, 572 .ro_reminv = frwr_op_reminv,
608 .ro_unmap_sync = frwr_op_unmap_sync, 573 .ro_unmap_sync = frwr_op_unmap_sync,
609 .ro_recover_mr = frwr_op_recover_mr,
610 .ro_open = frwr_op_open, 574 .ro_open = frwr_op_open,
611 .ro_maxpages = frwr_op_maxpages, 575 .ro_maxpages = frwr_op_maxpages,
612 .ro_init_mr = frwr_op_init_mr, 576 .ro_init_mr = frwr_op_init_mr,
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
index 15edc050ca93..228aee851667 100644
--- a/net/sunrpc/xprtrdma/rpc_rdma.c
+++ b/net/sunrpc/xprtrdma/rpc_rdma.c
@@ -803,7 +803,7 @@ rpcrdma_marshal_req(struct rpcrdma_xprt *r_xprt, struct rpc_rqst *rqst)
803 struct rpcrdma_mr *mr; 803 struct rpcrdma_mr *mr;
804 804
805 mr = rpcrdma_mr_pop(&req->rl_registered); 805 mr = rpcrdma_mr_pop(&req->rl_registered);
806 rpcrdma_mr_defer_recovery(mr); 806 rpcrdma_mr_recycle(mr);
807 } 807 }
808 808
809 /* This implementation supports the following combinations 809 /* This implementation supports the following combinations
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index 98cbc7b060ba..3ae73e6a5c93 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -792,7 +792,7 @@ void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
792 r_xprt->rx_stats.bad_reply_count, 792 r_xprt->rx_stats.bad_reply_count,
793 r_xprt->rx_stats.nomsg_call_count); 793 r_xprt->rx_stats.nomsg_call_count);
794 seq_printf(seq, "%lu %lu %lu %lu %lu %lu\n", 794 seq_printf(seq, "%lu %lu %lu %lu %lu %lu\n",
795 r_xprt->rx_stats.mrs_recovered, 795 r_xprt->rx_stats.mrs_recycled,
796 r_xprt->rx_stats.mrs_orphaned, 796 r_xprt->rx_stats.mrs_orphaned,
797 r_xprt->rx_stats.mrs_allocated, 797 r_xprt->rx_stats.mrs_allocated,
798 r_xprt->rx_stats.local_inv_needed, 798 r_xprt->rx_stats.local_inv_needed,
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 5625a5089f96..88fe75e6d41a 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -978,39 +978,6 @@ rpcrdma_sendctx_put_locked(struct rpcrdma_sendctx *sc)
978} 978}
979 979
980static void 980static void
981rpcrdma_mr_recovery_worker(struct work_struct *work)
982{
983 struct rpcrdma_buffer *buf = container_of(work, struct rpcrdma_buffer,
984 rb_recovery_worker.work);
985 struct rpcrdma_mr *mr;
986
987 spin_lock(&buf->rb_recovery_lock);
988 while (!list_empty(&buf->rb_stale_mrs)) {
989 mr = rpcrdma_mr_pop(&buf->rb_stale_mrs);
990 spin_unlock(&buf->rb_recovery_lock);
991
992 trace_xprtrdma_recover_mr(mr);
993 mr->mr_xprt->rx_ia.ri_ops->ro_recover_mr(mr);
994
995 spin_lock(&buf->rb_recovery_lock);
996 }
997 spin_unlock(&buf->rb_recovery_lock);
998}
999
1000void
1001rpcrdma_mr_defer_recovery(struct rpcrdma_mr *mr)
1002{
1003 struct rpcrdma_xprt *r_xprt = mr->mr_xprt;
1004 struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1005
1006 spin_lock(&buf->rb_recovery_lock);
1007 rpcrdma_mr_push(mr, &buf->rb_stale_mrs);
1008 spin_unlock(&buf->rb_recovery_lock);
1009
1010 schedule_delayed_work(&buf->rb_recovery_worker, 0);
1011}
1012
1013static void
1014rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt) 981rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt)
1015{ 982{
1016 struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 983 struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
@@ -1142,14 +1109,10 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
1142 buf->rb_bc_srv_max_requests = 0; 1109 buf->rb_bc_srv_max_requests = 0;
1143 spin_lock_init(&buf->rb_mrlock); 1110 spin_lock_init(&buf->rb_mrlock);
1144 spin_lock_init(&buf->rb_lock); 1111 spin_lock_init(&buf->rb_lock);
1145 spin_lock_init(&buf->rb_recovery_lock);
1146 INIT_LIST_HEAD(&buf->rb_mrs); 1112 INIT_LIST_HEAD(&buf->rb_mrs);
1147 INIT_LIST_HEAD(&buf->rb_all); 1113 INIT_LIST_HEAD(&buf->rb_all);
1148 INIT_LIST_HEAD(&buf->rb_stale_mrs);
1149 INIT_DELAYED_WORK(&buf->rb_refresh_worker, 1114 INIT_DELAYED_WORK(&buf->rb_refresh_worker,
1150 rpcrdma_mr_refresh_worker); 1115 rpcrdma_mr_refresh_worker);
1151 INIT_DELAYED_WORK(&buf->rb_recovery_worker,
1152 rpcrdma_mr_recovery_worker);
1153 1116
1154 rpcrdma_mrs_create(r_xprt); 1117 rpcrdma_mrs_create(r_xprt);
1155 1118
@@ -1233,7 +1196,6 @@ rpcrdma_mrs_destroy(struct rpcrdma_buffer *buf)
1233void 1196void
1234rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) 1197rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
1235{ 1198{
1236 cancel_delayed_work_sync(&buf->rb_recovery_worker);
1237 cancel_delayed_work_sync(&buf->rb_refresh_worker); 1199 cancel_delayed_work_sync(&buf->rb_refresh_worker);
1238 1200
1239 rpcrdma_sendctxs_destroy(buf); 1201 rpcrdma_sendctxs_destroy(buf);
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
index 2ca14f7c2d51..eae21668e692 100644
--- a/net/sunrpc/xprtrdma/xprt_rdma.h
+++ b/net/sunrpc/xprtrdma/xprt_rdma.h
@@ -280,6 +280,7 @@ struct rpcrdma_mr {
280 u32 mr_handle; 280 u32 mr_handle;
281 u32 mr_length; 281 u32 mr_length;
282 u64 mr_offset; 282 u64 mr_offset;
283 struct work_struct mr_recycle;
283 struct list_head mr_all; 284 struct list_head mr_all;
284}; 285};
285 286
@@ -411,9 +412,6 @@ struct rpcrdma_buffer {
411 412
412 u32 rb_bc_max_requests; 413 u32 rb_bc_max_requests;
413 414
414 spinlock_t rb_recovery_lock; /* protect rb_stale_mrs */
415 struct list_head rb_stale_mrs;
416 struct delayed_work rb_recovery_worker;
417 struct delayed_work rb_refresh_worker; 415 struct delayed_work rb_refresh_worker;
418}; 416};
419#define rdmab_to_ia(b) (&container_of((b), struct rpcrdma_xprt, rx_buf)->rx_ia) 417#define rdmab_to_ia(b) (&container_of((b), struct rpcrdma_xprt, rx_buf)->rx_ia)
@@ -452,7 +450,7 @@ struct rpcrdma_stats {
452 unsigned long hardway_register_count; 450 unsigned long hardway_register_count;
453 unsigned long failed_marshal_count; 451 unsigned long failed_marshal_count;
454 unsigned long bad_reply_count; 452 unsigned long bad_reply_count;
455 unsigned long mrs_recovered; 453 unsigned long mrs_recycled;
456 unsigned long mrs_orphaned; 454 unsigned long mrs_orphaned;
457 unsigned long mrs_allocated; 455 unsigned long mrs_allocated;
458 unsigned long empty_sendctx_q; 456 unsigned long empty_sendctx_q;
@@ -481,7 +479,6 @@ struct rpcrdma_memreg_ops {
481 struct list_head *mrs); 479 struct list_head *mrs);
482 void (*ro_unmap_sync)(struct rpcrdma_xprt *, 480 void (*ro_unmap_sync)(struct rpcrdma_xprt *,
483 struct list_head *); 481 struct list_head *);
484 void (*ro_recover_mr)(struct rpcrdma_mr *mr);
485 int (*ro_open)(struct rpcrdma_ia *, 482 int (*ro_open)(struct rpcrdma_ia *,
486 struct rpcrdma_ep *, 483 struct rpcrdma_ep *,
487 struct rpcrdma_create_data_internal *); 484 struct rpcrdma_create_data_internal *);
@@ -578,7 +575,12 @@ struct rpcrdma_sendctx *rpcrdma_sendctx_get_locked(struct rpcrdma_buffer *buf);
578struct rpcrdma_mr *rpcrdma_mr_get(struct rpcrdma_xprt *r_xprt); 575struct rpcrdma_mr *rpcrdma_mr_get(struct rpcrdma_xprt *r_xprt);
579void rpcrdma_mr_put(struct rpcrdma_mr *mr); 576void rpcrdma_mr_put(struct rpcrdma_mr *mr);
580void rpcrdma_mr_unmap_and_put(struct rpcrdma_mr *mr); 577void rpcrdma_mr_unmap_and_put(struct rpcrdma_mr *mr);
581void rpcrdma_mr_defer_recovery(struct rpcrdma_mr *mr); 578
579static inline void
580rpcrdma_mr_recycle(struct rpcrdma_mr *mr)
581{
582 schedule_work(&mr->mr_recycle);
583}
582 584
583struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *); 585struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *);
584void rpcrdma_buffer_put(struct rpcrdma_req *); 586void rpcrdma_buffer_put(struct rpcrdma_req *);