Merge tag 'mips_5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
[linux-2.6-microblaze.git] / net / ipv4 / ip_output.c
index c3efc7d..8d8a8da 100644 (file)
@@ -1054,7 +1054,7 @@ static int __ip_append_data(struct sock *sk,
                        unsigned int datalen;
                        unsigned int fraglen;
                        unsigned int fraggap;
-                       unsigned int alloclen;
+                       unsigned int alloclen, alloc_extra;
                        unsigned int pagedlen;
                        struct sk_buff *skb_prev;
 alloc_new_skb:
@@ -1074,35 +1074,39 @@ alloc_new_skb:
                        fraglen = datalen + fragheaderlen;
                        pagedlen = 0;
 
+                       alloc_extra = hh_len + 15;
+                       alloc_extra += exthdrlen;
+
+                       /* The last fragment gets additional space at tail.
+                        * Note, with MSG_MORE we overallocate on fragments,
+                        * because we have no idea what fragment will be
+                        * the last.
+                        */
+                       if (datalen == length + fraggap)
+                               alloc_extra += rt->dst.trailer_len;
+
                        if ((flags & MSG_MORE) &&
                            !(rt->dst.dev->features&NETIF_F_SG))
                                alloclen = mtu;
-                       else if (!paged)
+                       else if (!paged &&
+                                (fraglen + alloc_extra < SKB_MAX_ALLOC ||
+                                 !(rt->dst.dev->features & NETIF_F_SG)))
                                alloclen = fraglen;
                        else {
                                alloclen = min_t(int, fraglen, MAX_HEADER);
                                pagedlen = fraglen - alloclen;
                        }
 
-                       alloclen += exthdrlen;
-
-                       /* The last fragment gets additional space at tail.
-                        * Note, with MSG_MORE we overallocate on fragments,
-                        * because we have no idea what fragment will be
-                        * the last.
-                        */
-                       if (datalen == length + fraggap)
-                               alloclen += rt->dst.trailer_len;
+                       alloclen += alloc_extra;
 
                        if (transhdrlen) {
-                               skb = sock_alloc_send_skb(sk,
-                                               alloclen + hh_len + 15,
+                               skb = sock_alloc_send_skb(sk, alloclen,
                                                (flags & MSG_DONTWAIT), &err);
                        } else {
                                skb = NULL;
                                if (refcount_read(&sk->sk_wmem_alloc) + wmem_alloc_delta <=
                                    2 * sk->sk_sndbuf)
-                                       skb = alloc_skb(alloclen + hh_len + 15,
+                                       skb = alloc_skb(alloclen,
                                                        sk->sk_allocation);
                                if (unlikely(!skb))
                                        err = -ENOBUFS;