diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/tcp.c | 10 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 5 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 12 |
3 files changed, 24 insertions, 3 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 913f9bbfc030..259ffb50e429 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -996,8 +996,11 @@ do_error: | |||
996 | goto out; | 996 | goto out; |
997 | out_err: | 997 | out_err: |
998 | /* make sure we wake any epoll edge trigger waiter */ | 998 | /* make sure we wake any epoll edge trigger waiter */ |
999 | if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN)) | 999 | if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && |
1000 | err == -EAGAIN)) { | ||
1000 | sk->sk_write_space(sk); | 1001 | sk->sk_write_space(sk); |
1002 | tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED); | ||
1003 | } | ||
1001 | return sk_stream_error(sk, flags, err); | 1004 | return sk_stream_error(sk, flags, err); |
1002 | } | 1005 | } |
1003 | 1006 | ||
@@ -1331,8 +1334,11 @@ do_error: | |||
1331 | out_err: | 1334 | out_err: |
1332 | err = sk_stream_error(sk, flags, err); | 1335 | err = sk_stream_error(sk, flags, err); |
1333 | /* make sure we wake any epoll edge trigger waiter */ | 1336 | /* make sure we wake any epoll edge trigger waiter */ |
1334 | if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN)) | 1337 | if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && |
1338 | err == -EAGAIN)) { | ||
1335 | sk->sk_write_space(sk); | 1339 | sk->sk_write_space(sk); |
1340 | tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED); | ||
1341 | } | ||
1336 | release_sock(sk); | 1342 | release_sock(sk); |
1337 | return err; | 1343 | return err; |
1338 | } | 1344 | } |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a5d172761610..56fe736fd64d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -5059,8 +5059,11 @@ static void tcp_check_space(struct sock *sk) | |||
5059 | /* pairs with tcp_poll() */ | 5059 | /* pairs with tcp_poll() */ |
5060 | smp_mb__after_atomic(); | 5060 | smp_mb__after_atomic(); |
5061 | if (sk->sk_socket && | 5061 | if (sk->sk_socket && |
5062 | test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) | 5062 | test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { |
5063 | tcp_new_space(sk); | 5063 | tcp_new_space(sk); |
5064 | if (!test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) | ||
5065 | tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED); | ||
5066 | } | ||
5064 | } | 5067 | } |
5065 | } | 5068 | } |
5066 | 5069 | ||
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b74444cee24d..d3545d0cff75 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -1514,6 +1514,18 @@ static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) | |||
1514 | if (sysctl_tcp_slow_start_after_idle && | 1514 | if (sysctl_tcp_slow_start_after_idle && |
1515 | (s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= inet_csk(sk)->icsk_rto) | 1515 | (s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= inet_csk(sk)->icsk_rto) |
1516 | tcp_cwnd_application_limited(sk); | 1516 | tcp_cwnd_application_limited(sk); |
1517 | |||
1518 | /* The following conditions together indicate the starvation | ||
1519 | * is caused by insufficient sender buffer: | ||
1520 | * 1) just sent some data (see tcp_write_xmit) | ||
1521 | * 2) not cwnd limited (this else condition) | ||
1522 | * 3) no more data to send (null tcp_send_head ) | ||
1523 | * 4) application is hitting buffer limit (SOCK_NOSPACE) | ||
1524 | */ | ||
1525 | if (!tcp_send_head(sk) && sk->sk_socket && | ||
1526 | test_bit(SOCK_NOSPACE, &sk->sk_socket->flags) && | ||
1527 | (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) | ||
1528 | tcp_chrono_start(sk, TCP_CHRONO_SNDBUF_LIMITED); | ||
1517 | } | 1529 | } |
1518 | } | 1530 | } |
1519 | 1531 | ||