u32     retrans_stamp;  /* Timestamp of the last retransmit,
                                 * also used in SYN-SENT to remember stamp of
                                 * the first SYN. */
-       u32     undo_marker;    /* tracking retrans started here. */
+       u32     undo_marker;    /* snd_una upon a new recovery episode. */
        int     undo_retrans;   /* number of undoable retransmissions. */
        u32     total_retrans;  /* Total retransmits for entire connection */
 
 
        tp->sacked_out = 0;
 }
 
-static void tcp_clear_retrans_partial(struct tcp_sock *tp)
+void tcp_clear_retrans(struct tcp_sock *tp)
 {
        tp->retrans_out = 0;
        tp->lost_out = 0;
-
        tp->undo_marker = 0;
        tp->undo_retrans = -1;
+       tp->fackets_out = 0;
+       tp->sacked_out = 0;
 }
 
-void tcp_clear_retrans(struct tcp_sock *tp)
+static inline void tcp_init_undo(struct tcp_sock *tp)
 {
-       tcp_clear_retrans_partial(tp);
-
-       tp->fackets_out = 0;
-       tp->sacked_out = 0;
+       tp->undo_marker = tp->snd_una;
+       /* Retransmission still in flight may cause DSACKs later. */
+       tp->undo_retrans = tp->retrans_out ? : -1;
 }
 
 /* Enter Loss state. If we detect SACK reneging, forget all SACK information
                tp->prior_ssthresh = tcp_current_ssthresh(sk);
                tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
                tcp_ca_event(sk, CA_EVENT_LOSS);
+               tcp_init_undo(tp);
        }
        tp->snd_cwnd       = 1;
        tp->snd_cwnd_cnt   = 0;
        tp->snd_cwnd_stamp = tcp_time_stamp;
 
-       tcp_clear_retrans_partial(tp);
+       tp->retrans_out = 0;
+       tp->lost_out = 0;
 
        if (tcp_is_reno(tp))
                tcp_reset_reno_sack(tp);
 
-       tp->undo_marker = tp->snd_una;
-
        skb = tcp_write_queue_head(sk);
        is_reneg = skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED);
        if (is_reneg) {
                if (skb == tcp_send_head(sk))
                        break;
 
-               if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
-                       tp->undo_marker = 0;
-
                TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED;
                if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || is_reneg) {
                        TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
        NET_INC_STATS_BH(sock_net(sk), mib_idx);
 
        tp->prior_ssthresh = 0;
-       tp->undo_marker = tp->snd_una;
-       tp->undo_retrans = tp->retrans_out ? : -1;
+       tcp_init_undo(tp);
 
        if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) {
                if (!ece_ack)