summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-06-23 13:06:41 +0400
committerDavid S. Miller <davem@davemloft.net>2006-06-23 13:06:41 +0400
commit5b057c6b1a25d57edf2b4d1e956e50936480a9ff (patch)
treee641febd6f562e0ed1198c160ff353ab513f0612
parent5fa21d821f6972e70942f2c555ec29dde962bdb2 (diff)
downloadlinux-5b057c6b1a25d57edf2b4d1e956e50936480a9ff.tar.xz
[NET]: Avoid allocating skb in skb_pad
First of all it is unnecessary to allocate a new skb in skb_pad since the existing one is not shared. More importantly, our hard_start_xmit interface does not allow a new skb to be allocated since that breaks requeueing. This patch uses pskb_expand_head to expand the existing skb and linearize it if needed. Actually, someone should sift through every instance of skb_pad on a non-linear skb as they do not fit the reasons why this was originally created. Incidentally, this fixes a minor bug when the skb is cloned (tcpdump, TCP, etc.). As it is skb_pad will simply write over a cloned skb. Because of the position of the write it is unlikely to cause problems but still it's best if we don't do it. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/3c527.c3
-rw-r--r--drivers/net/82596.c3
-rw-r--r--drivers/net/a2065.c3
-rw-r--r--drivers/net/ariadne.c3
-rw-r--r--drivers/net/arm/ether1.c3
-rw-r--r--drivers/net/arm/ether3.c3
-rw-r--r--drivers/net/atarilance.c3
-rw-r--r--drivers/net/cassini.c3
-rw-r--r--drivers/net/declance.c3
-rw-r--r--drivers/net/depca.c7
-rw-r--r--drivers/net/eepro.c3
-rw-r--r--drivers/net/eexpress.c3
-rw-r--r--drivers/net/epic100.c7
-rw-r--r--drivers/net/eth16i.c3
-rw-r--r--drivers/net/hp100.c7
-rw-r--r--drivers/net/lance.c3
-rw-r--r--drivers/net/lasi_82596.c3
-rw-r--r--drivers/net/lp486e.c3
-rw-r--r--drivers/net/myri10ge/myri10ge.c3
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c3
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c3
-rw-r--r--drivers/net/r8169.c3
-rw-r--r--drivers/net/seeq8005.c3
-rw-r--r--drivers/net/sis190.c3
-rw-r--r--drivers/net/sk98lin/skge.c2
-rw-r--r--drivers/net/skge.c3
-rw-r--r--drivers/net/smc9194.c3
-rw-r--r--drivers/net/sonic.c3
-rw-r--r--drivers/net/starfire.c3
-rw-r--r--drivers/net/via-rhine.c7
-rw-r--r--drivers/net/wireless/ray_cs.c3
-rw-r--r--drivers/net/wireless/wavelan_cs.c7
-rw-r--r--drivers/net/yellowfin.c12
-rw-r--r--drivers/net/znet.c3
-rw-r--r--include/linux/skbuff.h11
-rw-r--r--net/core/skbuff.c36
36 files changed, 74 insertions, 103 deletions
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 1b1cb0026072..157eda573925 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -1031,8 +1031,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
return 1;
}
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL) {
+ if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
return 0;
}
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index da0c878dcba8..8a9f7d61b9b1 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -1070,8 +1070,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->len, (unsigned int)skb->data));
if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 79bb56b8dcef..71165ac0257a 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -573,8 +573,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
if (len < ETH_ZLEN) {
len = ETH_ZLEN;
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
}
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index d1b6b1f794e2..a9bb7a4aff98 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -607,8 +607,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* FIXME: is the 79C960 new enough to do its own padding right ? */
if (skb->len < ETH_ZLEN)
{
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
len = ETH_ZLEN;
}
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index 36475eb2727f..312955d07b28 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -700,8 +700,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
}
if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
goto out;
}
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index f1d5b1027ff7..081074180e62 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -518,8 +518,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
length = (length + 1) & ~1;
if (length != skb->len) {
- skb = skb_padto(skb, length);
- if (skb == NULL)
+ if (skb_padto(skb, length))
goto out;
}
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index 442b2cbeb58a..91783a8008be 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -804,8 +804,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
++len;
if (len > skb->len) {
- skb = skb_padto(skb, len);
- if (skb == NULL)
+ if (skb_padto(skb, len))
return 0;
}
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 39f36aa05aa8..565a54f1d06a 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2915,8 +2915,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
static int ring;
- skb = skb_padto(skb, cp->min_frame_size);
- if (!skb)
+ if (skb_padto(skb, cp->min_frame_size))
return 0;
/* XXX: we need some higher-level QoS hooks to steer packets to
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index f130bdab3fd3..d3d958e7ac56 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -885,8 +885,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skblen;
if (len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
len = ETH_ZLEN;
}
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 0941d40f046f..e946c43d3b10 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -938,11 +938,8 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < 1)
goto out;
- if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- goto out;
- }
+ if (skb_padto(skb, ETH_ZLEN))
+ goto out;
netif_stop_queue(dev);
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index a806dfe54d23..e70f172699db 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1154,8 +1154,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name);
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 82bd356e4f3a..a74b20715755 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -677,8 +677,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
#endif
if (buf->len < ETH_ZLEN) {
- buf = skb_padto(buf, ETH_ZLEN);
- if (buf == NULL)
+ if (skb_padto(buf, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 8d680ce600d7..724d7dc35fa3 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1027,11 +1027,8 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 ctrl_word;
unsigned long flags;
- if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
- }
+ if (skb_padto(skb, ETH_ZLEN))
+ return 0;
/* Caution: the write order is important here, set the field with the
"ownership" bit last. */
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index b67545be2caa..4bf76f86d8e9 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1064,8 +1064,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 247c8ca86033..dd1dc32dc98d 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1487,11 +1487,8 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
if (skb->len <= 0)
return 0;
- if (skb->len < ETH_ZLEN && lp->chip == HP100_CHIPID_SHASTA) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
- }
+ if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN))
+ return 0;
/* Get Tx ring tail pointer */
if (lp->txrtail->next == lp->txrhead) {
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index bb5ad479210b..c1c3452c90ca 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -968,8 +968,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The old LANCE chips doesn't automatically pad buffers to min. size. */
if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) {
if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
goto out;
lp->tx_ring[entry].length = -ETH_ZLEN;
}
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
index 957888de3d7e..1ab09447baa5 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/lasi_82596.c
@@ -1083,8 +1083,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->len, skb->data));
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index 94d5ea1ce8bd..bf3f343ae715 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -877,8 +877,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
length = skb->len;
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 5a74f63618bc..b983e1e04348 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1939,8 +1939,7 @@ again:
/* pad frames to at least ETH_ZLEN bytes */
if (unlikely(skb->len < ETH_ZLEN)) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL) {
+ if (skb_padto(skb, ETH_ZLEN)) {
/* The packet is gone, so we must
* return 0 */
mgp->stats.tx_dropped += 1;
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 09b11761cdfa..ea93b8f18605 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -831,8 +831,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN)
{
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index e80d1e3aec68..9bae77ce1314 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1374,8 +1374,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
if (pktlen < ETH_ZLEN)
{
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
pktlen = ETH_ZLEN;
}
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 9945cc6b8d90..985afe0e6273 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2222,8 +2222,7 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skb->len;
if (unlikely(len < ETH_ZLEN)) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (!skb)
+ if (skb_padto(skb, ETH_ZLEN))
goto err_update_stats;
len = ETH_ZLEN;
}
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index bcef03feb2fc..efd0f235020f 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -396,8 +396,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
unsigned char *buf;
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 31dd3f036fa8..df39f3447655 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1156,8 +1156,7 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev)
dma_addr_t mapping;
if (unlikely(skb->len < ETH_ZLEN)) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (!skb) {
+ if (skb_padto(skb, ETH_ZLEN)) {
tp->stats.tx_dropped++;
goto out;
}
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 38a26df4095f..f3efbd177ae7 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -1525,7 +1525,7 @@ struct sk_buff *pMessage) /* pointer to send-message */
** This is to resolve faulty padding by the HW with 0xaa bytes.
*/
if (BytesSend < C_LEN_ETHERNET_MINSIZE) {
- if ((pMessage = skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) == NULL) {
+ if (skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) {
spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
return 0;
}
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 536dd1cf7f79..19a4a16055dc 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -2310,8 +2310,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
u64 map;
unsigned long flags;
- skb = skb_padto(skb, ETH_ZLEN);
- if (!skb)
+ if (skb_padto(skb, ETH_ZLEN))
return NETDEV_TX_OK;
if (!spin_trylock_irqsave(&skge->tx_lock, flags))
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 6cf16f322ad5..8b0321f1976c 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -523,8 +523,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
length = skb->len;
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL) {
+ if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
return 0;
}
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index 90b818a8de6e..cab0dd958492 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -231,8 +231,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
length = skb->len;
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 9b7805be21da..c158eedc7813 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -1349,8 +1349,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
#if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE)
if (skb->ip_summed == CHECKSUM_HW) {
- skb = skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK);
- if (skb == NULL)
+ if (skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK))
return NETDEV_TX_OK;
}
#endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index fdc21037f6dc..c80a4f1d5f7a 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1284,11 +1284,8 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
/* Calculate the next Tx descriptor entry. */
entry = rp->cur_tx % TX_RING_SIZE;
- if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
- }
+ if (skb_padto(skb, ETH_ZLEN))
+ return 0;
rp->tx_skbuff[entry] = skb;
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 879eb427607c..a915fe6c6aa5 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -924,8 +924,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN)
{
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index f7724eb2fa7e..561250f73fd3 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -3194,11 +3194,8 @@ wavelan_packet_xmit(struct sk_buff * skb,
* and we don't have the Ethernet specific requirement of beeing
* able to detect collisions, therefore in theory we don't really
* need to pad. Jean II */
- if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
- }
+ if (skb_padto(skb, ETH_ZLEN))
+ return 0;
wv_packet_write(dev, skb->data, skb->len);
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index fd0f43b7db5b..ecec8e5db786 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -862,13 +862,11 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Fix GX chipset errata. */
if (cacheline_end > 24 || cacheline_end == 0) {
len = skb->len + 32 - cacheline_end + 1;
- if (len != skb->len)
- skb = skb_padto(skb, len);
- }
- if (skb == NULL) {
- yp->tx_skbuff[entry] = NULL;
- netif_wake_queue(dev);
- return 0;
+ if (skb_padto(skb, len)) {
+ yp->tx_skbuff[entry] = NULL;
+ netif_wake_queue(dev);
+ return 0;
+ }
}
}
yp->tx_skbuff[entry] = skb;
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index 3ac047bc727d..a7c089df66e6 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -544,8 +544,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
if (length < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
+ if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 66f8819f9568..f8c7eb79a27f 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -345,7 +345,7 @@ extern struct sk_buff *skb_realloc_headroom(struct sk_buff *skb,
extern struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
int newheadroom, int newtailroom,
gfp_t priority);
-extern struct sk_buff * skb_pad(struct sk_buff *skb, int pad);
+extern int skb_pad(struct sk_buff *skb, int pad);
#define dev_kfree_skb(a) kfree_skb(a)
extern void skb_over_panic(struct sk_buff *skb, int len,
void *here);
@@ -1122,16 +1122,15 @@ static inline int skb_cow(struct sk_buff *skb, unsigned int headroom)
*
* Pads up a buffer to ensure the trailing bytes exist and are
* blanked. If the buffer already contains sufficient data it
- * is untouched. Returns the buffer, which may be a replacement
- * for the original, or NULL for out of memory - in which case
- * the original buffer is still freed.
+ * is untouched. Otherwise it is extended. Returns zero on
+ * success. The skb is freed on error.
*/
-static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len)
+static inline int skb_padto(struct sk_buff *skb, unsigned int len)
{
unsigned int size = skb->len;
if (likely(size >= len))
- return skb;
+ return 0;
return skb_pad(skb, len-size);
}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index bb7210f4005e..fe63d4efbd4d 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -781,24 +781,40 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
* filled. Used by network drivers which may DMA or transfer data
* beyond the buffer end onto the wire.
*
- * May return NULL in out of memory cases.
+ * May return error in out of memory cases. The skb is freed on error.
*/
-struct sk_buff *skb_pad(struct sk_buff *skb, int pad)
+int skb_pad(struct sk_buff *skb, int pad)
{
- struct sk_buff *nskb;
+ int err;
+ int ntail;
/* If the skbuff is non linear tailroom is always zero.. */
- if (skb_tailroom(skb) >= pad) {
+ if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) {
memset(skb->data+skb->len, 0, pad);
- return skb;
+ return 0;
}
-
- nskb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + pad, GFP_ATOMIC);
+
+ ntail = skb->data_len + pad - (skb->end - skb->tail);
+ if (likely(skb_cloned(skb) || ntail > 0)) {
+ err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC);
+ if (unlikely(err))
+ goto free_skb;
+ }
+
+ /* FIXME: The use of this function with non-linear skb's really needs
+ * to be audited.
+ */
+ err = skb_linearize(skb);
+ if (unlikely(err))
+ goto free_skb;
+
+ memset(skb->data + skb->len, 0, pad);
+ return 0;
+
+free_skb:
kfree_skb(skb);
- if (nskb)
- memset(nskb->data+nskb->len, 0, pad);
- return nskb;
+ return err;
}
/* Trims skb to length len. It can change skb pointers.