Thread (28 messages) 28 messages, 5 authors, 2017-08-13

Re: unregister_netdevice: waiting for eth0 to become free. Usage count = 1

flat view

From: David Ahern <hidden>
Date: 2017-08-13 16:24:57
Also in: lkml

On 8/12/17 1:42 PM, Wei Wang wrote:
Hi Ido,
quoted
quoted
-     if ((rt->dst.dev == dev || !dev) &&
+     if ((rt->dst.dev == dev || !dev ||
+          rt->rt6i_idev->dev == dev) &&
Can you please explain why this line is needed? While host routes aren't
removed from the FIB by rt6_ifdown() (when dst.dev goes down), they are
removed later on in addrconf_ifdown().
Yes.. Agree. But one difference is that if the route is removed from
addrconf_ifdown(), dst_dev_put() won't be called to release the
devices before doing dst_release(). It is OK if dst_release() sees the
refcnt on dst already drops to 0 and directly destroys the dst. But I
think it will cause problem if at the time, the dst is still held by
some other users because then the refcnt on the device going down will
not get released.
That's why I think we should remove the dst with either dst->dev ==
going down dev or rt6->rt6i_idev->dev == going down dev from the fib6
tree always because there, we always call dst_dev_put() to release the
device.
quoted
With your patch, if I check the return value of ip6_del_rt() in
__ipv6_ifa_notify() I see that -ENONET is returned. Because the host
route was already removed by rt6_ifdown(). When the line in question is
removed from the patch I don't get the error anymore.
Right. That is expected as the route is already removed from the tree.
quoted
Is it possible that in John's case the host route was correctly removed
from the FIB and that the unreleased reference was due to a wrong check
in ip6_dst_ifdown() (which you patched correctly AFAICT)?
Yes. possible. But as I explained earlier, I still think we should
also remove routes with rt6->rt6i_idev->dev == going down dev from the
tree.
Looking at my patch to move host routes from loopback to device with the
address, I have this:
@@ -2789,7 +2808,8 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg)
        const struct arg_dev_net *adn = arg;
        const struct net_device *dev = adn->dev;

-       if ((rt->dst.dev == dev || !dev) &&
+       if ((rt->dst.dev == dev || !dev ||
+            (netdev_unregistering(dev) && rt->rt6i_idev->dev == dev)) &&
            rt != adn->net->ipv6.ip6_null_entry &&
            (rt->rt6i_nsiblings == 0 ||
             (dev && netdev_unregistering(dev)) ||
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help