Merge branch 'linux-linaro-lsk-v3.10' into linux-linaro-lsk-v3.10-android
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / tcp_input.c
index 4b75aad14b04a0c2dbf899d9d7993cf125002240..22fc869465e8b17b43208b6424f553531b593f21 100644 (file)
@@ -98,6 +98,7 @@ int sysctl_tcp_thin_dupack __read_mostly;
 
 int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
 int sysctl_tcp_early_retrans __read_mostly = 3;
+int sysctl_tcp_default_init_rwnd __read_mostly = TCP_DEFAULT_INIT_RCVWND;
 
 #define FLAG_DATA              0x01 /* Incoming frame contained data.          */
 #define FLAG_WIN_UPDATE                0x02 /* Incoming ACK was a window update.       */
@@ -351,14 +352,14 @@ static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb)
 static void tcp_fixup_rcvbuf(struct sock *sk)
 {
        u32 mss = tcp_sk(sk)->advmss;
-       u32 icwnd = TCP_DEFAULT_INIT_RCVWND;
+       u32 icwnd = sysctl_tcp_default_init_rwnd;
        int rcvmem;
 
        /* Limit to 10 segments if mss <= 1460,
         * or 14600/mss segments, with a minimum of two segments.
         */
        if (mss > 1460)
-               icwnd = max_t(u32, (1460 * TCP_DEFAULT_INIT_RCVWND) / mss, 2);
+               icwnd = max_t(u32, (1460 * icwnd) / mss, 2);
 
        rcvmem = SKB_TRUESIZE(mss + MAX_TCP_HEADER);
        while (tcp_win_from_space(rcvmem) < mss)
@@ -699,6 +700,34 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
        }
 }
 
+/* Set the sk_pacing_rate to allow proper sizing of TSO packets.
+ * Note: TCP stack does not yet implement pacing.
+ * FQ packet scheduler can be used to implement cheap but effective
+ * TCP pacing, to smooth the burst on large writes when packets
+ * in flight is significantly lower than cwnd (or rwin)
+ */
+static void tcp_update_pacing_rate(struct sock *sk)
+{
+       const struct tcp_sock *tp = tcp_sk(sk);
+       u64 rate;
+
+       /* set sk_pacing_rate to 200 % of current rate (mss * cwnd / srtt) */
+       rate = (u64)tp->mss_cache * 2 * (HZ << 3);
+
+       rate *= max(tp->snd_cwnd, tp->packets_out);
+
+       /* Correction for small srtt : minimum srtt being 8 (1 jiffy << 3),
+        * be conservative and assume srtt = 1 (125 us instead of 1.25 ms)
+        * We probably need usec resolution in the future.
+        * Note: This also takes care of possible srtt=0 case,
+        * when tcp_rtt_estimator() was not yet called.
+        */
+       if (tp->srtt > 8 + 2)
+               do_div(rate, tp->srtt);
+
+       sk->sk_pacing_rate = min_t(u64, rate, ~0U);
+}
+
 /* Calculate rto without backoff.  This is the second half of Van Jacobson's
  * routine referred to above.
  */
@@ -1047,7 +1076,7 @@ static bool tcp_check_dsack(struct sock *sk, const struct sk_buff *ack_skb,
        }
 
        /* D-SACK for already forgotten data... Do dumb counting. */
