Message ID | 1416599236.8629.124.camel@edumazet-glaptop2.roam.corp.google.com |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
From: Eric Dumazet <eric.dumazet@gmail.com> Date: Fri, 21 Nov 2014 11:47:16 -0800 > From: Eric Dumazet <edumazet@google.com> > > Not sure what I was thinking, but doing anything after > releasing a refcount is suicidal or/and embarrassing. > > By the time we set skb->fclone to SKB_FCLONE_FREE, another cpu > could have released last reference and freed whole skb. > > We potentially corrupt memory or trap if CONFIG_DEBUG_PAGEALLOC is set. > > Reported-by: Chris Mason <clm@fb.com> > Fixes: ce1a4ea3f1258 ("net: avoid one atomic operation in skb_clone()") > Signed-off-by: Eric Dumazet <edumazet@google.com> > Cc: Sabrina Dubroca <sd@queasysnail.net> > --- > v2: the revert went wrong, as SKB_FCLONE_UNAVAILABLE > was later replaced by SKB_FCLONE_FREE, spotted by Sabrina Dubroca Applied, thanks Eric. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Nov 21, 2014 at 2:47 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote: > From: Eric Dumazet <edumazet@google.com> > > v2: the revert went wrong, as SKB_FCLONE_UNAVAILABLE > was later replaced by SKB_FCLONE_FREE, spotted by Sabrina Dubroca > v2 is happy here too. I'll let it keep going over the weekend and add more memory pressure, but my crashes seem to be gone. -chris -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c16615bfb61e..be4c7deed971 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -552,20 +552,13 @@ static void kfree_skbmem(struct sk_buff *skb) case SKB_FCLONE_CLONE: fclones = container_of(skb, struct sk_buff_fclones, skb2); - /* Warning : We must perform the atomic_dec_and_test() before - * setting skb->fclone back to SKB_FCLONE_FREE, otherwise - * skb_clone() could set clone_ref to 2 before our decrement. - * Anyway, if we are going to free the structure, no need to - * rewrite skb->fclone. + /* The clone portion is available for + * fast-cloning again. */ - if (atomic_dec_and_test(&fclones->fclone_ref)) { + skb->fclone = SKB_FCLONE_FREE; + + if (atomic_dec_and_test(&fclones->fclone_ref)) kmem_cache_free(skbuff_fclone_cache, fclones); - } else { - /* The clone portion is available for - * fast-cloning again. - */ - skb->fclone = SKB_FCLONE_FREE; - } break; } } @@ -887,11 +880,7 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) if (skb->fclone == SKB_FCLONE_ORIG && n->fclone == SKB_FCLONE_FREE) { n->fclone = SKB_FCLONE_CLONE; - /* As our fastclone was free, clone_ref must be 1 at this point. - * We could use atomic_inc() here, but it is faster - * to set the final value. - */ - atomic_set(&fclones->fclone_ref, 2); + atomic_inc(&fclones->fclone_ref); } else { if (skb_pfmemalloc(skb)) gfp_mask |= __GFP_MEMALLOC;