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

Wei Wang
2017-08-10T05:41:04Z

[-- Attachment #1: Type: text/plain, Size: 3622 bytes --]

Hi John,

Is it possible to try the attached patch?
I am not sure if it actually fixes the issue. But I think it is worth a try.
Also, could you get me all the ipv6 routes when you plug in the usb
using "ip -6 route show"? (If you have multiple routing tables
configured, could you dump them all?)

Thanks a lot.
Wei

On Wed, Aug 9, 2017 at 6:36 PM, Wei Wang <weiwan@google.com> wrote:
> On Wed, Aug 9, 2017 at 6:26 PM, John Stultz <john.stultz@linaro.org> wrote:
>> On Wed, Aug 9, 2017 at 5:36 PM, Wei Wang <weiwan@google.com> wrote:
>>> On Wed, Aug 9, 2017 at 4:44 PM, John Stultz <john.stultz@linaro.org> wrote:
>>>> On Wed, Aug 9, 2017 at 4:34 PM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
>>>>> (Cc'ing Wei whose commit was blamed)
>>>>>
>>>>> On Mon, Aug 7, 2017 at 2:15 PM, John Stultz <john.stultz@linaro.org> wrote:
>>>>>> On Mon, Aug 7, 2017 at 2:05 PM, John Stultz <john.stultz@linaro.org> wrote:
>>>>>>> So, with recent testing with my HiKey board, I've been noticing some
>>>>>>> quirky behavior with my USB eth adapter.
>>>>>>>
>>>>>>> Basically, pluging the usb eth adapter in and then removing it, when
>>>>>>> plugging it back in I often find that its not detected, and the system
>>>>>>> slowly spits out the following message over and over:
>>>>>>> unregister_netdevice: waiting for eth0 to become free. Usage count = 1
>>>>>>
>>>>>> The other bit is that after this starts printing, the board will no
>>>>>> longer reboot (it hangs continuing to occasionally print the above
>>>>>> message), and I have to manually reset the device.
>>>>>>
>>>>>
>>>>> So this warning is not temporarily shown but lasts until a reboot,
>>>>> right? If so it is a dst refcnt leak.
>>>>
>>>> Correct, once I get into the state it lasts until a reboot.
>>>>
>>>>> How reproducible is it for you? From my reading, it seems always
>>>>> reproduced when you unplug and plug your usb eth interface?
>>>>> Is there anything else involved? For example, network namespace.
>>>>
>>>> So with 4.13-rc3/4 I seem to trigger it easily, often with the first
>>>> unplug of the USB eth adapter.
>>>>
>>>> But as I get back closer to 4.12, it seemingly becomes harder to
>>>> trigger, but sometimes still happens.
>>>>
>>>> So far, I've not been able to trigger it with 4.12.
>>>>
>>>> I don't think network namespaces are involved? Though its out of my
>>>> area, so AOSP may be using them these days. Is there a simple way to
>>>> check?
>>>>
>>>> I'll also do another bisection to see if the bad point moves back any further.
>>
>> So I went through another bisection around and got 9514528d92d4 ipv6:
>> call dst_dev_put() properly as the first bad commit again.
>>
>>> If you see the problem starts to happen on commit
>>> 9514528d92d4cbe086499322370155ed69f5d06c, could you try reverting all
>>> the following commits:
>>> (from new to old)
>>> 1eb04e7c9e63 net: reorder all the dst flags
>>> a4c2fd7f7891 net: remove DST_NOCACHE flag
>>> b2a9c0ed75a3 net: remove DST_NOGC flag
>>> 5b7c9a8ff828 net: remove dst gc related code
>>> db916649b5dd ipv6: get rid of icmp6 dst garbage collector
>>> 587fea741134 ipv6: mark DST_NOGC and remove the operation of dst_free()
>>> ad65a2f05695 ipv6: call dst_hold_safe() properly
>>> 9514528d92d4 ipv6: call dst_dev_put() properly
>>
>>
>> And reverting this set off of 4.13-rc4 seems to make the issue go away.
>>
>> Is there anything I can test to help narrow down the specific problem
>> with that patchset?
>>
>
> Thanks John for confirming.
> Let me spend some time on the commits and I will let you know if I
> have some debug image for you to try.
>
> Wei
>
>
>> thanks
>> -john

[-- Attachment #2: 0001-ipv6-unregister-netdev-bug-fix.patch --]
[-- Type: text/x-patch, Size: 3300 bytes --]

From 93f2836679c81915b110ff56617f9f5dae2e6927 Mon Sep 17 00:00:00 2001
From: Wei Wang <weiwan@google.com>
Date: Wed, 9 Aug 2017 22:27:36 -0700
Subject: [PATCH] ipv6: unregister netdev bug fix

Change-Id: I30fa739989ac50fbc7f4cbc6a04130005589cc25
---
include/net/ip6_route.h | 1 +
net/ipv6/addrconf.c | 10 +++++++---
net/ipv6/anycast.c | 3 ++-
net/ipv6/route.c | 2 +-
4 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 907d39a42f6b..dec1424ce619 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -94,6 +94,7 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg);
int ip6_route_add(struct fib6_config *cfg, struct netlink_ext_ack *extack);
int ip6_ins_rt(struct rt6_info *);
int ip6_del_rt(struct rt6_info *);
+void rt6_uncached_list_add(struct rt6_info *rt);

static inline int ip6_route_get_saddr(struct net *net, struct rt6_info *rt,
const struct in6_addr *daddr,
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3c46e9513a31..06a27addb93c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3079,7 +3079,8 @@ static void init_loopback(struct net_device *dev)
/* Failure cases are ignored */
if (!IS_ERR(sp_rt)) {
sp_ifa->rt = sp_rt;
- ip6_ins_rt(sp_rt);
+ if (ip6_ins_rt(sp_rt))
+ rt6_uncached_list_add(sp_rt);
}
}
read_unlock_bh(&idev->lock);
@@ -3711,6 +3712,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
rt = ifa->rt;
ifa->rt = NULL;
} else {
+ rt6_uncached_list_add(ifa->rt);
state = ifa->state;
ifa->state = INET6_IFADDR_STATE_DEAD;
}
@@ -3882,7 +3884,8 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
* Frames right away
*/
if (ifp->flags & IFA_F_OPTIMISTIC) {
- ip6_ins_rt(ifp->rt);
+ if (ip6_ins_rt(ifp->rt))
+ rt6_uncached_list_add(ifp->rt);
if (ipv6_use_optimistic_addr(idev)) {
/* Because optimistic nodes can use this address,
* notify listeners. If DAD fails, RTM_DELADDR is sent.
@@ -5557,7 +5560,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
* to do it again
*/
if (!(ifp->rt->rt6i_node))
- ip6_ins_rt(ifp->rt);
+ if(ip6_ins_rt(ifp->rt))
+ rt6_uncached_list_add(ifp->rt);
if (ifp->idev->cnf.forwarding)
addrconf_join_anycast(ifp);
if (!ipv6_addr_any(&ifp->peer_addr))
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 0bbab8a4b5d8..e21c2d6d9b95 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -283,7 +283,8 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
aca_get(aca);
write_unlock_bh(&idev->lock);

- ip6_ins_rt(rt);
+ if (!ip6_ins_rt(rt))
+ rt6_uncached_list_add(rt);

addrconf_join_solict(idev->dev, &aca->aca_addr);

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 4d30c96a819d..7a7299da4e09 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -124,7 +124,7 @@ struct uncached_list {

static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);

-static void rt6_uncached_list_add(struct rt6_info *rt)
+void rt6_uncached_list_add(struct rt6_info *rt)
{
struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);

--
2.14.0.434.g98096fd7a8-goog