Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / net / ipv4 / tcp_output.c
index 1c05443..858a15c 100644 (file)
@@ -324,7 +324,7 @@ static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        bool bpf_needs_ecn = tcp_bpf_ca_needs_ecn(sk);
-       bool use_ecn = sock_net(sk)->ipv4.sysctl_tcp_ecn == 1 ||
+       bool use_ecn = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn) == 1 ||
                tcp_ca_needs_ecn(sk) || bpf_needs_ecn;
 
        if (!use_ecn) {
@@ -346,7 +346,7 @@ static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb)
 
 static void tcp_ecn_clear_syn(struct sock *sk, struct sk_buff *skb)
 {
-       if (sock_net(sk)->ipv4.sysctl_tcp_ecn_fallback)
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn_fallback))
                /* tp->ecn_flags are cleared at a later point in time when
                 * SYN ACK is ultimatively being received.
                 */
@@ -3144,7 +3144,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
        struct tcp_sock *tp = tcp_sk(sk);
        unsigned int cur_mss;
        int diff, len, err;
-
+       int avail_wnd;
 
        /* Inconclusive MTU probe */
        if (icsk->icsk_mtup.probe_size)
@@ -3166,17 +3166,25 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
                return -EHOSTUNREACH; /* Routing failure or similar. */
 
        cur_mss = tcp_current_mss(sk);
+       avail_wnd = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq;
 
        /* If receiver has shrunk his window, and skb is out of
         * new window, do not retransmit it. The exception is the
         * case, when window is shrunk to zero. In this case
-        * our retransmit serves as a zero window probe.
+        * our retransmit of one segment serves as a zero window probe.
         */
-       if (!before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp)) &&
-           TCP_SKB_CB(skb)->seq != tp->snd_una)
-               return -EAGAIN;
+       if (avail_wnd <= 0) {
+               if (TCP_SKB_CB(skb)->seq != tp->snd_una)
+                       return -EAGAIN;
+               avail_wnd = cur_mss;
+       }
 
        len = cur_mss * segs;
+       if (len > avail_wnd) {
+               len = rounddown(avail_wnd, cur_mss);
+               if (!len)
+                       len = avail_wnd;
+       }
        if (skb->len > len) {
                if (tcp_fragment(sk, TCP_FRAG_IN_RTX_QUEUE, skb, len,
                                 cur_mss, GFP_ATOMIC))
@@ -3190,8 +3198,9 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
                diff -= tcp_skb_pcount(skb);
                if (diff)
                        tcp_adjust_pcount(sk, skb, diff);
-               if (skb->len < cur_mss)
-                       tcp_retrans_try_collapse(sk, skb, cur_mss);
+               avail_wnd = min_t(int, avail_wnd, cur_mss);
+               if (skb->len < avail_wnd)
+                       tcp_retrans_try_collapse(sk, skb, avail_wnd);
        }
 
        /* RFC3168, section 6.1.1.1. ECN fallback */
@@ -3362,12 +3371,13 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
  */
 void sk_forced_mem_schedule(struct sock *sk, int size)
 {
-       int amt;
+       int delta, amt;
 
-       if (size <= sk->sk_forward_alloc)
+       delta = size - sk->sk_forward_alloc;
+       if (delta <= 0)
                return;
-       amt = sk_mem_pages(size);
-       sk->sk_forward_alloc += amt * SK_MEM_QUANTUM;
+       amt = sk_mem_pages(delta);
+       sk->sk_forward_alloc += amt << PAGE_SHIFT;
        sk_memory_allocated_add(sk, amt);
 
        if (mem_cgroup_sockets_enabled && sk->sk_memcg)