On Tue, Nov 15, 2016 at 10:04 AM, Cong Wang <[email protected]> wrote:
> On Mon, Nov 14, 2016 at 10:23 PM, Andrei Vagin <[email protected]> wrote:
>> Hi Nicolas,
>>
>> cleanup_net() calls idr_destroy(net->netns_ids) for network namespaces
>> and then it calls unregister_netdevice_many() which calls
>> idr_alloc(net0>netns_ids). It looks wrong, doesn't it?
>>
>
> netns id is designed to allocate lazily, but yeah it makes no sense
> to allocate id for the netns being destroyed, not to mention idr is freed.
>
> I will send a patch.
Could you try the attached patch? I just did some quick netns creation/destroy
tests.
Thanks!
diff --git a/net/core/dev.c b/net/core/dev.c
index 6deba68..f9a2969 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6685,7 +6685,7 @@ static void net_set_todo(struct net_device *dev)
dev_net(dev)->dev_unreg_count++;
}
-static void rollback_registered_many(struct list_head *head)
+static void rollback_registered_many(struct list_head *head, bool send_rtmsg)
{
struct net_device *dev, *tmp;
LIST_HEAD(close_head);
@@ -6737,8 +6737,8 @@ static void rollback_registered_many(struct list_head
*head)
*/
call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
- if (!dev->rtnl_link_ops ||
- dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
+ if ((!dev->rtnl_link_ops ||
+ dev->rtnl_link_state == RTNL_LINK_INITIALIZED) &&
send_rtmsg)
skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U,
GFP_KERNEL);
@@ -6777,7 +6777,7 @@ static void rollback_registered(struct net_device *dev)
LIST_HEAD(single);
list_add(&dev->unreg_list, &single);
- rollback_registered_many(&single);
+ rollback_registered_many(&single, true);
list_del(&single);
}
@@ -7769,6 +7769,18 @@ void unregister_netdevice_queue(struct net_device *dev,
struct list_head *head)
}
EXPORT_SYMBOL(unregister_netdevice_queue);
+static void __unregister_netdevice_many(struct list_head *head, bool
send_rtmsg)
+{
+ struct net_device *dev;
+
+ if (!list_empty(head)) {
+ rollback_registered_many(head, send_rtmsg);
+ list_for_each_entry(dev, head, unreg_list)
+ net_set_todo(dev);
+ list_del(head);
+ }
+}
+
/**
* unregister_netdevice_many - unregister many devices
* @head: list of devices
@@ -7778,14 +7790,7 @@ EXPORT_SYMBOL(unregister_netdevice_queue);
*/
void unregister_netdevice_many(struct list_head *head)
{
- struct net_device *dev;
-
- if (!list_empty(head)) {
- rollback_registered_many(head);
- list_for_each_entry(dev, head, unreg_list)
- net_set_todo(dev);
- list_del(head);
- }
+ __unregister_netdevice_many(head, true);
}
EXPORT_SYMBOL(unregister_netdevice_many);
@@ -8239,7 +8244,7 @@ static void __net_exit default_device_exit_batch(struct
list_head *net_list)
unregister_netdevice_queue(dev, &dev_kill_list);
}
}
- unregister_netdevice_many(&dev_kill_list);
+ __unregister_netdevice_many(&dev_kill_list, false);
rtnl_unlock();
}