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); |