diff options
Diffstat (limited to 'net/ipv4/tcp_output.c')
| -rw-r--r-- | net/ipv4/tcp_output.c | 65 | 
1 files changed, 32 insertions, 33 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b1c218df2c85..f9a8a12b62ee 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -137,12 +137,12 @@ static __u16 tcp_advertise_mss(struct sock *sk)  }  /* RFC2861. Reset CWND after idle period longer RTO to "restart window". - * This is the first part of cwnd validation mechanism. */ -static void tcp_cwnd_restart(struct sock *sk, const struct dst_entry *dst) + * This is the first part of cwnd validation mechanism. + */ +void tcp_cwnd_restart(struct sock *sk, s32 delta)  {  	struct tcp_sock *tp = tcp_sk(sk); -	s32 delta = tcp_time_stamp - tp->lsndtime; -	u32 restart_cwnd = tcp_init_cwnd(tp, dst); +	u32 restart_cwnd = tcp_init_cwnd(tp, __sk_dst_get(sk));  	u32 cwnd = tp->snd_cwnd;  	tcp_ca_event(sk, CA_EVENT_CWND_RESTART); @@ -163,20 +163,17 @@ static void tcp_event_data_sent(struct tcp_sock *tp,  {  	struct inet_connection_sock *icsk = inet_csk(sk);  	const u32 now = tcp_time_stamp; -	const struct dst_entry *dst = __sk_dst_get(sk); -	if (sysctl_tcp_slow_start_after_idle && -	    (!tp->packets_out && (s32)(now - tp->lsndtime) > icsk->icsk_rto)) -		tcp_cwnd_restart(sk, __sk_dst_get(sk)); +	if (tcp_packets_in_flight(tp) == 0) +		tcp_ca_event(sk, CA_EVENT_TX_START);  	tp->lsndtime = now;  	/* If it is a reply for ato after last received  	 * packet, enter pingpong mode.  	 */ -	if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato && -	    (!dst || !dst_metric(dst, RTAX_QUICKACK))) -			icsk->icsk_ack.pingpong = 1; +	if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato) +		icsk->icsk_ack.pingpong = 1;  }  /* Account for an ACK we sent. */ @@ -946,9 +943,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,  							   &md5);  	tcp_header_size = tcp_options_size + sizeof(struct tcphdr); -	if (tcp_packets_in_flight(tp) == 0) -		tcp_ca_event(sk, CA_EVENT_TX_START); -  	/* if no packet is in qdisc/device queue, then allow XPS to select  	 * another queue. We can be called from tcp_tsq_handler()  	 * which holds one reference to sk_wmem_alloc. @@ -1776,7 +1770,7 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb,  	if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)  		goto send_now; -	if (!((1 << icsk->icsk_ca_state) & (TCPF_CA_Open | TCPF_CA_CWR))) +	if (icsk->icsk_ca_state >= TCP_CA_Recovery)  		goto send_now;  	/* Avoid bursty behavior by allowing defer @@ -2151,7 +2145,7 @@ repair:  		tcp_cwnd_validate(sk, is_cwnd_limited);  		return false;  	} -	return (push_one == 2) || (!tp->packets_out && tcp_send_head(sk)); +	return !tp->packets_out && tcp_send_head(sk);  }  bool tcp_schedule_loss_probe(struct sock *sk) @@ -2228,7 +2222,7 @@ static bool skb_still_in_host_queue(const struct sock *sk,  	return false;  } -/* When probe timeout (PTO) fires, send a new segment if one exists, else +/* When probe timeout (PTO) fires, try send a new segment if possible, else   * retransmit the last segment.   */  void tcp_send_loss_probe(struct sock *sk) @@ -2237,11 +2231,19 @@ void tcp_send_loss_probe(struct sock *sk)  	struct sk_buff *skb;  	int pcount;  	int mss = tcp_current_mss(sk); -	int err = -1; -	if (tcp_send_head(sk)) { -		err = tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); -		goto rearm_timer; +	skb = tcp_send_head(sk); +	if (skb) { +		if (tcp_snd_wnd_test(tp, skb, mss)) { +			pcount = tp->packets_out; +			tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); +			if (tp->packets_out > pcount) +				goto probe_sent; +			goto rearm_timer; +		} +		skb = tcp_write_queue_prev(sk, skb); +	} else { +		skb = tcp_write_queue_tail(sk);  	}  	/* At most one outstanding TLP retransmission. */ @@ -2249,7 +2251,6 @@ void tcp_send_loss_probe(struct sock *sk)  		goto rearm_timer;  	/* Retransmit last segment. */ -	skb = tcp_write_queue_tail(sk);  	if (WARN_ON(!skb))  		goto rearm_timer; @@ -2264,26 +2265,24 @@ void tcp_send_loss_probe(struct sock *sk)  		if (unlikely(tcp_fragment(sk, skb, (pcount - 1) * mss, mss,  					  GFP_ATOMIC)))  			goto rearm_timer; -		skb = tcp_write_queue_tail(sk); +		skb = tcp_write_queue_next(sk, skb);  	}  	if (WARN_ON(!skb || !tcp_skb_pcount(skb)))  		goto rearm_timer; -	err = __tcp_retransmit_skb(sk, skb); +	if (__tcp_retransmit_skb(sk, skb)) +		goto rearm_timer;  	/* Record snd_nxt for loss detection. */ -	if (likely(!err)) -		tp->tlp_high_seq = tp->snd_nxt; +	tp->tlp_high_seq = tp->snd_nxt; +probe_sent: +	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSSPROBES); +	/* Reset s.t. tcp_rearm_rto will restart timer from now */ +	inet_csk(sk)->icsk_pending = 0;  rearm_timer: -	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, -				  inet_csk(sk)->icsk_rto, -				  TCP_RTO_MAX); - -	if (likely(!err)) -		NET_INC_STATS_BH(sock_net(sk), -				 LINUX_MIB_TCPLOSSPROBES); +	tcp_rearm_rto(sk);  }  /* Push out any pending frames which were held back due to  |