-       if (dup_sack && tp->undo_marker && tp->undo_retrans &&
+       if (dup_sack && tp->undo_marker && tp->undo_retrans > 0 &&
            !after(end_seq_0, prior_snd_una) &&
            after(end_seq_0, tp->undo_marker))
                tp->undo_retrans--;
@@ -1102,7 +1131,7 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
                        unsigned int new_len = (pkt_len / mss) * mss;
                        if (!in_sack && new_len < pkt_len) {
                                new_len += mss;
-                               if (new_len > skb->len)
+                               if (new_len >= skb->len)
                                        return 0;
                        }
                        pkt_len = new_len;
@@ -1126,7 +1155,7 @@ static u8 tcp_sacktag_one(struct sock *sk,
 
        /* Account D-SACK for retransmitted packet. */
        if (dup_sack && (sacked & TCPCB_RETRANS)) {
-               if (tp->undo_marker && tp->undo_retrans &&
+               if (tp->undo_marker && tp->undo_retrans > 0 &&
                    after(end_seq, tp->undo_marker))
                        tp->undo_retrans--;
                if (sacked & TCPCB_SACKED_ACKED)
@@ -1264,7 +1293,10 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
                tp->lost_cnt_hint -= tcp_skb_pcount(prev);
        }
 
-       TCP_SKB_CB(skb)->tcp_flags |= TCP_SKB_CB(prev)->tcp_flags;
+       TCP_SKB_CB(prev)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags;
+       if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
+               TCP_SKB_CB(prev)->end_seq++;
+
        if (skb == tcp_highest_sack(sk))
                tcp_advance_highest_sack(sk, skb);
 
@@ -1819,7 +1851,7 @@ static void tcp_clear_retrans_partial(struct tcp_sock *tp)
        tp->lost_out = 0;
 
        tp->undo_marker = 0;
-       tp->undo_retrans = 0;
+       tp->undo_retrans = -1;
 }
 
 void tcp_clear_retrans(struct tcp_sock *tp)
@@ -2669,7 +2701,7 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack)
 
        tp->prior_ssthresh = 0;
        tp->undo_marker = tp->snd_una;
-       tp->undo_retrans = tp->retrans_out;
+       tp->undo_retrans = tp->retrans_out ? : -1;
 
        if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) {
                if (!ece_ack)
@@ -2689,13 +2721,12 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack)
        bool recovered = !before(tp->snd_una, tp->high_seq);
 
        if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */
-               if (flag & FLAG_ORIG_SACK_ACKED) {
-                       /* Step 3.b. A timeout is spurious if not all data are
-                        * lost, i.e., never-retransmitted data are (s)acked.
-                        */
-                       tcp_try_undo_loss(sk, true);
+               /* Step 3.b. A timeout is spurious if not all data are
+                * lost, i.e., never-retransmitted data are (s)acked.
+                */
+               if (tcp_try_undo_loss(sk, flag & FLAG_ORIG_SACK_ACKED))
                        return;
-               }
+
                if (after(tp->snd_nxt, tp->high_seq) &&
                    (flag & FLAG_DATA_SACKED || is_dupack)) {
                        tp->frto = 0; /* Loss was real: 2nd part of step 3.a */
@@ -3046,10 +3077,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                        if (seq_rtt < 0) {
                                seq_rtt = ca_seq_rtt;
                        }
-                       if (!(sacked & TCPCB_SACKED_ACKED))
+                       if (!(sacked & TCPCB_SACKED_ACKED)) {
                                reord = min(pkts_acked, reord);
-                       if (!after(scb->end_seq, tp->high_seq))
-                               flag |= FLAG_ORIG_SACK_ACKED;
+                               if (!after(scb->end_seq, tp->high_seq))
+                                       flag |= FLAG_ORIG_SACK_ACKED;
+                       }
                }
 
                if (sacked & TCPCB_SACKED_ACKED)
@@ -3314,7 +3346,7 @@ static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag)
                        tcp_init_cwnd_reduction(sk, true);
                        tcp_set_ca_state(sk, TCP_CA_CWR);
                        tcp_end_cwnd_reduction(sk);
-                       tcp_set_ca_state(sk, TCP_CA_Open);
+                       tcp_try_keep_open(sk);
                        NET_INC_STATS_BH(sock_net(sk),
                                         LINUX_MIB_TCPLOSSPROBERECOVERY);
                }
@@ -3330,7 +3362,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
        u32 ack_seq = TCP_SKB_CB(skb)->seq;
        u32 ack = TCP_SKB_CB(skb)->ack_seq;
        bool is_dupack = false;
-       u32 prior_in_flight;
+       u32 prior_in_flight, prior_cwnd = tp->snd_cwnd, prior_rtt = tp->srtt;
        u32 prior_fackets;
        int prior_packets = tp->packets_out;
        int prior_sacked = tp->sacked_out;
@@ -3438,6 +3470,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 
        if (icsk->icsk_pending == ICSK_TIME_RETRANS)
                tcp_schedule_loss_probe(sk);
+       if (tp->srtt != prior_rtt || tp->snd_cwnd != prior_cwnd)
+               tcp_update_pacing_rate(sk);
        return 1;
 
 no_queue:
@@ -5736,6 +5770,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                } else
                                        tcp_init_metrics(sk);
 
+                               tcp_update_pacing_rate(sk);
+
                                /* Prevent spurious tcp_cwnd_restart() on
                                 * first data packet.
                                 */