diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2018-10-01 14:25:25 -0400 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2018-10-02 15:48:12 -0400 |
commit | 61da886bf74e738995d359fa14d77f72d14cfb87 (patch) | |
tree | 2618cc1783b1cde279f0cb6bab4f687795fef935 /net | |
parent | c421ece68f6952d4cc48ee81ebfc61ef0b83ad3b (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.c | 124 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/frwr_ops.c | 130 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/rpc_rdma.c | 2 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/transport.c | 2 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/verbs.c | 38 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/xprt_rdma.h | 14 |
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 | ||
52 | static int | 52 | static void |
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 | ||
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 | */ | ||
103 | static void | 68 | static void |
104 | fmr_op_release_mr(struct rpcrdma_mr *mr) | 69 | fmr_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 | */ |
130 | static void | 92 | static void |
131 | fmr_op_recover_mr(struct rpcrdma_mr *mr) | 93 | fmr_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 | |||
147 | out_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 | ||
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 | |||
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 | ||
328 | out_reset: | 317 | out_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 | ||
100 | static void | ||
101 | frwr_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 | */ | ||
116 | static void | ||
117 | frwr_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 | |||
100 | static int | 138 | static int |
101 | frwr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr) | 139 | frwr_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 | ||
134 | static void | ||
135 | frwr_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 | |||
147 | static 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 | */ | ||
175 | static void | ||
176 | frwr_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 | |||
196 | out_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: | |||
452 | out_mapmr_err: | 418 | out_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 | ||
586 | reset_mrs: | 552 | out_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 | ||
604 | const struct rpcrdma_memreg_ops rpcrdma_frwr_memreg_ops = { | 569 | const 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 | ||
980 | static void | 980 | static void |
981 | rpcrdma_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 | |||
1000 | void | ||
1001 | rpcrdma_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 | |||
1013 | static void | ||
1014 | rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt) | 981 | rpcrdma_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) | |||
1233 | void | 1196 | void |
1234 | rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) | 1197 | rpcrdma_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); | |||
578 | struct rpcrdma_mr *rpcrdma_mr_get(struct rpcrdma_xprt *r_xprt); | 575 | struct rpcrdma_mr *rpcrdma_mr_get(struct rpcrdma_xprt *r_xprt); |
579 | void rpcrdma_mr_put(struct rpcrdma_mr *mr); | 576 | void rpcrdma_mr_put(struct rpcrdma_mr *mr); |
580 | void rpcrdma_mr_unmap_and_put(struct rpcrdma_mr *mr); | 577 | void rpcrdma_mr_unmap_and_put(struct rpcrdma_mr *mr); |
581 | void rpcrdma_mr_defer_recovery(struct rpcrdma_mr *mr); | 578 | |
579 | static inline void | ||
580 | rpcrdma_mr_recycle(struct rpcrdma_mr *mr) | ||
581 | { | ||
582 | schedule_work(&mr->mr_recycle); | ||
583 | } | ||
582 | 584 | ||
583 | struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *); | 585 | struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *); |
584 | void rpcrdma_buffer_put(struct rpcrdma_req *); | 586 | void rpcrdma_buffer_put(struct rpcrdma_req *); |