diff options
Diffstat (limited to 'net/sunrpc/xprt.c')
-rw-r--r-- | net/sunrpc/xprt.c | 77 |
1 files changed, 63 insertions, 14 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 2d1e8b83dd68..e92ea99dd318 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -153,14 +153,42 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) | |||
153 | return retval; | 153 | return retval; |
154 | } | 154 | } |
155 | 155 | ||
156 | |||
157 | static void __xprt_lock_write_next(struct rpc_xprt *xprt) | 156 | static void __xprt_lock_write_next(struct rpc_xprt *xprt) |
158 | { | 157 | { |
159 | struct rpc_task *task; | 158 | struct rpc_task *task; |
159 | struct rpc_rqst *req; | ||
160 | |||
161 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) | ||
162 | return; | ||
163 | |||
164 | task = rpc_wake_up_next(&xprt->resend); | ||
165 | if (!task) { | ||
166 | task = rpc_wake_up_next(&xprt->sending); | ||
167 | if (!task) | ||
168 | goto out_unlock; | ||
169 | } | ||
170 | |||
171 | req = task->tk_rqstp; | ||
172 | xprt->snd_task = task; | ||
173 | if (req) { | ||
174 | req->rq_bytes_sent = 0; | ||
175 | req->rq_ntrans++; | ||
176 | } | ||
177 | return; | ||
178 | |||
179 | out_unlock: | ||
180 | smp_mb__before_clear_bit(); | ||
181 | clear_bit(XPRT_LOCKED, &xprt->state); | ||
182 | smp_mb__after_clear_bit(); | ||
183 | } | ||
184 | |||
185 | static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) | ||
186 | { | ||
187 | struct rpc_task *task; | ||
160 | 188 | ||
161 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) | 189 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) |
162 | return; | 190 | return; |
163 | if (!xprt->nocong && RPCXPRT_CONGESTED(xprt)) | 191 | if (RPCXPRT_CONGESTED(xprt)) |
164 | goto out_unlock; | 192 | goto out_unlock; |
165 | task = rpc_wake_up_next(&xprt->resend); | 193 | task = rpc_wake_up_next(&xprt->resend); |
166 | if (!task) { | 194 | if (!task) { |
@@ -168,7 +196,7 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt) | |||
168 | if (!task) | 196 | if (!task) |
169 | goto out_unlock; | 197 | goto out_unlock; |
170 | } | 198 | } |
171 | if (xprt->nocong || __xprt_get_cong(xprt, task)) { | 199 | if (__xprt_get_cong(xprt, task)) { |
172 | struct rpc_rqst *req = task->tk_rqstp; | 200 | struct rpc_rqst *req = task->tk_rqstp; |
173 | xprt->snd_task = task; | 201 | xprt->snd_task = task; |
174 | if (req) { | 202 | if (req) { |
@@ -183,11 +211,14 @@ out_unlock: | |||
183 | smp_mb__after_clear_bit(); | 211 | smp_mb__after_clear_bit(); |
184 | } | 212 | } |
185 | 213 | ||
186 | /* | 214 | /** |
187 | * Releases the transport for use by other requests. | 215 | * xprt_release_xprt - allow other requests to use a transport |
216 | * @xprt: transport with other tasks potentially waiting | ||
217 | * @task: task that is releasing access to the transport | ||
218 | * | ||
219 | * Note that "task" can be NULL. No congestion control is provided. | ||
188 | */ | 220 | */ |
189 | static void | 221 | void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) |
190 | __xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) | ||
191 | { | 222 | { |
192 | if (xprt->snd_task == task) { | 223 | if (xprt->snd_task == task) { |
193 | xprt->snd_task = NULL; | 224 | xprt->snd_task = NULL; |
@@ -198,11 +229,29 @@ __xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) | |||
198 | } | 229 | } |
199 | } | 230 | } |
200 | 231 | ||
201 | static inline void | 232 | /** |
202 | xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) | 233 | * xprt_release_xprt_cong - allow other requests to use a transport |
234 | * @xprt: transport with other tasks potentially waiting | ||
235 | * @task: task that is releasing access to the transport | ||
236 | * | ||
237 | * Note that "task" can be NULL. Another task is awoken to use the | ||
238 | * transport if the transport's congestion window allows it. | ||
239 | */ | ||
240 | void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) | ||
241 | { | ||
242 | if (xprt->snd_task == task) { | ||
243 | xprt->snd_task = NULL; | ||
244 | smp_mb__before_clear_bit(); | ||
245 | clear_bit(XPRT_LOCKED, &xprt->state); | ||
246 | smp_mb__after_clear_bit(); | ||
247 | __xprt_lock_write_next_cong(xprt); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) | ||
203 | { | 252 | { |
204 | spin_lock_bh(&xprt->transport_lock); | 253 | spin_lock_bh(&xprt->transport_lock); |
205 | __xprt_release_write(xprt, task); | 254 | xprt->ops->release_xprt(xprt, task); |
206 | spin_unlock_bh(&xprt->transport_lock); | 255 | spin_unlock_bh(&xprt->transport_lock); |
207 | } | 256 | } |
208 | 257 | ||
@@ -237,7 +286,7 @@ __xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req) | |||
237 | return; | 286 | return; |
238 | req->rq_cong = 0; | 287 | req->rq_cong = 0; |
239 | xprt->cong -= RPC_CWNDSCALE; | 288 | xprt->cong -= RPC_CWNDSCALE; |
240 | __xprt_lock_write_next(xprt); | 289 | __xprt_lock_write_next_cong(xprt); |
241 | } | 290 | } |
242 | 291 | ||
243 | /* | 292 | /* |
@@ -256,7 +305,7 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, int result) | |||
256 | cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd; | 305 | cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd; |
257 | if (cwnd > RPC_MAXCWND(xprt)) | 306 | if (cwnd > RPC_MAXCWND(xprt)) |
258 | cwnd = RPC_MAXCWND(xprt); | 307 | cwnd = RPC_MAXCWND(xprt); |
259 | __xprt_lock_write_next(xprt); | 308 | __xprt_lock_write_next_cong(xprt); |
260 | } else if (result == -ETIMEDOUT) { | 309 | } else if (result == -ETIMEDOUT) { |
261 | cwnd >>= 1; | 310 | cwnd >>= 1; |
262 | if (cwnd < RPC_CWNDSCALE) | 311 | if (cwnd < RPC_CWNDSCALE) |
@@ -693,7 +742,7 @@ void xprt_transmit(struct rpc_task *task) | |||
693 | task->tk_status = -ENOTCONN; | 742 | task->tk_status = -ENOTCONN; |
694 | else if (!req->rq_received) | 743 | else if (!req->rq_received) |
695 | rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); | 744 | rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); |
696 | __xprt_release_write(xprt, task); | 745 | xprt->ops->release_xprt(xprt, task); |
697 | spin_unlock_bh(&xprt->transport_lock); | 746 | spin_unlock_bh(&xprt->transport_lock); |
698 | return; | 747 | return; |
699 | } | 748 | } |
@@ -792,7 +841,7 @@ void xprt_release(struct rpc_task *task) | |||
792 | if (!(req = task->tk_rqstp)) | 841 | if (!(req = task->tk_rqstp)) |
793 | return; | 842 | return; |
794 | spin_lock_bh(&xprt->transport_lock); | 843 | spin_lock_bh(&xprt->transport_lock); |
795 | __xprt_release_write(xprt, task); | 844 | xprt->ops->release_xprt(xprt, task); |
796 | __xprt_put_cong(xprt, req); | 845 | __xprt_put_cong(xprt, req); |
797 | if (!list_empty(&req->rq_list)) | 846 | if (!list_empty(&req->rq_list)) |
798 | list_del(&req->rq_list); | 847 | list_del(&req->rq_list); |