diff options
author | Michal Kubeček <mkubecek@suse.cz> | 2017-06-29 11:13:36 +0200 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2017-09-15 18:30:16 +0100 |
commit | 96f30d3ea5241db59cc9ae9787df195e19f3d2bd (patch) | |
tree | aa749f664be43c499e67d5ee70b4b0950832544f | |
parent | 5a74f081200c711f516a4eeb729c6568438d974a (diff) | |
download | linux-stable-96f30d3ea5241db59cc9ae9787df195e19f3d2bd.tar.gz linux-stable-96f30d3ea5241db59cc9ae9787df195e19f3d2bd.tar.bz2 linux-stable-96f30d3ea5241db59cc9ae9787df195e19f3d2bd.zip |
net: handle NAPI_GRO_FREE_STOLEN_HEAD case also in napi_frags_finish()
commit e44699d2c28067f69698ccb68dd3ddeacfebc434 upstream.
Recently I started seeing warnings about pages with refcount -1. The
problem was traced to packets being reused after their head was merged into
a GRO packet by skb_gro_receive(). While bisecting the issue pointed to
commit c21b48cc1bbf ("net: adjust skb->truesize in ___pskb_trim()") and
I have never seen it on a kernel with it reverted, I believe the real
problem appeared earlier when the option to merge head frag in GRO was
implemented.
Handling NAPI_GRO_FREE_STOLEN_HEAD state was only added to GRO_MERGED_FREE
branch of napi_skb_finish() so that if the driver uses napi_gro_frags()
and head is merged (which in my case happens after the skb_condense()
call added by the commit mentioned above), the skb is reused including the
head that has been merged. As a result, we release the page reference
twice and eventually end up with negative page refcount.
To fix the problem, handle NAPI_GRO_FREE_STOLEN_HEAD in napi_frags_finish()
the same way it's done in napi_skb_finish().
Fixes: d7e8883cfcf4 ("net: make GRO aware of skb->head_frag")
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
Signed-off-by: David S. Miller <davem@davemloft.net>
[bwh: Backported to 3.16: The necessary cleanup is just kmem_cache_free(),
so don't bother adding a function for this.]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r-- | net/core/dev.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 278faa3933ad..869a04d5558d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4166,10 +4166,16 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, break; case GRO_DROP: - case GRO_MERGED_FREE: napi_reuse_skb(napi, skb); break; + case GRO_MERGED_FREE: + if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) + kmem_cache_free(skbuff_head_cache, skb); + else + napi_reuse_skb(napi, skb); + break; + case GRO_MERGED: break; } |