diff options
| -rw-r--r-- | include/linux/sunrpc/xprt.h | 2 | ||||
| -rw-r--r-- | net/sunrpc/xprt.c | 4 | ||||
| -rw-r--r-- | net/sunrpc/xprtsock.c | 61 |
3 files changed, 44 insertions, 23 deletions
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index b3ff9a815e6f..8a0629abb86a 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -232,7 +232,7 @@ int xprt_unregister_transport(struct xprt_class *type); | |||
| 232 | void xprt_set_retrans_timeout_def(struct rpc_task *task); | 232 | void xprt_set_retrans_timeout_def(struct rpc_task *task); |
| 233 | void xprt_set_retrans_timeout_rtt(struct rpc_task *task); | 233 | void xprt_set_retrans_timeout_rtt(struct rpc_task *task); |
| 234 | void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); | 234 | void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); |
| 235 | void xprt_wait_for_buffer_space(struct rpc_task *task); | 235 | void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action); |
| 236 | void xprt_write_space(struct rpc_xprt *xprt); | 236 | void xprt_write_space(struct rpc_xprt *xprt); |
| 237 | void xprt_update_rtt(struct rpc_task *task); | 237 | void xprt_update_rtt(struct rpc_task *task); |
| 238 | void xprt_adjust_cwnd(struct rpc_task *task, int result); | 238 | void xprt_adjust_cwnd(struct rpc_task *task, int result); |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 85199c647022..3ba64f9f84ba 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -447,13 +447,13 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks); | |||
| 447 | * @task: task to be put to sleep | 447 | * @task: task to be put to sleep |
| 448 | * | 448 | * |
| 449 | */ | 449 | */ |
| 450 | void xprt_wait_for_buffer_space(struct rpc_task *task) | 450 | void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action) |
| 451 | { | 451 | { |
| 452 | struct rpc_rqst *req = task->tk_rqstp; | 452 | struct rpc_rqst *req = task->tk_rqstp; |
| 453 | struct rpc_xprt *xprt = req->rq_xprt; | 453 | struct rpc_xprt *xprt = req->rq_xprt; |
| 454 | 454 | ||
| 455 | task->tk_timeout = req->rq_timeout; | 455 | task->tk_timeout = req->rq_timeout; |
| 456 | rpc_sleep_on(&xprt->pending, task, NULL); | 456 | rpc_sleep_on(&xprt->pending, task, action); |
| 457 | } | 457 | } |
| 458 | EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space); | 458 | EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space); |
| 459 | 459 | ||
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 8bd3b0f73ac0..4c2462e2f2b2 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -516,6 +516,14 @@ out: | |||
| 516 | return sent; | 516 | return sent; |
| 517 | } | 517 | } |
| 518 | 518 | ||
| 519 | static void xs_nospace_callback(struct rpc_task *task) | ||
| 520 | { | ||
| 521 | struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt); | ||
| 522 | |||
| 523 | transport->inet->sk_write_pending--; | ||
| 524 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
| 525 | } | ||
| 526 | |||
| 519 | /** | 527 | /** |
| 520 | * xs_nospace - place task on wait queue if transmit was incomplete | 528 | * xs_nospace - place task on wait queue if transmit was incomplete |
| 521 | * @task: task to put to sleep | 529 | * @task: task to put to sleep |
| @@ -531,20 +539,27 @@ static void xs_nospace(struct rpc_task *task) | |||
| 531 | task->tk_pid, req->rq_slen - req->rq_bytes_sent, | 539 | task->tk_pid, req->rq_slen - req->rq_bytes_sent, |
| 532 | req->rq_slen); | 540 | req->rq_slen); |
| 533 | 541 | ||
| 534 | if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) { | 542 | /* Protect against races with write_space */ |
| 535 | /* Protect against races with write_space */ | 543 | spin_lock_bh(&xprt->transport_lock); |
| 536 | spin_lock_bh(&xprt->transport_lock); | 544 | |
| 537 | 545 | /* Don't race with disconnect */ | |
| 538 | /* Don't race with disconnect */ | 546 | if (xprt_connected(xprt)) { |
| 539 | if (!xprt_connected(xprt)) | 547 | if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) { |
| 540 | task->tk_status = -ENOTCONN; | 548 | /* |
| 541 | else if (test_bit(SOCK_NOSPACE, &transport->sock->flags)) | 549 | * Notify TCP that we're limited by the application |
| 542 | xprt_wait_for_buffer_space(task); | 550 | * window size |
| 551 | */ | ||
| 552 | set_bit(SOCK_NOSPACE, &transport->sock->flags); | ||
| 553 | transport->inet->sk_write_pending++; | ||
| 554 | /* ...and wait for more buffer space */ | ||
| 555 | xprt_wait_for_buffer_space(task, xs_nospace_callback); | ||
| 556 | } | ||
| 557 | } else { | ||
| 558 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
| 559 | task->tk_status = -ENOTCONN; | ||
| 560 | } | ||
| 543 | 561 | ||
| 544 | spin_unlock_bh(&xprt->transport_lock); | 562 | spin_unlock_bh(&xprt->transport_lock); |
| 545 | } else | ||
| 546 | /* Keep holding the socket if it is blocked */ | ||
| 547 | rpc_delay(task, HZ>>4); | ||
| 548 | } | 563 | } |
| 549 | 564 | ||
| 550 | /** | 565 | /** |
| @@ -588,19 +603,20 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
| 588 | } | 603 | } |
| 589 | 604 | ||
| 590 | switch (status) { | 605 | switch (status) { |
| 606 | case -EAGAIN: | ||
| 607 | xs_nospace(task); | ||
| 608 | break; | ||
| 591 | case -ENETUNREACH: | 609 | case -ENETUNREACH: |
| 592 | case -EPIPE: | 610 | case -EPIPE: |
| 593 | case -ECONNREFUSED: | 611 | case -ECONNREFUSED: |
| 594 | /* When the server has died, an ICMP port unreachable message | 612 | /* When the server has died, an ICMP port unreachable message |
| 595 | * prompts ECONNREFUSED. */ | 613 | * prompts ECONNREFUSED. */ |
| 596 | break; | 614 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); |
| 597 | case -EAGAIN: | ||
| 598 | xs_nospace(task); | ||
| 599 | break; | 615 | break; |
| 600 | default: | 616 | default: |
| 617 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
| 601 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | 618 | dprintk("RPC: sendmsg returned unrecognized error %d\n", |
| 602 | -status); | 619 | -status); |
| 603 | break; | ||
| 604 | } | 620 | } |
| 605 | 621 | ||
| 606 | return status; | 622 | return status; |
| @@ -695,12 +711,13 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
| 695 | case -ENOTCONN: | 711 | case -ENOTCONN: |
| 696 | case -EPIPE: | 712 | case -EPIPE: |
| 697 | status = -ENOTCONN; | 713 | status = -ENOTCONN; |
| 714 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
| 698 | break; | 715 | break; |
| 699 | default: | 716 | default: |
| 700 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | 717 | dprintk("RPC: sendmsg returned unrecognized error %d\n", |
| 701 | -status); | 718 | -status); |
| 719 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
| 702 | xs_tcp_shutdown(xprt); | 720 | xs_tcp_shutdown(xprt); |
| 703 | break; | ||
| 704 | } | 721 | } |
| 705 | 722 | ||
| 706 | return status; | 723 | return status; |
| @@ -1189,9 +1206,11 @@ static void xs_udp_write_space(struct sock *sk) | |||
| 1189 | 1206 | ||
| 1190 | if (unlikely(!(sock = sk->sk_socket))) | 1207 | if (unlikely(!(sock = sk->sk_socket))) |
| 1191 | goto out; | 1208 | goto out; |
| 1209 | clear_bit(SOCK_NOSPACE, &sock->flags); | ||
| 1210 | |||
| 1192 | if (unlikely(!(xprt = xprt_from_sock(sk)))) | 1211 | if (unlikely(!(xprt = xprt_from_sock(sk)))) |
| 1193 | goto out; | 1212 | goto out; |
| 1194 | if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) | 1213 | if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0) |
| 1195 | goto out; | 1214 | goto out; |
| 1196 | 1215 | ||
| 1197 | xprt_write_space(xprt); | 1216 | xprt_write_space(xprt); |
| @@ -1222,9 +1241,11 @@ static void xs_tcp_write_space(struct sock *sk) | |||
| 1222 | 1241 | ||
| 1223 | if (unlikely(!(sock = sk->sk_socket))) | 1242 | if (unlikely(!(sock = sk->sk_socket))) |
| 1224 | goto out; | 1243 | goto out; |
| 1244 | clear_bit(SOCK_NOSPACE, &sock->flags); | ||
| 1245 | |||
| 1225 | if (unlikely(!(xprt = xprt_from_sock(sk)))) | 1246 | if (unlikely(!(xprt = xprt_from_sock(sk)))) |
| 1226 | goto out; | 1247 | goto out; |
| 1227 | if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) | 1248 | if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0) |
| 1228 | goto out; | 1249 | goto out; |
| 1229 | 1250 | ||
| 1230 | xprt_write_space(xprt); | 1251 | xprt_write_space(xprt); |
