Skip to content

Commit

Permalink
net: don't reallocate skb->head unless the current one hasn't the nee…
Browse files Browse the repository at this point in the history
…ded extra size or is shared

skb head being allocated by kmalloc(), it might be larger than what
actually requested because of discrete kmem caches sizes. Before
reallocating a new skb head, check if the current one has the needed
extra size.

Do this check only if skb head is not shared.

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Changli Gao authored and David S. Miller committed Dec 3, 2010
1 parent 289700d commit ca44ac3
Showing 1 changed file with 23 additions and 11 deletions.
34 changes: 23 additions & 11 deletions net/core/skbuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,28 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,

size = SKB_DATA_ALIGN(size);

/* Check if we can avoid taking references on fragments if we own
* the last reference on skb->head. (see skb_release_data())
*/
if (!skb->cloned)
fastpath = true;
else {
int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;

fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
}

if (fastpath &&
size + sizeof(struct skb_shared_info) <= ksize(skb->head)) {
memmove(skb->head + size, skb_shinfo(skb),
offsetof(struct skb_shared_info,
frags[skb_shinfo(skb)->nr_frags]));
memmove(skb->head + nhead, skb->head,
skb_tail_pointer(skb) - skb->head);
off = nhead;
goto adjust_others;
}

data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
if (!data)
goto nodata;
Expand All @@ -791,17 +813,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
skb_shinfo(skb),
offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));

/* Check if we can avoid taking references on fragments if we own
* the last reference on skb->head. (see skb_release_data())
*/
if (!skb->cloned)
fastpath = true;
else {
int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;

fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
}

if (fastpath) {
kfree(skb->head);
} else {
Expand All @@ -816,6 +827,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
off = (data + nhead) - skb->head;

skb->head = data;
adjust_others:
skb->data += off;
#ifdef NET_SKBUFF_DATA_USES_OFFSET
skb->end = size;
Expand Down

0 comments on commit ca44ac3

Please sign in to comment.