ipv6: release rt6->rt6i_idev properly during ifdown
When a dst is created by addrconf_dst_alloc() for a host route or an
anycast route, dst->dev points to loopback dev while rt6->rt6i_idev
points to a real device.
When the real device goes down, the current cleanup code only checks for
dst->dev and assumes rt6->rt6i_idev->dev is the same. This causes the
refcount leak on the real device in the above situation.
This patch makes sure to always release the refcount taken on
rt6->rt6i_idev during dst_dev_put().
Fixes: 587fea7411
("ipv6: mark DST_NOGC and remove the operation of
dst_free()")
Reported-by: John Stultz <john.stultz@linaro.org>
Tested-by: John Stultz <john.stultz@linaro.org>
Tested-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Wei Wang <weiwan@google.com>
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
36f41f8fc6
commit
e5645f51ba
|
@ -417,14 +417,11 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
|
|||
struct net_device *loopback_dev =
|
||||
dev_net(dev)->loopback_dev;
|
||||
|
||||
if (dev != loopback_dev) {
|
||||
if (idev && idev->dev == dev) {
|
||||
struct inet6_dev *loopback_idev =
|
||||
in6_dev_get(loopback_dev);
|
||||
if (loopback_idev) {
|
||||
rt->rt6i_idev = loopback_idev;
|
||||
in6_dev_put(idev);
|
||||
}
|
||||
if (idev && idev->dev != loopback_dev) {
|
||||
struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
|
||||
if (loopback_idev) {
|
||||
rt->rt6i_idev = loopback_idev;
|
||||
in6_dev_put(idev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue