diff options
Diffstat (limited to 'net/sunrpc/xprtsock.c')
| -rw-r--r-- | net/sunrpc/xprtsock.c | 82 |
1 files changed, 51 insertions, 31 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 613daf8c1ff7..ddbe981ab516 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -136,12 +136,6 @@ static ctl_table sunrpc_table[] = { | |||
| 136 | #endif | 136 | #endif |
| 137 | 137 | ||
| 138 | /* | 138 | /* |
| 139 | * How many times to try sending a request on a socket before waiting | ||
| 140 | * for the socket buffer to clear. | ||
| 141 | */ | ||
| 142 | #define XS_SENDMSG_RETRY (10U) | ||
| 143 | |||
| 144 | /* | ||
| 145 | * Time out for an RPC UDP socket connect. UDP socket connects are | 139 | * Time out for an RPC UDP socket connect. UDP socket connects are |
| 146 | * synchronous, but we set a timeout anyway in case of resource | 140 | * synchronous, but we set a timeout anyway in case of resource |
| 147 | * exhaustion on the local host. | 141 | * exhaustion on the local host. |
| @@ -516,6 +510,14 @@ out: | |||
| 516 | return sent; | 510 | return sent; |
| 517 | } | 511 | } |
| 518 | 512 | ||
| 513 | static void xs_nospace_callback(struct rpc_task *task) | ||
| 514 | { | ||
| 515 | struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt); | ||
| 516 | |||
| 517 | transport->inet->sk_write_pending--; | ||
| 518 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
| 519 | } | ||
| 520 | |||
| 519 | /** | 521 | /** |
| 520 | * xs_nospace - place task on wait queue if transmit was incomplete | 522 | * xs_nospace - place task on wait queue if transmit was incomplete |
| 521 | * @task: task to put to sleep | 523 | * @task: task to put to sleep |
| @@ -531,20 +533,27 @@ static void xs_nospace(struct rpc_task *task) | |||
| 531 | task->tk_pid, req->rq_slen - req->rq_bytes_sent, | 533 | task->tk_pid, req->rq_slen - req->rq_bytes_sent, |
| 532 | req->rq_slen); | 534 | req->rq_slen); |
| 533 | 535 | ||
| 534 | if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) { | 536 | /* Protect against races with write_space */ |
| 535 | /* Protect against races with write_space */ | 537 | spin_lock_bh(&xprt->transport_lock); |
| 536 | spin_lock_bh(&xprt->transport_lock); | 538 | |
| 537 | 539 | /* Don't race with disconnect */ | |
| 538 | /* Don't race with disconnect */ | 540 | if (xprt_connected(xprt)) { |
| 539 | if (!xprt_connected(xprt)) | 541 | if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) { |
| 540 | task->tk_status = -ENOTCONN; | 542 | /* |
| 541 | else if (test_bit(SOCK_NOSPACE, &transport->sock->flags)) | 543 | * Notify TCP that we're limited by the application |
| 542 | xprt_wait_for_buffer_space(task); | 544 | * window size |
| 545 | */ | ||
| 546 | set_bit(SOCK_NOSPACE, &transport->sock->flags); | ||
| 547 | transport->inet->sk_write_pending++; | ||
| 548 | /* ...and wait for more buffer space */ | ||
| 549 | xprt_wait_for_buffer_space(task, xs_nospace_callback); | ||
| 550 | } | ||
| 551 | } else { | ||
| 552 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
| 553 | task->tk_status = -ENOTCONN; | ||
| 554 | } | ||
| 543 | 555 | ||
| 544 | spin_unlock_bh(&xprt->transport_lock); | 556 | spin_unlock_bh(&xprt->transport_lock); |
| 545 | } else | ||
| 546 | /* Keep holding the socket if it is blocked */ | ||
| 547 | rpc_delay(task, HZ>>4); | ||
| 548 | } | 557 | } |
| 549 | 558 | ||
| 550 | /** | 559 | /** |
| @@ -588,19 +597,20 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
| 588 | } | 597 | } |
| 589 | 598 | ||
| 590 | switch (status) { | 599 | switch (status) { |
| 600 | case -EAGAIN: | ||
| 601 | xs_nospace(task); | ||
| 602 | break; | ||
| 591 | case -ENETUNREACH: | 603 | case -ENETUNREACH: |
| 592 | case -EPIPE: | 604 | case -EPIPE: |
| 593 | case -ECONNREFUSED: | 605 | case -ECONNREFUSED: |
| 594 | /* When the server has died, an ICMP port unreachable message | 606 | /* When the server has died, an ICMP port unreachable message |
| 595 | * prompts ECONNREFUSED. */ | 607 | * prompts ECONNREFUSED. */ |
| 596 | break; | 608 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); |
| 597 | case -EAGAIN: | ||
| 598 | xs_nospace(task); | ||
| 599 | break; | 609 | break; |
| 600 | default: | 610 | default: |
| 611 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
| 601 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | 612 | dprintk("RPC: sendmsg returned unrecognized error %d\n", |
| 602 | -status); | 613 | -status); |
| 603 | break; | ||
| 604 | } | 614 | } |
| 605 | 615 | ||
| 606 | return status; | 616 | return status; |
| @@ -650,7 +660,6 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
| 650 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 660 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); |
| 651 | struct xdr_buf *xdr = &req->rq_snd_buf; | 661 | struct xdr_buf *xdr = &req->rq_snd_buf; |
| 652 | int status; | 662 | int status; |
| 653 | unsigned int retry = 0; | ||
| 654 | 663 | ||
| 655 | xs_encode_tcp_record_marker(&req->rq_snd_buf); | 664 | xs_encode_tcp_record_marker(&req->rq_snd_buf); |
| 656 | 665 | ||
| @@ -681,9 +690,10 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
| 681 | return 0; | 690 | return 0; |
| 682 | } | 691 | } |
| 683 | 692 | ||
| 693 | if (status != 0) | ||
| 694 | continue; | ||
| 684 | status = -EAGAIN; | 695 | status = -EAGAIN; |
| 685 | if (retry++ > XS_SENDMSG_RETRY) | 696 | break; |
| 686 | break; | ||
| 687 | } | 697 | } |
| 688 | 698 | ||
| 689 | switch (status) { | 699 | switch (status) { |
| @@ -695,12 +705,13 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
| 695 | case -ENOTCONN: | 705 | case -ENOTCONN: |
| 696 | case -EPIPE: | 706 | case -EPIPE: |
| 697 | status = -ENOTCONN; | 707 | status = -ENOTCONN; |
| 708 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
| 698 | break; | 709 | break; |
| 699 | default: | 710 | default: |
| 700 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | 711 | dprintk("RPC: sendmsg returned unrecognized error %d\n", |
| 701 | -status); | 712 | -status); |
| 713 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | ||
| 702 | xs_tcp_shutdown(xprt); | 714 | xs_tcp_shutdown(xprt); |
| 703 | break; | ||
| 704 | } | 715 | } |
| 705 | 716 | ||
| 706 | return status; | 717 | return status; |
| @@ -1073,6 +1084,7 @@ static void xs_tcp_data_ready(struct sock *sk, int bytes) | |||
| 1073 | { | 1084 | { |
| 1074 | struct rpc_xprt *xprt; | 1085 | struct rpc_xprt *xprt; |
| 1075 | read_descriptor_t rd_desc; | 1086 | read_descriptor_t rd_desc; |
| 1087 | int read; | ||
| 1076 | 1088 | ||
| 1077 | dprintk("RPC: xs_tcp_data_ready...\n"); | 1089 | dprintk("RPC: xs_tcp_data_ready...\n"); |
| 1078 | 1090 | ||
| @@ -1084,8 +1096,10 @@ static void xs_tcp_data_ready(struct sock *sk, int bytes) | |||
| 1084 | 1096 | ||
| 1085 | /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */ | 1097 | /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */ |
| 1086 | rd_desc.arg.data = xprt; | 1098 | rd_desc.arg.data = xprt; |
| 1087 | rd_desc.count = 65536; | 1099 | do { |
| 1088 | tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv); | 1100 | rd_desc.count = 65536; |
| 1101 | read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv); | ||
| 1102 | } while (read > 0); | ||
| 1089 | out: | 1103 | out: |
| 1090 | read_unlock(&sk->sk_callback_lock); | 1104 | read_unlock(&sk->sk_callback_lock); |
| 1091 | } | 1105 | } |
| @@ -1128,6 +1142,7 @@ static void xs_tcp_state_change(struct sock *sk) | |||
| 1128 | break; | 1142 | break; |
| 1129 | case TCP_FIN_WAIT1: | 1143 | case TCP_FIN_WAIT1: |
| 1130 | /* The client initiated a shutdown of the socket */ | 1144 | /* The client initiated a shutdown of the socket */ |
| 1145 | xprt->connect_cookie++; | ||
| 1131 | xprt->reestablish_timeout = 0; | 1146 | xprt->reestablish_timeout = 0; |
| 1132 | set_bit(XPRT_CLOSING, &xprt->state); | 1147 | set_bit(XPRT_CLOSING, &xprt->state); |
| 1133 | smp_mb__before_clear_bit(); | 1148 | smp_mb__before_clear_bit(); |
| @@ -1140,6 +1155,7 @@ static void xs_tcp_state_change(struct sock *sk) | |||
| 1140 | set_bit(XPRT_CLOSING, &xprt->state); | 1155 | set_bit(XPRT_CLOSING, &xprt->state); |
| 1141 | xprt_force_disconnect(xprt); | 1156 | xprt_force_disconnect(xprt); |
| 1142 | case TCP_SYN_SENT: | 1157 | case TCP_SYN_SENT: |
| 1158 | xprt->connect_cookie++; | ||
| 1143 | case TCP_CLOSING: | 1159 | case TCP_CLOSING: |
| 1144 | /* | 1160 | /* |
| 1145 | * If the server closed down the connection, make sure that | 1161 | * If the server closed down the connection, make sure that |
| @@ -1186,9 +1202,11 @@ static void xs_udp_write_space(struct sock *sk) | |||
| 1186 | 1202 | ||
| 1187 | if (unlikely(!(sock = sk->sk_socket))) | 1203 | if (unlikely(!(sock = sk->sk_socket))) |
| 1188 | goto out; | 1204 | goto out; |
| 1205 | clear_bit(SOCK_NOSPACE, &sock->flags); | ||
| 1206 | |||
| 1189 | if (unlikely(!(xprt = xprt_from_sock(sk)))) | 1207 | if (unlikely(!(xprt = xprt_from_sock(sk)))) |
| 1190 | goto out; | 1208 | goto out; |
| 1191 | if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) | 1209 | if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0) |
| 1192 | goto out; | 1210 | goto out; |
| 1193 | 1211 | ||
| 1194 | xprt_write_space(xprt); | 1212 | xprt_write_space(xprt); |
| @@ -1219,9 +1237,11 @@ static void xs_tcp_write_space(struct sock *sk) | |||
| 1219 | 1237 | ||
| 1220 | if (unlikely(!(sock = sk->sk_socket))) | 1238 | if (unlikely(!(sock = sk->sk_socket))) |
| 1221 | goto out; | 1239 | goto out; |
| 1240 | clear_bit(SOCK_NOSPACE, &sock->flags); | ||
| 1241 | |||
| 1222 | if (unlikely(!(xprt = xprt_from_sock(sk)))) | 1242 | if (unlikely(!(xprt = xprt_from_sock(sk)))) |
| 1223 | goto out; | 1243 | goto out; |
| 1224 | if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) | 1244 | if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0) |
| 1225 | goto out; | 1245 | goto out; |
| 1226 | 1246 | ||
| 1227 | xprt_write_space(xprt); | 1247 | xprt_write_space(xprt); |
