diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 37 | 
1 files changed, 20 insertions, 17 deletions
| diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2920e0cb09f8..bab7f0493098 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -107,6 +107,7 @@ int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2;  #define FLAG_ORIG_SACK_ACKED	0x200 /* Never retransmitted data are (s)acked	*/  #define FLAG_SND_UNA_ADVANCED	0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */  #define FLAG_DSACKING_ACK	0x800 /* SACK blocks contained D-SACK info */ +#define FLAG_SET_XMIT_TIMER	0x1000 /* Set TLP or RTO timer */  #define FLAG_SACK_RENEGING	0x2000 /* snd_una advanced to a sacked seq */  #define FLAG_UPDATE_TS_RECENT	0x4000 /* tcp_replace_ts_recent() */  #define FLAG_NO_CHALLENGE_ACK	0x8000 /* do not call tcp_send_challenge_ack()	*/ @@ -2520,8 +2521,8 @@ static inline void tcp_end_cwnd_reduction(struct sock *sk)  		return;  	/* Reset cwnd to ssthresh in CWR or Recovery (unless it's undone) */ -	if (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR || -	    (tp->undo_marker && tp->snd_ssthresh < TCP_INFINITE_SSTHRESH)) { +	if (tp->snd_ssthresh < TCP_INFINITE_SSTHRESH && +	    (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR || tp->undo_marker)) {  		tp->snd_cwnd = tp->snd_ssthresh;  		tp->snd_cwnd_stamp = tcp_jiffies32;  	} @@ -3004,21 +3005,24 @@ void tcp_rearm_rto(struct sock *sk)  		/* Offset the time elapsed after installing regular RTO */  		if (icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT ||  		    icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { -			struct sk_buff *skb = tcp_write_queue_head(sk); -			u64 rto_time_stamp = skb->skb_mstamp + -					     jiffies_to_usecs(rto); -			s64 delta_us = rto_time_stamp - tp->tcp_mstamp; +			s64 delta_us = tcp_rto_delta_us(sk);  			/* delta_us may not be positive if the socket is locked  			 * when the retrans timer fires and is rescheduled.  			 */ -			if (delta_us > 0) -				rto = usecs_to_jiffies(delta_us); +			rto = usecs_to_jiffies(max_t(int, delta_us, 1));  		}  		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, rto,  					  TCP_RTO_MAX);  	}  } +/* Try to schedule a loss probe; if that doesn't work, then schedule an RTO. */ +static void tcp_set_xmit_timer(struct sock *sk) +{ +	if (!tcp_schedule_loss_probe(sk)) +		tcp_rearm_rto(sk); +} +  /* If we get here, the whole TSO packet has not been acked. */  static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb)  { @@ -3180,7 +3184,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,  					ca_rtt_us, sack->rate);  	if (flag & FLAG_ACKED) { -		tcp_rearm_rto(sk); +		flag |= FLAG_SET_XMIT_TIMER;  /* set TLP or RTO timer */  		if (unlikely(icsk->icsk_mtup.probe_size &&  			     !after(tp->mtu_probe.probe_seq_end, tp->snd_una))) {  			tcp_mtup_probe_success(sk); @@ -3208,7 +3212,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,  		 * after when the head was last (re)transmitted. Otherwise the  		 * timeout may continue to extend in loss recovery.  		 */ -		tcp_rearm_rto(sk); +		flag |= FLAG_SET_XMIT_TIMER;  /* set TLP or RTO timer */  	}  	if (icsk->icsk_ca_ops->pkts_acked) { @@ -3580,9 +3584,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)  	if (after(ack, tp->snd_nxt))  		goto invalid_ack; -	if (icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) -		tcp_rearm_rto(sk); -  	if (after(ack, prior_snd_una)) {  		flag |= FLAG_SND_UNA_ADVANCED;  		icsk->icsk_retransmits = 0; @@ -3647,18 +3648,20 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)  	flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una, &acked,  				    &sack_state); +	if (tp->tlp_high_seq) +		tcp_process_tlp_ack(sk, ack, flag); +	/* If needed, reset TLP/RTO timer; RACK may later override this. */ +	if (flag & FLAG_SET_XMIT_TIMER) +		tcp_set_xmit_timer(sk); +  	if (tcp_ack_is_dubious(sk, flag)) {  		is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));  		tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit);  	} -	if (tp->tlp_high_seq) -		tcp_process_tlp_ack(sk, ack, flag);  	if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP))  		sk_dst_confirm(sk); -	if (icsk->icsk_pending == ICSK_TIME_RETRANS) -		tcp_schedule_loss_probe(sk);  	delivered = tp->delivered - delivered;	/* freshly ACKed or SACKed */  	lost = tp->lost - lost;			/* freshly marked lost */  	tcp_rate_gen(sk, delivered, lost, sack_state.rate); |