diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2006-06-23 05:06:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-06-23 05:06:41 -0400 |
commit | 5b057c6b1a25d57edf2b4d1e956e50936480a9ff (patch) | |
tree | e641febd6f562e0ed1198c160ff353ab513f0612 /net | |
parent | 5fa21d821f6972e70942f2c555ec29dde962bdb2 (diff) |
[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>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/skbuff.c | 36 |
1 files changed, 26 insertions, 10 deletions
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, | |||
781 | * filled. Used by network drivers which may DMA or transfer data | 781 | * filled. Used by network drivers which may DMA or transfer data |
782 | * beyond the buffer end onto the wire. | 782 | * beyond the buffer end onto the wire. |
783 | * | 783 | * |
784 | * May return NULL in out of memory cases. | 784 | * May return error in out of memory cases. The skb is freed on error. |
785 | */ | 785 | */ |
786 | 786 | ||
787 | struct sk_buff *skb_pad(struct sk_buff *skb, int pad) | 787 | int skb_pad(struct sk_buff *skb, int pad) |
788 | { | 788 | { |
789 | struct sk_buff *nskb; | 789 | int err; |
790 | int ntail; | ||
790 | 791 | ||
791 | /* If the skbuff is non linear tailroom is always zero.. */ | 792 | /* If the skbuff is non linear tailroom is always zero.. */ |
792 | if (skb_tailroom(skb) >= pad) { | 793 | if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) { |
793 | memset(skb->data+skb->len, 0, pad); | 794 | memset(skb->data+skb->len, 0, pad); |
794 | return skb; | 795 | return 0; |
795 | } | 796 | } |
796 | 797 | ||
797 | nskb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + pad, GFP_ATOMIC); | 798 | ntail = skb->data_len + pad - (skb->end - skb->tail); |
799 | if (likely(skb_cloned(skb) || ntail > 0)) { | ||
800 | err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC); | ||
801 | if (unlikely(err)) | ||
802 | goto free_skb; | ||
803 | } | ||
804 | |||
805 | /* FIXME: The use of this function with non-linear skb's really needs | ||
806 | * to be audited. | ||
807 | */ | ||
808 | err = skb_linearize(skb); | ||
809 | if (unlikely(err)) | ||
810 | goto free_skb; | ||
811 | |||
812 | memset(skb->data + skb->len, 0, pad); | ||
813 | return 0; | ||
814 | |||
815 | free_skb: | ||
798 | kfree_skb(skb); | 816 | kfree_skb(skb); |
799 | if (nskb) | 817 | return err; |
800 | memset(nskb->data+nskb->len, 0, pad); | ||
801 | return nskb; | ||
802 | } | 818 | } |
803 | 819 | ||
804 | /* Trims skb to length len. It can change skb pointers. | 820 | /* Trims skb to length len. It can change skb pointers. |