|
|
@@ -36,6 +36,21 @@ u32 tcp_retransmit_stamp(const struct sock *sk)
|
|
|
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.
|
|
|
@@ -544,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);
|
|
|
|