Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751756AbdHMU4f (ORCPT ); Sun, 13 Aug 2017 16:56:35 -0400 Received: from mail-vk0-f50.google.com ([209.85.213.50]:36078 "EHLO mail-vk0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750867AbdHMU4c (ORCPT ); Sun, 13 Aug 2017 16:56:32 -0400 MIME-Version: 1.0 In-Reply-To: <61d95fe2-edfd-9fc4-5e21-5b96e4e03c9f@gmail.com> References: <20170812180129.GA31700@splinter> <61d95fe2-edfd-9fc4-5e21-5b96e4e03c9f@gmail.com> From: Wei Wang Date: Sun, 13 Aug 2017 13:56:30 -0700 Message-ID: Subject: Re: unregister_netdevice: waiting for eth0 to become free. Usage count = 1 To: David Ahern Cc: Ido Schimmel , Cong Wang , John Stultz , Martin KaFai Lau , lkml , Network Development , Linux USB List , "David S. Miller" , Felipe Balbi Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3618 Lines: 86 > 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)) || As you explained earlier, after your patch, all entries in the fib6 tree will have rt->dst.dev be the same as rt->rt6i_idev->dev except those ones created by p6_rt_cache_alloc() and ip6_rt_pcpu_alloc(). Then the above newly added check is mainly to catch those cached dst entries (created by ip6_rt_cached_alloc()). right? And it is required because __ipv6_ifa_notify() -> ip6_del_rt() won't take care of those cached dst entries. Then I think I should wait for your patches to get merged before submitting my patch? Thanks. Wei On Sun, Aug 13, 2017 at 9:24 AM, David Ahern wrote: > On 8/12/17 1:42 PM, Wei Wang wrote: >> Hi Ido, >> >>>> - 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. >> >>> 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. >> >>> 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)) || > >