Merge branch 'cpufreq/arm/fixes' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / net / core / skbuff.c
index bbc3b4b..fc7942c 100644 (file)
@@ -70,6 +70,7 @@
 #include <net/xfrm.h>
 #include <net/mpls.h>
 #include <net/mptcp.h>
+#include <net/page_pool.h>
 
 #include <linux/uaccess.h>
 #include <trace/events/skb.h>
@@ -645,10 +646,13 @@ static void skb_free_head(struct sk_buff *skb)
 {
        unsigned char *head = skb->head;
 
-       if (skb->head_frag)
+       if (skb->head_frag) {
+               if (skb_pp_recycle(skb, head))
+                       return;
                skb_free_frag(head);
-       else
+       } else {
                kfree(head);
+       }
 }
 
 static void skb_release_data(struct sk_buff *skb)
@@ -659,17 +663,28 @@ static void skb_release_data(struct sk_buff *skb)
        if (skb->cloned &&
            atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1,
                              &shinfo->dataref))
-               return;
+               goto exit;
 
        skb_zcopy_clear(skb, true);
 
        for (i = 0; i < shinfo->nr_frags; i++)
-               __skb_frag_unref(&shinfo->frags[i]);
+               __skb_frag_unref(&shinfo->frags[i], skb->pp_recycle);
 
        if (shinfo->frag_list)
                kfree_skb_list(shinfo->frag_list);
 
        skb_free_head(skb);
+exit:
+       /* When we clone an SKB we copy the reycling bit. The pp_recycle
+        * bit is only set on the head though, so in order to avoid races
+        * while trying to recycle fragments on __skb_frag_unref() we need
+        * to make one SKB responsible for triggering the recycle path.
+        * So disable the recycling bit if an SKB is cloned and we have
+        * additional references to to the fragmented part of the SKB.
+        * Eventually the last SKB will have the recycling bit set and it's
+        * dataref set to 0, which will trigger the recycling
+        */
+       skb->pp_recycle = 0;
 }
 
 /*
@@ -939,6 +954,7 @@ void __kfree_skb_defer(struct sk_buff *skb)
 
 void napi_skb_free_stolen_head(struct sk_buff *skb)
 {
+       nf_reset_ct(skb);
        skb_dst_drop(skb);
        skb_ext_put(skb);
        napi_skb_cache_put(skb);
@@ -1046,6 +1062,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
        n->nohdr = 0;
        n->peeked = 0;
        C(pfmemalloc);
+       C(pp_recycle);
        n->destructor = NULL;
        C(tail);
        C(end);
@@ -1289,7 +1306,7 @@ static void __msg_zerocopy_callback(struct ubuf_info *uarg)
        }
        spin_unlock_irqrestore(&q->lock, flags);
 
-       sk->sk_error_report(sk);
+       sk_error_report(sk);
 
 release:
        consume_skb(skb);
@@ -3005,8 +3022,11 @@ skb_zerocopy_headlen(const struct sk_buff *from)
 
        if (!from->head_frag ||
            skb_headlen(from) < L1_CACHE_BYTES ||
-           skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS)
+           skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS) {
                hlen = skb_headlen(from);
+               if (!hlen)
+                       hlen = from->len;
+       }
 
        if (skb_has_frag_list(from))
                hlen = from->len;
@@ -3497,7 +3517,7 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
                fragto = &skb_shinfo(tgt)->frags[merge];
 
                skb_frag_size_add(fragto, skb_frag_size(fragfrom));
-               __skb_frag_unref(fragfrom);
+               __skb_frag_unref(fragfrom, skb->pp_recycle);
        }
 
        /* Reposition in the original skb */
@@ -4680,7 +4700,7 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 
        skb_queue_tail(&sk->sk_error_queue, skb);
        if (!sock_flag(sk, SOCK_DEAD))
-               sk->sk_error_report(sk);
+               sk_error_report(sk);
        return 0;
 }
 EXPORT_SYMBOL(sock_queue_err_skb);
@@ -4711,7 +4731,7 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
                sk->sk_err = 0;
 
        if (skb_next)
-               sk->sk_error_report(sk);
+               sk_error_report(sk);
 
        return skb;
 }
@@ -5287,6 +5307,13 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
        if (skb_cloned(to))
                return false;
 
+       /* The page pool signature of struct page will eventually figure out
+        * which pages can be recycled or not but for now let's prohibit slab
+        * allocated and page_pool allocated SKBs from being coalesced.
+        */
+       if (to->pp_recycle != from->pp_recycle)
+               return false;
+
        if (len <= skb_tailroom(to)) {
                if (len)
                        BUG_ON(skb_copy_bits(from, 0, skb_put(to, len), len));