|
@@ -2717,6 +2717,35 @@ static void tcp_try_undo_dsack(struct sock *sk)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* We can clear retrans_stamp when there are no retransmissions in the
|
|
|
|
+ * window. It would seem that it is trivially available for us in
|
|
|
|
+ * tp->retrans_out, however, that kind of assumptions doesn't consider
|
|
|
|
+ * what will happen if errors occur when sending retransmission for the
|
|
|
|
+ * second time. ...It could the that such segment has only
|
|
|
|
+ * TCPCB_EVER_RETRANS set at the present time. It seems that checking
|
|
|
|
+ * the head skb is enough except for some reneging corner cases that
|
|
|
|
+ * are not worth the effort.
|
|
|
|
+ *
|
|
|
|
+ * Main reason for all this complexity is the fact that connection dying
|
|
|
|
+ * time now depends on the validity of the retrans_stamp, in particular,
|
|
|
|
+ * that successive retransmissions of a segment must not advance
|
|
|
|
+ * retrans_stamp under any conditions.
|
|
|
|
+ */
|
|
|
|
+static int tcp_any_retrans_done(struct sock *sk)
|
|
|
|
+{
|
|
|
|
+ struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
+ struct sk_buff *skb;
|
|
|
|
+
|
|
|
|
+ if (tp->retrans_out)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ skb = tcp_write_queue_head(sk);
|
|
|
|
+ if (unlikely(skb && TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS))
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/* Undo during fast recovery after partial ACK. */
|
|
/* Undo during fast recovery after partial ACK. */
|
|
|
|
|
|
static int tcp_try_undo_partial(struct sock *sk, int acked)
|
|
static int tcp_try_undo_partial(struct sock *sk, int acked)
|
|
@@ -2729,7 +2758,7 @@ static int tcp_try_undo_partial(struct sock *sk, int acked)
|
|
/* Plain luck! Hole if filled with delayed
|
|
/* Plain luck! Hole if filled with delayed
|
|
* packet, rather than with a retransmit.
|
|
* packet, rather than with a retransmit.
|
|
*/
|
|
*/
|
|
- if (tp->retrans_out == 0)
|
|
|
|
|
|
+ if (!tcp_any_retrans_done(sk))
|
|
tp->retrans_stamp = 0;
|
|
tp->retrans_stamp = 0;
|
|
|
|
|
|
tcp_update_reordering(sk, tcp_fackets_out(tp) + acked, 1);
|
|
tcp_update_reordering(sk, tcp_fackets_out(tp) + acked, 1);
|
|
@@ -2788,7 +2817,7 @@ static void tcp_try_keep_open(struct sock *sk)
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
int state = TCP_CA_Open;
|
|
int state = TCP_CA_Open;
|
|
|
|
|
|
- if (tcp_left_out(tp) || tp->retrans_out || tp->undo_marker)
|
|
|
|
|
|
+ if (tcp_left_out(tp) || tcp_any_retrans_done(sk) || tp->undo_marker)
|
|
state = TCP_CA_Disorder;
|
|
state = TCP_CA_Disorder;
|
|
|
|
|
|
if (inet_csk(sk)->icsk_ca_state != state) {
|
|
if (inet_csk(sk)->icsk_ca_state != state) {
|
|
@@ -2803,7 +2832,7 @@ static void tcp_try_to_open(struct sock *sk, int flag)
|
|
|
|
|
|
tcp_verify_left_out(tp);
|
|
tcp_verify_left_out(tp);
|
|
|
|
|
|
- if (!tp->frto_counter && tp->retrans_out == 0)
|
|
|
|
|
|
+ if (!tp->frto_counter && !tcp_any_retrans_done(sk))
|
|
tp->retrans_stamp = 0;
|
|
tp->retrans_stamp = 0;
|
|
|
|
|
|
if (flag & FLAG_ECE)
|
|
if (flag & FLAG_ECE)
|