diff options
Diffstat (limited to 'net/ipv4/tcp_timer.c')
| -rw-r--r-- | net/ipv4/tcp_timer.c | 53 | 
1 files changed, 39 insertions, 14 deletions
| diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 3b3611729928..676020663ce8 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -22,6 +22,35 @@  #include <linux/gfp.h>  #include <net/tcp.h> +static u32 tcp_retransmit_stamp(const struct sock *sk) +{ +	u32 start_ts = tcp_sk(sk)->retrans_stamp; + +	if (unlikely(!start_ts)) { +		struct sk_buff *head = tcp_rtx_queue_head(sk); + +		if (!head) +			return 0; +		start_ts = tcp_skb_timestamp(head); +	} +	return start_ts; +} + +static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk) +{ +	struct inet_connection_sock *icsk = inet_csk(sk); +	u32 elapsed, start_ts; + +	start_ts = tcp_retransmit_stamp(sk); +	if (!icsk->icsk_user_timeout || !start_ts) +		return icsk->icsk_rto; +	elapsed = tcp_time_stamp(tcp_sk(sk)) - start_ts; +	if (elapsed >= icsk->icsk_user_timeout) +		return 1; /* user timeout has passed; fire ASAP */ +	else +		return min_t(u32, icsk->icsk_rto, msecs_to_jiffies(icsk->icsk_user_timeout - elapsed)); +} +  /**   *  tcp_write_err() - close socket and save error info   *  @sk:  The socket the error has appeared on. @@ -166,14 +195,9 @@ static bool retransmits_timed_out(struct sock *sk,  	if (!inet_csk(sk)->icsk_retransmits)  		return false; -	start_ts = tcp_sk(sk)->retrans_stamp; -	if (unlikely(!start_ts)) { -		struct sk_buff *head = tcp_rtx_queue_head(sk); - -		if (!head) -			return false; -		start_ts = tcp_skb_timestamp(head); -	} +	start_ts = tcp_retransmit_stamp(sk); +	if (!start_ts) +		return false;  	if (likely(timeout == 0)) {  		linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base); @@ -183,8 +207,9 @@ static bool retransmits_timed_out(struct sock *sk,  		else  			timeout = ((2 << linear_backoff_thresh) - 1) * rto_base +  				(boundary - linear_backoff_thresh) * TCP_RTO_MAX; +		timeout = jiffies_to_msecs(timeout);  	} -	return (tcp_time_stamp(tcp_sk(sk)) - start_ts) >= jiffies_to_msecs(timeout); +	return (tcp_time_stamp(tcp_sk(sk)) - start_ts) >= timeout;  }  /* A write timeout has occurred. Process the after effects. */ @@ -335,10 +360,9 @@ static void tcp_probe_timer(struct sock *sk)  	 */  	start_ts = tcp_skb_timestamp(skb);  	if (!start_ts) -		skb->skb_mstamp = tp->tcp_mstamp; +		skb->skb_mstamp_ns = tp->tcp_clock_cache;  	else if (icsk->icsk_user_timeout && -		 (s32)(tcp_time_stamp(tp) - start_ts) > -		 jiffies_to_msecs(icsk->icsk_user_timeout)) +		 (s32)(tcp_time_stamp(tp) - start_ts) > icsk->icsk_user_timeout)  		goto abort;  	max_probes = sock_net(sk)->ipv4.sysctl_tcp_retries2; @@ -535,7 +559,8 @@ out_reset_timer:  		/* Use normal (exponential) backoff */  		icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);  	} -	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX); +	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, +				  tcp_clamp_rto_to_user_timeout(sk), TCP_RTO_MAX);  	if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0))  		__sk_dst_reset(sk); @@ -672,7 +697,7 @@ static void tcp_keepalive_timer (struct timer_list *t)  		 * to determine when to timeout instead.  		 */  		if ((icsk->icsk_user_timeout != 0 && -		    elapsed >= icsk->icsk_user_timeout && +		    elapsed >= msecs_to_jiffies(icsk->icsk_user_timeout) &&  		    icsk->icsk_probes_out > 0) ||  		    (icsk->icsk_user_timeout == 0 &&  		    icsk->icsk_probes_out >= keepalive_probes(tp))) { |