[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20100921104821.GA8986@ff.dom.local>
Date: Tue, 21 Sep 2010 10:48:21 +0000
From: Jarek Poplawski <jarkao2@...il.com>
To: Eric Dumazet <eric.dumazet@...il.com>
Cc: Nick Bowler <nbowler@...iptictech.com>,
linux-kernel@...r.kernel.org, netdev@...r.kernel.org,
"David S. Miller" <davem@...emloft.net>
Subject: Re: Regression, bisected: reference leak with IPSec since ~2.6.31
On Tue, Sep 21, 2010 at 12:07:37PM +0200, Eric Dumazet wrote:
> Le mardi 21 septembre 2010 ?? 11:55 +0200, Eric Dumazet a écrit :
> > Le mardi 21 septembre 2010 ?? 09:38 +0000, Jarek Poplawski a écrit :
> > > On Tue, Sep 21, 2010 at 11:21:00AM +0200, Eric Dumazet wrote:
> >
> > > I hope you're right with this.
> > >
> > > >
> > > > I liked the :
> > > >
> > > > <check everything without changing state>
> > > > if something wrong
> > > > goto slow_path
> > > > else
> > > > <OK, lets do destructive things>
> > > >
> > >
> > > But it's an optimization of the "unlikely" case btw. ;-)
> > >
> >
> > This is a bug fix, in a complex function.
> >
> > in -next branch, we can try to be smart, adding more code in slow_path
> > to revert what was done in the hope fast path would be taken.
> > And pray we dont add another bug :)
But if you were honest about caches there is no reason to be smart
no more. ;-)
Below is your patch mostly as an example only that I didn't mean
nothing complex (ipv4 only, not compiled).
Jarek P.
---
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 04b6989..049d61f 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -490,7 +490,6 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
if (skb_has_frags(skb)) {
struct sk_buff *frag;
int first_len = skb_pagelen(skb);
- int truesizes = 0;
if (first_len - hlen > mtu ||
((first_len - hlen) & 7) ||
@@ -503,18 +502,18 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
if (frag->len > mtu ||
((frag->len & 7) && frag->next) ||
skb_headroom(frag) < hlen)
- goto slow_path;
+ goto slow_path_clean;
/* Partially cloned skb? */
if (skb_shared(frag))
- goto slow_path;
+ goto slow_path_clean;
BUG_ON(frag->sk);
if (skb->sk) {
frag->sk = skb->sk;
frag->destructor = sock_wfree;
+ skb->truesize -= frag->truesize;
}
- truesizes += frag->truesize;
}
/* Everything is OK. Generate! */
@@ -524,7 +523,6 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
frag = skb_shinfo(skb)->frag_list;
skb_frag_list_init(skb);
skb->data_len = first_len - skb_headlen(skb);
- skb->truesize -= truesizes;
skb->len = first_len;
iph->tot_len = htons(first_len);
iph->frag_off = htons(IP_MF);
@@ -576,6 +574,17 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
}
IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
return err;
+
+slow_path_clean:
+ if (skb->sk) {
+ skb_walk_frags(skb, frag) {
+ if (!frag->sk)
+ break;
+ frag->sk = NULL;
+ frag->destructor = NULL;
+ skb->truesize += frag->truesize;
+ }
+ }
}
slow_path:
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists