]> err.no Git - linux-2.6/blobdiff - net/ipv4/tcp_input.c
Pull thinkpad-2.6.24 into release branch
[linux-2.6] / net / ipv4 / tcp_input.c
index 9fc9096ada8a13416e80e73ec36090e4e62119db..0f0c1c9829a14b41e9654b3a108d2f1aa3b5e6f1 100644 (file)
@@ -1269,6 +1269,9 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
        if (before(TCP_SKB_CB(ack_skb)->ack_seq, prior_snd_una - tp->max_window))
                return 0;
 
+       if (!tp->packets_out)
+               goto out;
+
        /* SACK fastpath:
         * if the only SACK change is the increase of the end_seq of
         * the first block then only apply that SACK block
@@ -1400,7 +1403,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
                        /* DSACK info lost if out-of-mem, try SACK still */
                        if (in_sack <= 0)
                                in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq);
-                       if (in_sack < 0)
+                       if (unlikely(in_sack < 0))
                                break;
 
                        sacked = TCP_SKB_CB(skb)->sacked;
@@ -1444,12 +1447,17 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
                                                tp->retransmit_skb_hint = NULL;
                                        }
                                } else {
-                                       /* New sack for not retransmitted frame,
-                                        * which was in hole. It is reordering.
-                                        */
-                                       if (!(sacked & TCPCB_RETRANS) &&
-                                           fack_count < prior_fackets)
-                                               reord = min(fack_count, reord);
+                                       if (!(sacked & TCPCB_RETRANS)) {
+                                               /* New sack for not retransmitted frame,
+                                                * which was in hole. It is reordering.
+                                                */
+                                               if (fack_count < prior_fackets)
+                                                       reord = min(fack_count, reord);
+
+                                               /* SACK enhanced F-RTO (RFC4138; Appendix B) */
+                                               if (!after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark))
+                                                       flag |= FLAG_ONLY_ORIG_SACKED;
+                                       }
 
                                        if (sacked & TCPCB_LOST) {
                                                TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
@@ -1458,18 +1466,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
                                                /* clear lost hint */
                                                tp->retransmit_skb_hint = NULL;
                                        }
-                                       /* SACK enhanced F-RTO detection.
-                                        * Set flag if and only if non-rexmitted
-                                        * segments below frto_highmark are
-                                        * SACKed (RFC4138; Appendix B).
-                                        * Clearing correct due to in-order walk
-                                        */
-                                       if (after(end_seq, tp->frto_highmark)) {
-                                               flag &= ~FLAG_ONLY_ORIG_SACKED;
-                                       } else {
-                                               if (!(sacked & TCPCB_RETRANS))
-                                                       flag |= FLAG_ONLY_ORIG_SACKED;
-                                       }
                                }
 
                                TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
@@ -1503,6 +1499,12 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
                                tp->retransmit_skb_hint = NULL;
                        }
                }
+
+               /* SACK enhanced FRTO (RFC4138, Appendix B): Clearing correct
+                * due to in-order walk
+                */
+               if (after(end_seq, tp->frto_highmark))
+                       flag &= ~FLAG_ONLY_ORIG_SACKED;
        }
 
        if (tp->retrans_out &&
@@ -1516,6 +1518,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
            (!tp->frto_highmark || after(tp->snd_una, tp->frto_highmark)))
                tcp_update_reordering(sk, tp->fackets_out - reord, 0);
 
+out:
+
 #if FASTRETRANS_DEBUG > 0
        BUG_TRAP((int)tp->sacked_out >= 0);
        BUG_TRAP((int)tp->lost_out >= 0);
@@ -1670,6 +1674,9 @@ void tcp_enter_frto(struct sock *sk)
        }
        tcp_verify_left_out(tp);
 
+       /* Too bad if TCP was application limited */
+       tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp) + 1);
+
        /* Earlier loss recovery underway (see RFC4138; Appendix B).
         * The last condition is necessary at least in tp->frto_counter case.
         */
@@ -1702,6 +1709,8 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
        tcp_for_write_queue(skb, sk) {
                if (skb == tcp_send_head(sk))
                        break;
+
+               TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
                /*
                 * Count the retransmission made on RTO correctly (only when
                 * waiting for the first ACK and did not get it)...
@@ -1715,7 +1724,7 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
                } else {
                        if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS)
                                tp->undo_marker = 0;
-                       TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
+                       TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
                }
 
                /* Don't lost mark skbs that were fwd transmitted after RTO */
@@ -3104,11 +3113,11 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
        /* See if we can take anything off of the retransmit queue. */
        flag |= tcp_clean_rtx_queue(sk, &seq_rtt, prior_fackets);
 
+       if (tp->frto_counter)
+               frto_cwnd = tcp_process_frto(sk, flag);
        /* Guarantee sacktag reordering detection against wrap-arounds */
        if (before(tp->frto_highmark, tp->snd_una))
                tp->frto_highmark = 0;
-       if (tp->frto_counter)
-               frto_cwnd = tcp_process_frto(sk, flag);
 
        if (tcp_ack_is_dubious(sk, flag)) {
                /* Advance CWND, if state allows this. */