[Click] 2.6 update - Bug + Fix
Eddie Kohler
kohler at cs.ucla.edu
Wed Jun 28 12:47:20 EDT 2006
Beyers,
Thanks much for this fix! However there are a couple problems with it. You
say this:
!(atomic_read(&skb_shinfo(skb)->dataref) - skb->nohdr ? (1 <<
SKB_DATAREF_SHIFT) + 1 : 1))
Because of C precedence rules this gets parsed as
!( (atomic_read(&skb_shinfo(skb)->dataref) - skb->nohdr)
? (1 << SKB_DATAREF_SHIFT) + 1
: 1 )
which is always true. So skbs never get recycled in your code.
I've checked in a different fix, which changes the if statement to:
if (skb->fclone == SKB_FCLONE_UNAVAILABLE
&& (!skb->cloned ||
atomic_read(&skb_shinfo(skb)->dataref) == (skb->nohdr ? (1 <<
SKB_DATAREF_SHIFT) + 1 : 1))) {
There is no need for a following atomic_sub, since dataref is set to 1 below
anyway.
Does this work for you?
Eddie
Beyers Cronje wrote:
> Hi Eddie,
>
> I found the bug I reported earlier on the new etc/linux-2.6.16.13-patch
> you posted below. The problem is that skb_recycle does a
> atomic_sub_return on the skb dataref if the skb is cloned. If the skb
> data-reference is more than 1, ie shared by another skb and the
> recycling condition fails, skb_recycle calls kfree_skbmem, which in
> turns calls skb_release_data which does another atomic_sub_return on
> the dataref of the skb. This double subtraction on dataref on the same
> skb will obviously cause skb_release_data to prematurely free the packet
> data.
>
> The attached patch fixes this by first checking using atomic_read on
> dataref, and only calls atomic_sub after we know we can recycle the skb.
>
> I'm not sure what performance impact the additional atomic operation
> will have.
>
> Cheers
>
> Beyers Cronje
>
> if (skb->fclone == SKB_FCLONE_UNAVAILABLE
> && (!skb->cloned ||
> - !atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) +
> 1 : 1,
> - &skb_shinfo(skb)->dataref))) {
> + !(atomic_read(&skb_shinfo(skb)->dataref) - skb->nohdr ? (1
> << SKB_DATAREF_SHIFT) + 1 : 1))) {
> + if (skb->cloned)
> + atomic_sub(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 :
> 1,&skb_shinfo(skb)->dataref);
> if (skb_shinfo(skb)->nr_frags) {
> int i;
> for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
>
>
>
> On 6/23/06, *Eddie Kohler* <kohler at cs.ucla.edu
> <mailto:kohler at cs.ucla.edu>> wrote:
>
> Hi all,
>
> A brief update on Linux 2.6 kernel module support. We've just
> checked in a
> fix that plugs a large memory leak of sk_buffs. You will need to
> re-patch
> your kernels with the current etc/linux-2.6.16.13-patch . FYI.
>
> Eddie
> _______________________________________________
> click mailing list
> click at amsterdam.lcs.mit.edu <mailto:click at amsterdam.lcs.mit.edu>
> https://amsterdam.lcs.mit.edu/mailman/listinfo/click
>
>
>
> ------------------------------------------------------------------------
>
> --- click.skbuff.c 2006-06-28 07:05:40.000000000 +0200
> +++ src/linux-2.6.16.13/net/core/skbuff.c 2006-06-28 06:21:23.000000000 +0200
> @@ -570,8 +570,9 @@
>
> if (skb->fclone == SKB_FCLONE_UNAVAILABLE
> && (!skb->cloned ||
> - !atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1,
> - &skb_shinfo(skb)->dataref))) {
> + !(atomic_read(&skb_shinfo(skb)->dataref) - skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1))) {
> + if (skb->cloned)
> + atomic_sub(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1,&skb_shinfo(skb)->dataref);
> if (skb_shinfo(skb)->nr_frags) {
> int i;
> for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
More information about the click
mailing list