[NET]: Clean up skb_linearize
authorHerbert Xu <herbert@gondor.apana.org.au>
Fri, 9 Jun 2006 23:10:40 +0000 (16:10 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Sun, 18 Jun 2006 04:30:16 +0000 (21:30 -0700)
The linearisation operation doesn't need to be super-optimised.  So we can
replace __skb_linearize with __pskb_pull_tail which does the same thing but
is more general.

Also, most users of skb_linearize end up testing whether the skb is linear
or not so it helps to make skb_linearize do just that.

Some callers of skb_linearize also use it to copy cloned data, so it's
useful to have a new function skb_linearize_cow to copy the data if it's
either non-linear or cloned.

Last but not least, I've removed the gfp argument since nobody uses it
anymore.  If it's ever needed we can easily add it back.

Misc bugs fixed by this patch:

* via-velocity error handling (also, no SG => no frags)

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/block/aoe/aoenet.c
drivers/net/mv643xx_eth.c
drivers/net/via-velocity.c
include/linux/skbuff.h
net/core/dev.c
net/decnet/dn_nsp_in.c
net/decnet/dn_route.c
net/ipv4/ipcomp.c
net/ipv6/ipcomp6.c

index fdff774b8ab944421ad0190486e98cc4c5f458a5..c1434ed118808999a3b05f148ef3b76b0590360f 100644 (file)
@@ -116,8 +116,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
        skb = skb_share_check(skb, GFP_ATOMIC);
        if (skb == NULL)
                return 0;
-       if (skb_is_nonlinear(skb))
-       if (skb_linearize(skb, GFP_ATOMIC) < 0)
+       if (skb_linearize(skb))
                goto exit;
        if (!is_aoe_netif(ifp))
                goto exit;
index 411f4d809c477d99175ee0eaa10257938a08d407..625ff61c9988e7e0519c3dda2ba82f59cbc33d53 100644 (file)
@@ -1200,7 +1200,7 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        if (has_tiny_unaligned_frags(skb)) {
-               if ((skb_linearize(skb, GFP_ATOMIC) != 0)) {
+               if (__skb_linearize(skb)) {
                        stats->tx_dropped++;
                        printk(KERN_DEBUG "%s: failed to linearize tiny "
                                        "unaligned fragment\n", dev->name);
index ed1f837c8fda2274a3874855550f1d39e81f1bcd..2eb6b5f9ba0df647bd760b43abcec48216241df6 100644 (file)
@@ -1899,6 +1899,13 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
 
        int pktlen = skb->len;
 
+#ifdef VELOCITY_ZERO_COPY_SUPPORT
+       if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
+               kfree_skb(skb);
+               return 0;
+       }
+#endif
+
        spin_lock_irqsave(&vptr->lock, flags);
 
        index = vptr->td_curr[qnum];
@@ -1914,8 +1921,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
         */
        if (pktlen < ETH_ZLEN) {
                /* Cannot occur until ZC support */
-               if(skb_linearize(skb, GFP_ATOMIC))
-                       return 0; 
                pktlen = ETH_ZLEN;
                memcpy(tdinfo->buf, skb->data, skb->len);
                memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
@@ -1933,7 +1938,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
                int nfrags = skb_shinfo(skb)->nr_frags;
                tdinfo->skb = skb;
                if (nfrags > 6) {
-                       skb_linearize(skb, GFP_ATOMIC);
                        memcpy(tdinfo->buf, skb->data, skb->len);
                        tdinfo->skb_dma[0] = tdinfo->buf_dma;
                        td_ptr->tdesc0.pktsize = 
index fe2c58e5306fc8b9e0b2ef6cddee4317f15ec047..830f58fa03a2519d4159aaba97fde1b867391034 100644 (file)
@@ -1169,18 +1169,34 @@ static inline int skb_can_coalesce(struct sk_buff *skb, int i,
        return 0;
 }
 
+static inline int __skb_linearize(struct sk_buff *skb)
+{
+       return __pskb_pull_tail(skb, skb->data_len) ? 0 : -ENOMEM;
+}
+
 /**
  *     skb_linearize - convert paged skb to linear one
  *     @skb: buffer to linarize
- *     @gfp: allocation mode
  *
  *     If there is no free memory -ENOMEM is returned, otherwise zero
  *     is returned and the old skb data released.
  */
-extern int __skb_linearize(struct sk_buff *skb, gfp_t gfp);
-static inline int skb_linearize(struct sk_buff *skb, gfp_t gfp)
+static inline int skb_linearize(struct sk_buff *skb)
+{
+       return skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0;
+}
+
+/**
+ *     skb_linearize_cow - make sure skb is linear and writable
+ *     @skb: buffer to process
+ *
+ *     If there is no free memory -ENOMEM is returned, otherwise zero
+ *     is returned and the old skb data released.
+ */
+static inline int skb_linearize_cow(struct sk_buff *skb)
 {
-       return __skb_linearize(skb, gfp);
+       return skb_is_nonlinear(skb) || skb_cloned(skb) ?
+              __skb_linearize(skb) : 0;
 }
 
 /**
index 1b09f1cae46ea069e6f709895f33a5a28eb79c4a..91361bc2b6823182cddaeac83103206460f0f335 100644 (file)
@@ -1222,64 +1222,6 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
 #define illegal_highdma(dev, skb)      (0)
 #endif
 
-/* Keep head the same: replace data */
-int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask)
-{
-       unsigned int size;
-       u8 *data;
-       long offset;
-       struct skb_shared_info *ninfo;
-       int headerlen = skb->data - skb->head;
-       int expand = (skb->tail + skb->data_len) - skb->end;
-
-       if (skb_shared(skb))
-               BUG();
-
-       if (expand <= 0)
-               expand = 0;
-
-       size = skb->end - skb->head + expand;
-       size = SKB_DATA_ALIGN(size);
-       data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
-       if (!data)
-               return -ENOMEM;
-
-       /* Copy entire thing */
-       if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len))
-               BUG();
-
-       /* Set up shinfo */
-       ninfo = (struct skb_shared_info*)(data + size);
-       atomic_set(&ninfo->dataref, 1);
-       ninfo->tso_size = skb_shinfo(skb)->tso_size;
-       ninfo->tso_segs = skb_shinfo(skb)->tso_segs;
-       ninfo->nr_frags = 0;
-       ninfo->frag_list = NULL;
-
-       /* Offset between the two in bytes */
-       offset = data - skb->head;
-
-       /* Free old data. */
-       skb_release_data(skb);
-
-       skb->head = data;
-       skb->end  = data + size;
-
-       /* Set up new pointers */
-       skb->h.raw   += offset;
-       skb->nh.raw  += offset;
-       skb->mac.raw += offset;
-       skb->tail    += offset;
-       skb->data    += offset;
-
-       /* We are no longer a clone, even if we were. */
-       skb->cloned    = 0;
-
-       skb->tail     += skb->data_len;
-       skb->data_len  = 0;
-       return 0;
-}
-
 #define HARD_TX_LOCK(dev, cpu) {                       \
        if ((dev->features & NETIF_F_LLTX) == 0) {      \
                netif_tx_lock(dev);                     \
@@ -1326,7 +1268,7 @@ int dev_queue_xmit(struct sk_buff *skb)
 
        if (skb_shinfo(skb)->frag_list &&
            !(dev->features & NETIF_F_FRAGLIST) &&
-           __skb_linearize(skb, GFP_ATOMIC))
+           __skb_linearize(skb))
                goto out_kfree_skb;
 
        /* Fragmented skb is linearized if device does not support SG,
@@ -1335,7 +1277,7 @@ int dev_queue_xmit(struct sk_buff *skb)
         */
        if (skb_shinfo(skb)->nr_frags &&
            (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
-           __skb_linearize(skb, GFP_ATOMIC))
+           __skb_linearize(skb))
                goto out_kfree_skb;
 
        /* If packet is not checksummed and device does not support
@@ -3473,7 +3415,6 @@ subsys_initcall(net_dev_init);
 EXPORT_SYMBOL(__dev_get_by_index);
 EXPORT_SYMBOL(__dev_get_by_name);
 EXPORT_SYMBOL(__dev_remove_pack);
-EXPORT_SYMBOL(__skb_linearize);
 EXPORT_SYMBOL(dev_valid_name);
 EXPORT_SYMBOL(dev_add_pack);
 EXPORT_SYMBOL(dev_alloc_name);
index 547523b41c8168e6c9b67dd25964cfe1aeccfc4c..a2ba9db1c37643aa5fd6d22359661a5564f3c9b0 100644 (file)
@@ -801,8 +801,7 @@ got_it:
                 * We linearize everything except data segments here.
                 */
                if (cb->nsp_flags & ~0x60) {
-                       if (unlikely(skb_is_nonlinear(skb)) &&
-                           skb_linearize(skb, GFP_ATOMIC) != 0)
+                       if (unlikely(skb_linearize(skb)))
                                goto free_out;
                }
 
index e172cf98d7fc3bdfda1831f06fed18fa20e097c6..5abf7057af00db705d4ec019a2c670312d6cdd5c 100644 (file)
@@ -629,8 +629,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
                        padlen);
 
         if (flags & DN_RT_PKT_CNTL) {
-               if (unlikely(skb_is_nonlinear(skb)) &&
-                   skb_linearize(skb, GFP_ATOMIC) != 0)
+               if (unlikely(skb_linearize(skb)))
                        goto dump_it;
 
                 switch(flags & DN_RT_CNTL_MSK) {
index 8e243589045ff64d0ae5ee67271151f0e06cbc68..3ed8b57a1002c307d4fd74f021d6177de3d9aefe 100644 (file)
@@ -80,15 +80,12 @@ out:
 
 static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-       int err = 0;
+       int err = -ENOMEM;
        struct iphdr *iph;
        struct ip_comp_hdr *ipch;
 
-       if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
-           skb_linearize(skb, GFP_ATOMIC) != 0) {
-               err = -ENOMEM;
+       if (skb_linearize_cow(skb))
                goto out;
-       }
 
        skb->ip_summed = CHECKSUM_NONE;
 
@@ -158,10 +155,8 @@ static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
                goto out_ok;
        }
 
-       if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
-           skb_linearize(skb, GFP_ATOMIC) != 0) {
+       if (skb_linearize_cow(skb))
                goto out_ok;
-       }
        
        err = ipcomp_compress(x, skb);
        iph = skb->nh.iph;
index cec3be544b69b23431fec2bbfb8981f95d75dc05..f28cd37feed3132444f84609cfaaed24ecfe3ede 100644 (file)
@@ -65,7 +65,7 @@ static LIST_HEAD(ipcomp6_tfms_list);
 
 static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-       int err = 0;
+       int err = -ENOMEM;
        struct ipv6hdr *iph;
        struct ipv6_comp_hdr *ipch;
        int plen, dlen;
@@ -74,11 +74,8 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
        struct crypto_tfm *tfm;
        int cpu;
 
-       if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
-               skb_linearize(skb, GFP_ATOMIC) != 0) {
-               err = -ENOMEM;
+       if (skb_linearize_cow(skb))
                goto out;
-       }
 
        skb->ip_summed = CHECKSUM_NONE;
 
@@ -142,10 +139,8 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb)
                goto out_ok;
        }
 
-       if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
-               skb_linearize(skb, GFP_ATOMIC) != 0) {
+       if (skb_linearize_cow(skb))
                goto out_ok;
-       }
 
        /* compression */
        plen = skb->len - hdr_len;