]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/core/skbuff.c
net: add documentation for skb recycling
[linux-2.6-omap-h63xx.git] / net / core / skbuff.c
index ca1ccdf1ef7612b87d16f53f803b2460de612360..ebb6b94f8af2343963f10c02b2d35f912a8c9d46 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     Routines having to do with the 'struct sk_buff' memory handlers.
  *
- *     Authors:        Alan Cox <iiitac@pyr.swan.ac.uk>
+ *     Authors:        Alan Cox <alan@lxorguk.ukuu.org.uk>
  *                     Florian La Roche <rzsfl@rz.uni-sb.de>
  *
  *     Fixes:
@@ -263,6 +263,26 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
        return skb;
 }
 
+struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask)
+{
+       int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
+       struct page *page;
+
+       page = alloc_pages_node(node, gfp_mask, 0);
+       return page;
+}
+EXPORT_SYMBOL(__netdev_alloc_page);
+
+void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
+               int size)
+{
+       skb_fill_page_desc(skb, i, page, off, size);
+       skb->len += size;
+       skb->data_len += size;
+       skb->truesize += size;
+}
+EXPORT_SYMBOL(skb_add_rx_frag);
+
 /**
  *     dev_alloc_skb - allocate an skbuff for receiving
  *     @length: length to allocate
@@ -363,8 +383,7 @@ static void kfree_skbmem(struct sk_buff *skb)
        }
 }
 
-/* Free everything but the sk_buff shell. */
-static void skb_release_all(struct sk_buff *skb)
+static void skb_release_head_state(struct sk_buff *skb)
 {
        dst_release(skb->dst);
 #ifdef CONFIG_XFRM
@@ -388,6 +407,12 @@ static void skb_release_all(struct sk_buff *skb)
        skb->tc_verd = 0;
 #endif
 #endif
+}
+
+/* Free everything but the sk_buff shell. */
+static void skb_release_all(struct sk_buff *skb)
+{
+       skb_release_head_state(skb);
        skb_release_data(skb);
 }
 
@@ -424,6 +449,50 @@ void kfree_skb(struct sk_buff *skb)
        __kfree_skb(skb);
 }
 
+/**
+ *     skb_recycle_check - check if skb can be reused for receive
+ *     @skb: buffer
+ *     @skb_size: minimum receive buffer size
+ *
+ *     Checks that the skb passed in is not shared or cloned, and
+ *     that it is linear and its head portion at least as large as
+ *     skb_size so that it can be recycled as a receive buffer.
+ *     If these conditions are met, this function does any necessary
+ *     reference count dropping and cleans up the skbuff as if it
+ *     just came from __alloc_skb().
+ */
+int skb_recycle_check(struct sk_buff *skb, int skb_size)
+{
+       struct skb_shared_info *shinfo;
+
+       if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
+               return 0;
+
+       skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
+       if (skb_end_pointer(skb) - skb->head < skb_size)
+               return 0;
+
+       if (skb_shared(skb) || skb_cloned(skb))
+               return 0;
+
+       skb_release_head_state(skb);
+       shinfo = skb_shinfo(skb);
+       atomic_set(&shinfo->dataref, 1);
+       shinfo->nr_frags = 0;
+       shinfo->gso_size = 0;
+       shinfo->gso_segs = 0;
+       shinfo->gso_type = 0;
+       shinfo->ip6_frag_id = 0;
+       shinfo->frag_list = NULL;
+
+       memset(skb, 0, offsetof(struct sk_buff, tail));
+       skb_reset_tail_pointer(skb);
+       skb->data = skb->head + NET_SKB_PAD;
+
+       return 1;
+}
+EXPORT_SYMBOL(skb_recycle_check);
+
 static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 {
        new->tstamp             = old->tstamp;
@@ -701,6 +770,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 #endif
        long off;
 
+       BUG_ON(nhead < 0);
+
        if (skb_shared(skb))
                BUG();