浏览代码

tcp: don't clear retransmit_skb_hint when not necessary

Most importantly avoid doing it with cumulative ACK. Not clearing
means that we no longer need n^2 processing in resolution of each
fast recovery.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
Ilpo Järvinen 16 年之前
父节点
当前提交
ef9da47c7c
共有 3 个文件被更改,包括 14 次插入5 次删除
  1. 6 1
      include/net/tcp.h
  2. 3 1
      net/ipv4/tcp_input.c
  3. 5 3
      net/ipv4/tcp_output.c

+ 6 - 1
include/net/tcp.h

@@ -1037,10 +1037,15 @@ static inline void tcp_mib_init(struct net *net)
 }
 }
 
 
 /* from STCP */
 /* from STCP */
-static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp)
+static inline void tcp_clear_retrans_hints_partial(struct tcp_sock *tp)
 {
 {
 	tp->lost_skb_hint = NULL;
 	tp->lost_skb_hint = NULL;
 	tp->scoreboard_skb_hint = NULL;
 	tp->scoreboard_skb_hint = NULL;
+}
+
+static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp)
+{
+	tcp_clear_retrans_hints_partial(tp);
 	tp->retransmit_skb_hint = NULL;
 	tp->retransmit_skb_hint = NULL;
 }
 }
 
 

+ 3 - 1
net/ipv4/tcp_input.c

@@ -2925,7 +2925,9 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets)
 
 
 		tcp_unlink_write_queue(skb, sk);
 		tcp_unlink_write_queue(skb, sk);
 		sk_wmem_free_skb(sk, skb);
 		sk_wmem_free_skb(sk, skb);
-		tcp_clear_all_retrans_hints(tp);
+		tcp_clear_retrans_hints_partial(tp);
+		if (skb == tp->retransmit_skb_hint)
+			tp->retransmit_skb_hint = NULL;
 	}
 	}
 
 
 	if (skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
 	if (skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))

+ 5 - 3
net/ipv4/tcp_output.c

@@ -750,7 +750,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
 
 
 	BUG_ON(len > skb->len);
 	BUG_ON(len > skb->len);
 
 
-	tcp_clear_all_retrans_hints(tp);
+	tcp_clear_retrans_hints_partial(tp);
 	nsize = skb_headlen(skb) - len;
 	nsize = skb_headlen(skb) - len;
 	if (nsize < 0)
 	if (nsize < 0)
 		nsize = 0;
 		nsize = 0;
@@ -1823,7 +1823,9 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb,
 	tp->packets_out -= tcp_skb_pcount(next_skb);
 	tp->packets_out -= tcp_skb_pcount(next_skb);
 
 
 	/* changed transmit queue under us so clear hints */
 	/* changed transmit queue under us so clear hints */
-	tcp_clear_all_retrans_hints(tp);
+	tcp_clear_retrans_hints_partial(tp);
+	if (next_skb == tp->retransmit_skb_hint)
+		tp->retransmit_skb_hint = skb;
 
 
 	sk_wmem_free_skb(sk, next_skb);
 	sk_wmem_free_skb(sk, next_skb);
 }
 }
@@ -1853,7 +1855,7 @@ void tcp_simple_retransmit(struct sock *sk)
 		}
 		}
 	}
 	}
 
 
-	tcp_clear_all_retrans_hints(tp);
+	tcp_clear_retrans_hints_partial(tp);
 
 
 	if (prior_lost == tp->lost_out)
 	if (prior_lost == tp->lost_out)
 		return;
 		return;