diff options
| -rw-r--r-- | include/linux/sunrpc/xprt.h | 3 | ||||
| -rw-r--r-- | net/sunrpc/xprt.c | 77 | ||||
| -rw-r--r-- | net/sunrpc/xprtsock.c | 2 |
3 files changed, 68 insertions, 14 deletions
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index eee1c6877851..86833b725bb5 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -133,6 +133,7 @@ struct rpc_xprt; | |||
| 133 | struct rpc_xprt_ops { | 133 | struct rpc_xprt_ops { |
| 134 | void (*set_buffer_size)(struct rpc_xprt *xprt); | 134 | void (*set_buffer_size)(struct rpc_xprt *xprt); |
| 135 | int (*reserve_xprt)(struct rpc_task *task); | 135 | int (*reserve_xprt)(struct rpc_task *task); |
| 136 | void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); | ||
| 136 | void (*connect)(struct rpc_task *task); | 137 | void (*connect)(struct rpc_task *task); |
| 137 | int (*send_request)(struct rpc_task *task); | 138 | int (*send_request)(struct rpc_task *task); |
| 138 | void (*set_retrans_timeout)(struct rpc_task *task); | 139 | void (*set_retrans_timeout)(struct rpc_task *task); |
| @@ -238,6 +239,8 @@ int xprt_reserve_xprt_cong(struct rpc_task *task); | |||
| 238 | int xprt_prepare_transmit(struct rpc_task *task); | 239 | int xprt_prepare_transmit(struct rpc_task *task); |
| 239 | void xprt_transmit(struct rpc_task *task); | 240 | void xprt_transmit(struct rpc_task *task); |
| 240 | int xprt_adjust_timeout(struct rpc_rqst *req); | 241 | int xprt_adjust_timeout(struct rpc_rqst *req); |
| 242 | void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task); | ||
| 243 | void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); | ||
| 241 | void xprt_release(struct rpc_task *task); | 244 | void xprt_release(struct rpc_task *task); |
| 242 | int xprt_destroy(struct rpc_xprt *xprt); | 245 | int xprt_destroy(struct rpc_xprt *xprt); |
| 243 | 246 | ||
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); |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index fc4fbe8ea346..8589c1ad55e3 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -1046,6 +1046,7 @@ static void xs_connect(struct rpc_task *task) | |||
| 1046 | static struct rpc_xprt_ops xs_udp_ops = { | 1046 | static struct rpc_xprt_ops xs_udp_ops = { |
| 1047 | .set_buffer_size = xs_udp_set_buffer_size, | 1047 | .set_buffer_size = xs_udp_set_buffer_size, |
| 1048 | .reserve_xprt = xprt_reserve_xprt_cong, | 1048 | .reserve_xprt = xprt_reserve_xprt_cong, |
| 1049 | .release_xprt = xprt_release_xprt_cong, | ||
| 1049 | .connect = xs_connect, | 1050 | .connect = xs_connect, |
| 1050 | .send_request = xs_udp_send_request, | 1051 | .send_request = xs_udp_send_request, |
| 1051 | .set_retrans_timeout = xprt_set_retrans_timeout_rtt, | 1052 | .set_retrans_timeout = xprt_set_retrans_timeout_rtt, |
| @@ -1056,6 +1057,7 @@ static struct rpc_xprt_ops xs_udp_ops = { | |||
| 1056 | static struct rpc_xprt_ops xs_tcp_ops = { | 1057 | static struct rpc_xprt_ops xs_tcp_ops = { |
| 1057 | .set_buffer_size = xs_tcp_set_buffer_size, | 1058 | .set_buffer_size = xs_tcp_set_buffer_size, |
| 1058 | .reserve_xprt = xprt_reserve_xprt, | 1059 | .reserve_xprt = xprt_reserve_xprt, |
| 1060 | .release_xprt = xprt_release_xprt, | ||
| 1059 | .connect = xs_connect, | 1061 | .connect = xs_connect, |
| 1060 | .send_request = xs_tcp_send_request, | 1062 | .send_request = xs_tcp_send_request, |
| 1061 | .set_retrans_timeout = xprt_set_retrans_timeout_def, | 1063 | .set_retrans_timeout = xprt_set_retrans_timeout_def, |
