ipmr.c uses unregister_netdevice() to remove DVMRP tunnel devices created in ipmr_new_tunnel(). This is fine because currently ip_tunnel_uninit() also calls ip_tunnel_del() to unlink the device from the hash table. However, we will move ip_tunnel_del() from ip_tunnel_uninit() to ip_tunnel_dellink(). Removing DVMRP tunnel devices by unregister_netdevice() would leave them in the hash table. Let's call ->dellink for DVMRP tunnel devices. Signed-off-by: Kuniyuki Iwashima --- v2: Correct commit message --- net/ipv4/ipmr.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index e5f2b1c6150d..02edf9d7f4b5 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -479,6 +479,7 @@ static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) { struct net_device *tunnel_dev, *new_dev; struct ip_tunnel_parm_kern p = { }; + LIST_HEAD(dev_kill_list); int err; tunnel_dev = __dev_get_by_name(net, "tunl0"); @@ -520,7 +521,8 @@ static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) return new_dev; out_unregister: - unregister_netdevice(new_dev); + new_dev->rtnl_link_ops->dellink(new_dev, &dev_kill_list); + unregister_netdevice_many(&dev_kill_list); out: return ERR_PTR(-ENOBUFS); } @@ -733,8 +735,12 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify, ip_rt_multicast_event(in_dev); } - if (v->flags & (VIFF_TUNNEL | VIFF_REGISTER) && !notify) - unregister_netdevice_queue(dev, head); + if (!notify) { + if (v->flags & VIFF_TUNNEL) + dev->rtnl_link_ops->dellink(dev, head); + else if (v->flags & VIFF_REGISTER) + unregister_netdevice_queue(dev, head); + } netdev_put(dev, &v->dev_tracker); return 0; -- 2.55.0.1003.g10538fe699-goog