diff options
-rw-r--r-- | net/ipv4/tcp_output.c | 75 |
1 files changed, 38 insertions, 37 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 2f24ecc37067..9f44be633ef6 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -2034,53 +2034,54 @@ void tcp_xmit_retransmit_queue(struct sock *sk) | |||
2034 | struct sk_buff *skb; | 2034 | struct sk_buff *skb; |
2035 | int mib_idx; | 2035 | int mib_idx; |
2036 | 2036 | ||
2037 | if (!tp->lost_out) | ||
2038 | tp->retransmit_high = tp->snd_una; | ||
2039 | |||
2037 | if (tp->retransmit_skb_hint) | 2040 | if (tp->retransmit_skb_hint) |
2038 | skb = tp->retransmit_skb_hint; | 2041 | skb = tp->retransmit_skb_hint; |
2039 | else | 2042 | else |
2040 | skb = tcp_write_queue_head(sk); | 2043 | skb = tcp_write_queue_head(sk); |
2041 | 2044 | ||
2042 | /* First pass: retransmit lost packets. */ | 2045 | /* First pass: retransmit lost packets. */ |
2043 | if (tp->lost_out) { | 2046 | tcp_for_write_queue_from(skb, sk) { |
2044 | tcp_for_write_queue_from(skb, sk) { | 2047 | __u8 sacked = TCP_SKB_CB(skb)->sacked; |
2045 | __u8 sacked = TCP_SKB_CB(skb)->sacked; | ||
2046 | 2048 | ||
2047 | if (skb == tcp_send_head(sk)) | 2049 | if (skb == tcp_send_head(sk)) |
2048 | break; | 2050 | break; |
2049 | /* we could do better than to assign each time */ | 2051 | /* we could do better than to assign each time */ |
2050 | tp->retransmit_skb_hint = skb; | 2052 | tp->retransmit_skb_hint = skb; |
2051 | 2053 | ||
2052 | /* Assume this retransmit will generate | 2054 | /* Assume this retransmit will generate |
2053 | * only one packet for congestion window | 2055 | * only one packet for congestion window |
2054 | * calculation purposes. This works because | 2056 | * calculation purposes. This works because |
2055 | * tcp_retransmit_skb() will chop up the | 2057 | * tcp_retransmit_skb() will chop up the |
2056 | * packet to be MSS sized and all the | 2058 | * packet to be MSS sized and all the |
2057 | * packet counting works out. | 2059 | * packet counting works out. |
2058 | */ | 2060 | */ |
2059 | if (tcp_packets_in_flight(tp) >= tp->snd_cwnd) | 2061 | if (tcp_packets_in_flight(tp) >= tp->snd_cwnd) |
2060 | return; | 2062 | return; |
2061 | if (!before(TCP_SKB_CB(skb)->seq, tp->retransmit_high)) | 2063 | if (!before(TCP_SKB_CB(skb)->seq, tp->retransmit_high)) |
2062 | break; | 2064 | break; |
2063 | if (sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS)) | 2065 | if (sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS)) |
2064 | continue; | 2066 | continue; |
2065 | 2067 | ||
2066 | if (!(sacked & TCPCB_LOST)) | 2068 | if (!(sacked & TCPCB_LOST)) |
2067 | continue; | 2069 | continue; |
2068 | 2070 | ||
2069 | if (tcp_retransmit_skb(sk, skb)) { | 2071 | if (tcp_retransmit_skb(sk, skb)) { |
2070 | tp->retransmit_skb_hint = NULL; | 2072 | tp->retransmit_skb_hint = NULL; |
2071 | return; | 2073 | return; |
2072 | } | ||
2073 | if (icsk->icsk_ca_state != TCP_CA_Loss) | ||
2074 | mib_idx = LINUX_MIB_TCPFASTRETRANS; | ||
2075 | else | ||
2076 | mib_idx = LINUX_MIB_TCPSLOWSTARTRETRANS; | ||
2077 | NET_INC_STATS_BH(sock_net(sk), mib_idx); | ||
2078 | |||
2079 | if (skb == tcp_write_queue_head(sk)) | ||
2080 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, | ||
2081 | inet_csk(sk)->icsk_rto, | ||
2082 | TCP_RTO_MAX); | ||
2083 | } | 2074 | } |
2075 | if (icsk->icsk_ca_state != TCP_CA_Loss) | ||
2076 | mib_idx = LINUX_MIB_TCPFASTRETRANS; | ||
2077 | else | ||
2078 | mib_idx = LINUX_MIB_TCPSLOWSTARTRETRANS; | ||
2079 | NET_INC_STATS_BH(sock_net(sk), mib_idx); | ||
2080 | |||
2081 | if (skb == tcp_write_queue_head(sk)) | ||
2082 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, | ||
2083 | inet_csk(sk)->icsk_rto, | ||
2084 | TCP_RTO_MAX); | ||
2084 | } | 2085 | } |
2085 | 2086 | ||
2086 | /* OK, demanded retransmission is finished. */ | 2087 | /* OK, demanded retransmission is finished. */ |