diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-07-17 16:01:03 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-07-17 16:01:03 -0400 |
| commit | 43cedbf0e8dfb9c5610eb7985d5f21263e313802 (patch) | |
| tree | 7758630292b6a276a3db72e63803ddc02c0a4444 | |
| parent | f85ef69ce08bc2209858135328335f668ba35bdb (diff) | |
SUNRPC: Ensure that we grab the XPRT_LOCK before calling xprt_alloc_slot
This throttles the allocation of new slots when the socket is busy
reconnecting and/or is out of buffer space.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
| -rw-r--r-- | include/linux/sunrpc/xprt.h | 6 | ||||
| -rw-r--r-- | net/sunrpc/xprt.c | 66 | ||||
| -rw-r--r-- | net/sunrpc/xprtrdma/transport.c | 5 | ||||
| -rw-r--r-- | net/sunrpc/xprtsock.c | 2 |
4 files changed, 49 insertions, 30 deletions
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 217b0206581b..a876882fb923 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -111,7 +111,7 @@ struct rpc_rqst { | |||
| 111 | 111 | ||
| 112 | struct rpc_xprt_ops { | 112 | struct rpc_xprt_ops { |
| 113 | void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); | 113 | void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); |
| 114 | int (*reserve_xprt)(struct rpc_task *task); | 114 | int (*reserve_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); |
| 115 | void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); | 115 | void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); |
| 116 | void (*rpcbind)(struct rpc_task *task); | 116 | void (*rpcbind)(struct rpc_task *task); |
| 117 | void (*set_port)(struct rpc_xprt *xprt, unsigned short port); | 117 | void (*set_port)(struct rpc_xprt *xprt, unsigned short port); |
| @@ -271,8 +271,8 @@ struct xprt_class { | |||
| 271 | struct rpc_xprt *xprt_create_transport(struct xprt_create *args); | 271 | struct rpc_xprt *xprt_create_transport(struct xprt_create *args); |
| 272 | void xprt_connect(struct rpc_task *task); | 272 | void xprt_connect(struct rpc_task *task); |
| 273 | void xprt_reserve(struct rpc_task *task); | 273 | void xprt_reserve(struct rpc_task *task); |
| 274 | int xprt_reserve_xprt(struct rpc_task *task); | 274 | int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task); |
| 275 | int xprt_reserve_xprt_cong(struct rpc_task *task); | 275 | int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); |
| 276 | int xprt_prepare_transmit(struct rpc_task *task); | 276 | int xprt_prepare_transmit(struct rpc_task *task); |
| 277 | void xprt_transmit(struct rpc_task *task); | 277 | void xprt_transmit(struct rpc_task *task); |
| 278 | void xprt_end_transmit(struct rpc_task *task); | 278 | void xprt_end_transmit(struct rpc_task *task); |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index fbdbaf2cd58d..ccd583a46ff6 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -191,10 +191,9 @@ EXPORT_SYMBOL_GPL(xprt_load_transport); | |||
| 191 | * transport connects from colliding with writes. No congestion control | 191 | * transport connects from colliding with writes. No congestion control |
| 192 | * is provided. | 192 | * is provided. |
| 193 | */ | 193 | */ |
| 194 | int xprt_reserve_xprt(struct rpc_task *task) | 194 | int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) |
| 195 | { | 195 | { |
| 196 | struct rpc_rqst *req = task->tk_rqstp; | 196 | struct rpc_rqst *req = task->tk_rqstp; |
| 197 | struct rpc_xprt *xprt = req->rq_xprt; | ||
| 198 | 197 | ||
| 199 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { | 198 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { |
| 200 | if (task == xprt->snd_task) | 199 | if (task == xprt->snd_task) |
| @@ -202,8 +201,10 @@ int xprt_reserve_xprt(struct rpc_task *task) | |||
| 202 | goto out_sleep; | 201 | goto out_sleep; |
| 203 | } | 202 | } |
| 204 | xprt->snd_task = task; | 203 | xprt->snd_task = task; |
| 205 | req->rq_bytes_sent = 0; | 204 | if (req != NULL) { |
| 206 | req->rq_ntrans++; | 205 | req->rq_bytes_sent = 0; |
| 206 | req->rq_ntrans++; | ||
| 207 | } | ||
| 207 | 208 | ||
| 208 | return 1; | 209 | return 1; |
| 209 | 210 | ||
| @@ -212,7 +213,7 @@ out_sleep: | |||
| 212 | task->tk_pid, xprt); | 213 | task->tk_pid, xprt); |
| 213 | task->tk_timeout = 0; | 214 | task->tk_timeout = 0; |
| 214 | task->tk_status = -EAGAIN; | 215 | task->tk_status = -EAGAIN; |
| 215 | if (req->rq_ntrans) | 216 | if (req != NULL && req->rq_ntrans) |
| 216 | rpc_sleep_on(&xprt->resend, task, NULL); | 217 | rpc_sleep_on(&xprt->resend, task, NULL); |
| 217 | else | 218 | else |
| 218 | rpc_sleep_on(&xprt->sending, task, NULL); | 219 | rpc_sleep_on(&xprt->sending, task, NULL); |
| @@ -239,9 +240,8 @@ static void xprt_clear_locked(struct rpc_xprt *xprt) | |||
| 239 | * integrated into the decision of whether a request is allowed to be | 240 | * integrated into the decision of whether a request is allowed to be |
| 240 | * woken up and given access to the transport. | 241 | * woken up and given access to the transport. |
| 241 | */ | 242 | */ |
| 242 | int xprt_reserve_xprt_cong(struct rpc_task *task) | 243 | int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) |
| 243 | { | 244 | { |
| 244 | struct rpc_xprt *xprt = task->tk_xprt; | ||
| 245 | struct rpc_rqst *req = task->tk_rqstp; | 245 | struct rpc_rqst *req = task->tk_rqstp; |
| 246 | 246 | ||
| 247 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { | 247 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { |
| @@ -249,12 +249,14 @@ int xprt_reserve_xprt_cong(struct rpc_task *task) | |||
| 249 | return 1; | 249 | return 1; |
| 250 | goto out_sleep; | 250 | goto out_sleep; |
| 251 | } | 251 | } |
| 252 | if (req == NULL) { | ||
| 253 | xprt->snd_task = task; | ||
| 254 | return 1; | ||
| 255 | } | ||
| 252 | if (__xprt_get_cong(xprt, task)) { | 256 | if (__xprt_get_cong(xprt, task)) { |
| 253 | xprt->snd_task = task; | 257 | xprt->snd_task = task; |
| 254 | if (req) { | 258 | req->rq_bytes_sent = 0; |
| 255 | req->rq_bytes_sent = 0; | 259 | req->rq_ntrans++; |
| 256 | req->rq_ntrans++; | ||
| 257 | } | ||
| 258 | return 1; | 260 | return 1; |
| 259 | } | 261 | } |
| 260 | xprt_clear_locked(xprt); | 262 | xprt_clear_locked(xprt); |
| @@ -262,7 +264,7 @@ out_sleep: | |||
| 262 | dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); | 264 | dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); |
| 263 | task->tk_timeout = 0; | 265 | task->tk_timeout = 0; |
| 264 | task->tk_status = -EAGAIN; | 266 | task->tk_status = -EAGAIN; |
| 265 | if (req && req->rq_ntrans) | 267 | if (req != NULL && req->rq_ntrans) |
| 266 | rpc_sleep_on(&xprt->resend, task, NULL); | 268 | rpc_sleep_on(&xprt->resend, task, NULL); |
| 267 | else | 269 | else |
| 268 | rpc_sleep_on(&xprt->sending, task, NULL); | 270 | rpc_sleep_on(&xprt->sending, task, NULL); |
| @@ -275,7 +277,7 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) | |||
| 275 | int retval; | 277 | int retval; |
| 276 | 278 | ||
| 277 | spin_lock_bh(&xprt->transport_lock); | 279 | spin_lock_bh(&xprt->transport_lock); |
| 278 | retval = xprt->ops->reserve_xprt(task); | 280 | retval = xprt->ops->reserve_xprt(xprt, task); |
| 279 | spin_unlock_bh(&xprt->transport_lock); | 281 | spin_unlock_bh(&xprt->transport_lock); |
| 280 | return retval; | 282 | return retval; |
| 281 | } | 283 | } |
| @@ -291,7 +293,7 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt) | |||
| 291 | task = rpc_wake_up_next(&xprt->resend); | 293 | task = rpc_wake_up_next(&xprt->resend); |
| 292 | if (!task) { | 294 | if (!task) { |
| 293 | task = rpc_wake_up_next(&xprt->sending); | 295 | task = rpc_wake_up_next(&xprt->sending); |
| 294 | if (!task) | 296 | if (task == NULL) |
| 295 | goto out_unlock; | 297 | goto out_unlock; |
| 296 | } | 298 | } |
| 297 | 299 | ||
| @@ -310,6 +312,7 @@ out_unlock: | |||
| 310 | static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) | 312 | static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) |
| 311 | { | 313 | { |
| 312 | struct rpc_task *task; | 314 | struct rpc_task *task; |
| 315 | struct rpc_rqst *req; | ||
| 313 | 316 | ||
| 314 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) | 317 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) |
| 315 | return; | 318 | return; |
| @@ -318,16 +321,19 @@ static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) | |||
| 318 | task = rpc_wake_up_next(&xprt->resend); | 321 | task = rpc_wake_up_next(&xprt->resend); |
| 319 | if (!task) { | 322 | if (!task) { |
| 320 | task = rpc_wake_up_next(&xprt->sending); | 323 | task = rpc_wake_up_next(&xprt->sending); |
| 321 | if (!task) | 324 | if (task == NULL) |
| 322 | goto out_unlock; | 325 | goto out_unlock; |
| 323 | } | 326 | } |
| 327 | |||
| 328 | req = task->tk_rqstp; | ||
| 329 | if (req == NULL) { | ||
| 330 | xprt->snd_task = task; | ||
| 331 | return; | ||
| 332 | } | ||
| 324 | if (__xprt_get_cong(xprt, task)) { | 333 | if (__xprt_get_cong(xprt, task)) { |
| 325 | struct rpc_rqst *req = task->tk_rqstp; | ||
| 326 | xprt->snd_task = task; | 334 | xprt->snd_task = task; |
| 327 | if (req) { | 335 | req->rq_bytes_sent = 0; |
| 328 | req->rq_bytes_sent = 0; | 336 | req->rq_ntrans++; |
| 329 | req->rq_ntrans++; | ||
| 330 | } | ||
| 331 | return; | 337 | return; |
| 332 | } | 338 | } |
| 333 | out_unlock: | 339 | out_unlock: |
| @@ -852,7 +858,7 @@ int xprt_prepare_transmit(struct rpc_task *task) | |||
| 852 | err = req->rq_reply_bytes_recvd; | 858 | err = req->rq_reply_bytes_recvd; |
| 853 | goto out_unlock; | 859 | goto out_unlock; |
| 854 | } | 860 | } |
| 855 | if (!xprt->ops->reserve_xprt(task)) | 861 | if (!xprt->ops->reserve_xprt(xprt, task)) |
| 856 | err = -EAGAIN; | 862 | err = -EAGAIN; |
| 857 | out_unlock: | 863 | out_unlock: |
| 858 | spin_unlock_bh(&xprt->transport_lock); | 864 | spin_unlock_bh(&xprt->transport_lock); |
| @@ -933,8 +939,6 @@ static void xprt_alloc_slot(struct rpc_task *task) | |||
| 933 | struct rpc_xprt *xprt = task->tk_xprt; | 939 | struct rpc_xprt *xprt = task->tk_xprt; |
