|
@@ -22,6 +22,35 @@
|
|
|
#include <linux/gfp.h>
|
|
|
#include <net/tcp.h>
|
|
|
|
|
|
+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. */
|
|
@@ -337,8 +362,7 @@ static void tcp_probe_timer(struct sock *sk)
|
|
|
if (!start_ts)
|
|
|
skb->skb_mstamp = tp->tcp_mstamp;
|
|
|
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))) {
|