diff options
author | Martin KaFai Lau <kafai@fb.com> | 2015-09-15 14:30:08 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-09-15 14:53:05 -0700 |
commit | 8e3d5be7368107f0c27a1f8126d79b01a47e9567 (patch) | |
tree | 9930ab62052124ba2e56db04cdbab518a533f4bc /net/ipv6/addrconf.c | |
parent | cdf3464e6c6bd764277cbbe992cd12da735b92fb (diff) | |
download | linux-rpi-8e3d5be7368107f0c27a1f8126d79b01a47e9567.tar.gz linux-rpi-8e3d5be7368107f0c27a1f8126d79b01a47e9567.tar.bz2 linux-rpi-8e3d5be7368107f0c27a1f8126d79b01a47e9567.zip |
ipv6: Avoid double dst_free
It is a prep work to get dst freeing from fib tree undergo
a rcu grace period.
The following is a common paradigm:
if (ip6_del_rt(rt))
dst_free(rt)
which means, if rt cannot be deleted from the fib tree, dst_free(rt) now.
1. We don't know the ip6_del_rt(rt) failure is because it
was not managed by fib tree (e.g. DST_NOCACHE) or it had already been
removed from the fib tree.
2. If rt had been managed by the fib tree, ip6_del_rt(rt) failure means
dst_free(rt) has been called already. A second
dst_free(rt) is not always obviously safe. The rt may have
been destroyed already.
3. If rt is a DST_NOCACHE, dst_free(rt) should not be called.
4. It is a stopper to make dst freeing from fib tree undergo a
rcu grace period.
This patch is to use a DST_NOCACHE flag to indicate a rt is
not managed by the fib tree.
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 7 |
1 files changed, 3 insertions, 4 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 030fefdc9aed..900113376d4e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -5127,13 +5127,12 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) rt = addrconf_get_prefix_route(&ifp->peer_addr, 128, ifp->idev->dev, 0, 0); - if (rt && ip6_del_rt(rt)) - dst_free(&rt->dst); + if (rt) + ip6_del_rt(rt); } dst_hold(&ifp->rt->dst); - if (ip6_del_rt(ifp->rt)) - dst_free(&ifp->rt->dst); + ip6_del_rt(ifp->rt); rt_genid_bump_ipv6(net); break; |