diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2017-12-14 20:56:09 -0500 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2018-01-16 11:19:41 -0500 |
commit | d698c4a02ee02053bbebe051322ff427a2dad56a (patch) | |
tree | 61e79e7e1319fa679eef870f60fb7dad0f111caa | |
parent | 03ac1a76ce5e5a6052a421e1d6a5c97778e88a8c (diff) |
xprtrdma: Fix backchannel allocation of extra rpcrdma_reps
The backchannel code uses rpcrdma_recv_buffer_put to add new reps
to the free rep list. This also decrements rb_recv_count, which
spoofs the receive overrun logic in rpcrdma_buffer_get_rep.
Commit 9b06688bc3b9 ("xprtrdma: Fix additional uses of
spin_lock_irqsave(rb_lock)") replaced the original open-coded
list_add with a call to rpcrdma_recv_buffer_put(), but then a year
later, commit 05c974669ece ("xprtrdma: Fix receive buffer
accounting") added rep accounting to rpcrdma_recv_buffer_put.
It was an oversight to let the backchannel continue to use this
function.
The fix this, let's combine the "add to free list" logic with
rpcrdma_create_rep.
Also, do not allocate RPCRDMA_MAX_BC_REQUESTS rpcrdma_reps in
rpcrdma_buffer_create and then allocate additional rpcrdma_reps in
rpcrdma_bc_setup_reps. Allocating the extra reps during backchannel
set-up is sufficient.
Fixes: 05c974669ece ("xprtrdma: Fix receive buffer accounting")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r-- | net/sunrpc/xprtrdma/backchannel.c | 12 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/verbs.c | 32 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/xprt_rdma.h | 2 |
3 files changed, 22 insertions, 24 deletions
diff --git a/net/sunrpc/xprtrdma/backchannel.c b/net/sunrpc/xprtrdma/backchannel.c index 8b818bb3518a..256c67b433c1 100644 --- a/net/sunrpc/xprtrdma/backchannel.c +++ b/net/sunrpc/xprtrdma/backchannel.c | |||
@@ -74,21 +74,13 @@ out_fail: | |||
74 | static int rpcrdma_bc_setup_reps(struct rpcrdma_xprt *r_xprt, | 74 | static int rpcrdma_bc_setup_reps(struct rpcrdma_xprt *r_xprt, |
75 | unsigned int count) | 75 | unsigned int count) |
76 | { | 76 | { |
77 | struct rpcrdma_rep *rep; | ||
78 | int rc = 0; | 77 | int rc = 0; |
79 | 78 | ||
80 | while (count--) { | 79 | while (count--) { |
81 | rep = rpcrdma_create_rep(r_xprt); | 80 | rc = rpcrdma_create_rep(r_xprt); |
82 | if (IS_ERR(rep)) { | 81 | if (rc) |
83 | pr_err("RPC: %s: reply buffer alloc failed\n", | ||
84 | __func__); | ||
85 | rc = PTR_ERR(rep); | ||
86 | break; | 82 | break; |
87 | } | ||
88 | |||
89 | rpcrdma_recv_buffer_put(rep); | ||
90 | } | 83 | } |
91 | |||
92 | return rc; | 84 | return rc; |
93 | } | 85 | } |
94 | 86 | ||
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 8607c029c0dd..6eecd9714051 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
@@ -1093,10 +1093,17 @@ rpcrdma_create_req(struct rpcrdma_xprt *r_xprt) | |||
1093 | return req; | 1093 | return req; |
1094 | } | 1094 | } |
1095 | 1095 | ||
1096 | struct rpcrdma_rep * | 1096 | /** |
1097 | * rpcrdma_create_rep - Allocate an rpcrdma_rep object | ||
1098 | * @r_xprt: controlling transport | ||
1099 | * | ||
1100 | * Returns 0 on success or a negative errno on failure. | ||
1101 | */ | ||
1102 | int | ||
1097 | rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt) | 1103 | rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt) |
1098 | { | 1104 | { |
1099 | struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data; | 1105 | struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data; |
1106 | struct rpcrdma_buffer *buf = &r_xprt->rx_buf; | ||
1100 | struct rpcrdma_rep *rep; | 1107 | struct rpcrdma_rep *rep; |
1101 | int rc; | 1108 | int rc; |
1102 | 1109 | ||
@@ -1121,12 +1128,18 @@ rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt) | |||
1121 | rep->rr_recv_wr.wr_cqe = &rep->rr_cqe; | 1128 | rep->rr_recv_wr.wr_cqe = &rep->rr_cqe; |
1122 | rep->rr_recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov; | 1129 | rep->rr_recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov; |
1123 | rep->rr_recv_wr.num_sge = 1; | 1130 | rep->rr_recv_wr.num_sge = 1; |
1124 | return rep; | 1131 | |
1132 | spin_lock(&buf->rb_lock); | ||
1133 | list_add(&rep->rr_list, &buf->rb_recv_bufs); | ||
1134 | spin_unlock(&buf->rb_lock); | ||
1135 | return 0; | ||
1125 | 1136 | ||
1126 | out_free: | 1137 | out_free: |
1127 | kfree(rep); | 1138 | kfree(rep); |
1128 | out: | 1139 | out: |
1129 | return ERR_PTR(rc); | 1140 | dprintk("RPC: %s: reply buffer %d alloc failed\n", |
1141 | __func__, rc); | ||
1142 | return rc; | ||
1130 | } | 1143 | } |
1131 | 1144 | ||
1132 | int | 1145 | int |
@@ -1167,17 +1180,10 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) | |||
1167 | } | 1180 | } |
1168 | 1181 | ||
1169 | INIT_LIST_HEAD(&buf->rb_recv_bufs); | 1182 | INIT_LIST_HEAD(&buf->rb_recv_bufs); |
1170 | for (i = 0; i < buf->rb_max_requests + RPCRDMA_MAX_BC_REQUESTS; i++) { | 1183 | for (i = 0; i <= buf->rb_max_requests; i++) { |
1171 | struct rpcrdma_rep *rep; | 1184 | rc = rpcrdma_create_rep(r_xprt); |
1172 | 1185 | if (rc) | |
1173 | rep = rpcrdma_create_rep(r_xprt); | ||
1174 | if (IS_ERR(rep)) { | ||
1175 | dprintk("RPC: %s: reply buffer %d alloc failed\n", | ||
1176 | __func__, i); | ||
1177 | rc = PTR_ERR(rep); | ||
1178 | goto out; | 1186 | goto out; |
1179 | } | ||
1180 | list_add(&rep->rr_list, &buf->rb_recv_bufs); | ||
1181 | } | 1187 | } |
1182 | 1188 | ||
1183 | rc = rpcrdma_sendctxs_create(r_xprt); | 1189 | rc = rpcrdma_sendctxs_create(r_xprt); |
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index 1342f743f1c4..3b63e61feae2 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h | |||
@@ -564,8 +564,8 @@ int rpcrdma_ep_post_recv(struct rpcrdma_ia *, struct rpcrdma_rep *); | |||
564 | * Buffer calls - xprtrdma/verbs.c | 564 | * Buffer calls - xprtrdma/verbs.c |
565 | */ | 565 | */ |
566 | struct rpcrdma_req *rpcrdma_create_req(struct rpcrdma_xprt *); | 566 | struct rpcrdma_req *rpcrdma_create_req(struct rpcrdma_xprt *); |
567 | struct rpcrdma_rep *rpcrdma_create_rep(struct rpcrdma_xprt *); | ||
568 | void rpcrdma_destroy_req(struct rpcrdma_req *); | 567 | void rpcrdma_destroy_req(struct rpcrdma_req *); |
568 | int rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt); | ||
569 | int rpcrdma_buffer_create(struct rpcrdma_xprt *); | 569 | int rpcrdma_buffer_create(struct rpcrdma_xprt *); |
570 | void rpcrdma_buffer_destroy(struct rpcrdma_buffer *); | 570 | void rpcrdma_buffer_destroy(struct rpcrdma_buffer *); |
571 | struct rpcrdma_sendctx *rpcrdma_sendctx_get_locked(struct rpcrdma_buffer *buf); | 571 | struct rpcrdma_sendctx *rpcrdma_sendctx_get_locked(struct rpcrdma_buffer *buf); |