diff mbox

net: skip genenerating uevents for network namespaces that are exiting

Message ID 1477017986-18889-1-git-send-email-avagin@openvz.org
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Andrei Vagin Oct. 21, 2016, 2:46 a.m. UTC
No one can see these events, because a network namespace can not be
destroyed, if it has sockets.

My experiments shows that net namespaces are destroyed more 30% faster
with this optimization.

Here is a perf output for destroying network namespaces without this
patch.

-   94.76%     0.02%  kworker/u48:1  [kernel.kallsyms]     [k] cleanup_net
   - 94.74% cleanup_net
      - 94.64% ops_exit_list.isra.4
         - 41.61% default_device_exit_batch
            - 41.47% unregister_netdevice_many
               - rollback_registered_many
                  - 40.36% netdev_unregister_kobject
                     - 14.55% device_del
                        + 13.71% kobject_uevent
                     - 13.04% netdev_queue_update_kobjects
                        + 12.96% kobject_put
                     - 12.72% net_rx_queue_update_kobjects
                          kobject_put
                        - kobject_release
                           + 12.69% kobject_uevent
                  + 0.80% call_netdevice_notifiers_info
         + 19.57% nfsd_exit_net
         + 11.15% tcp_net_metrics_exit
         + 8.25% rpcsec_gss_exit_net

It's very critical to optimize the exit path for network namespaces,
because they are destroyed under net_mutex and many namespaces can be
destroyed for one iteration.

Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Andrei Vagin <avagin@openvz.org>
---
 net/core/net-sysfs.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

Comments

Cong Wang Oct. 21, 2016, 3:10 a.m. UTC | #1
On Thu, Oct 20, 2016 at 7:46 PM, Andrei Vagin <avagin@openvz.org> wrote:
> No one can see these events, because a network namespace can not be
> destroyed, if it has sockets.
>

Are you sure? kobject_uevent_env() seems sending uevents to all
network namespaces.
Andrei Vagin Oct. 21, 2016, 5:25 a.m. UTC | #2
On Thu, Oct 20, 2016 at 8:10 PM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> On Thu, Oct 20, 2016 at 7:46 PM, Andrei Vagin <avagin@openvz.org> wrote:
>> No one can see these events, because a network namespace can not be
>> destroyed, if it has sockets.
>>
>
> Are you sure? kobject_uevent_env() seems sending uevents to all
> network namespaces.

kobj_bcast_filter() checks that a kobject namespace is equal to a
socket namespace.


> _______________________________________________
> Containers mailing list
> Containers@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/containers
Andrei Vagin Oct. 22, 2016, 7:37 a.m. UTC | #3
Hi Cong,

On Thu, Oct 20, 2016 at 10:25 PM, Andrey Vagin <avagin@openvz.org> wrote:
> On Thu, Oct 20, 2016 at 8:10 PM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
>> On Thu, Oct 20, 2016 at 7:46 PM, Andrei Vagin <avagin@openvz.org> wrote:
>>> No one can see these events, because a network namespace can not be
>>> destroyed, if it has sockets.
>>>
>>
>> Are you sure? kobject_uevent_env() seems sending uevents to all
>> network namespaces.
>
> kobj_bcast_filter() checks that a kobject namespace is equal to a
> socket namespace.

Today I've checked that it really works as I read from the source code.
I use this tool to read events:
https://gist.github.com/avagin/430ba431fc2972002df40ebe6a048b36

And I see that events from non-network devices are delivered to all sockets,
but events from network devices are delivered only to sockets from
a network namespace where a device is operated.

Thanks,
Andrei

>
>
>> _______________________________________________
>> Containers mailing list
>> Containers@lists.linux-foundation.org
>> https://lists.linuxfoundation.org/mailman/listinfo/containers
David Miller Oct. 22, 2016, 9 p.m. UTC | #4
From: Andrei Vagin <avagin@openvz.org>
Date: Thu, 20 Oct 2016 19:46:26 -0700

> @@ -1525,6 +1530,9 @@ void netdev_unregister_kobject(struct net_device *ndev)
>  {
>  	struct device *dev = &(ndev->dev);
>  
> +	if (!list_empty(&dev_net(ndev)->exit_list))
> +		dev->kobj.uevent_suppress = 1;
> +

Please use "dev_set_uevent_suppress(dev, 1);"
Cong Wang Oct. 24, 2016, 5:17 p.m. UTC | #5
On Sat, Oct 22, 2016 at 12:37 AM, Andrey Vagin <avagin@openvz.org> wrote:
> Hi Cong,
>
> On Thu, Oct 20, 2016 at 10:25 PM, Andrey Vagin <avagin@openvz.org> wrote:
>> On Thu, Oct 20, 2016 at 8:10 PM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
>>> On Thu, Oct 20, 2016 at 7:46 PM, Andrei Vagin <avagin@openvz.org> wrote:
>>>> No one can see these events, because a network namespace can not be
>>>> destroyed, if it has sockets.
>>>>
>>>
>>> Are you sure? kobject_uevent_env() seems sending uevents to all
>>> network namespaces.
>>
>> kobj_bcast_filter() checks that a kobject namespace is equal to a
>> socket namespace.
>
> Today I've checked that it really works as I read from the source code.
> I use this tool to read events:
> https://gist.github.com/avagin/430ba431fc2972002df40ebe6a048b36
>
> And I see that events from non-network devices are delivered to all sockets,
> but events from network devices are delivered only to sockets from
> a network namespace where a device is operated.

I missed it, it makes sense now. Please consider adding a comment in
the code or expanding your changelog for reference.

Thanks!
diff mbox

Patch

diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 6e4f347..c02515e 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -950,10 +950,13 @@  net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num)
 	}
 
 	while (--i >= new_num) {
+		struct kobject *kobj = &dev->_rx[i].kobj;
+
+		if (!list_empty(&dev_net(dev)->exit_list))
+			kobj->uevent_suppress = 1;
 		if (dev->sysfs_rx_queue_group)
-			sysfs_remove_group(&dev->_rx[i].kobj,
-					   dev->sysfs_rx_queue_group);
-		kobject_put(&dev->_rx[i].kobj);
+			sysfs_remove_group(kobj, dev->sysfs_rx_queue_group);
+		kobject_put(kobj);
 	}
 
 	return error;
@@ -1340,6 +1343,8 @@  netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num)
 	while (--i >= new_num) {
 		struct netdev_queue *queue = dev->_tx + i;
 
+		if (!list_empty(&dev_net(dev)->exit_list))
+			queue->kobj.uevent_suppress = 1;
 #ifdef CONFIG_BQL
 		sysfs_remove_group(&queue->kobj, &dql_group);
 #endif
@@ -1525,6 +1530,9 @@  void netdev_unregister_kobject(struct net_device *ndev)
 {
 	struct device *dev = &(ndev->dev);
 
+	if (!list_empty(&dev_net(ndev)->exit_list))
+		dev->kobj.uevent_suppress = 1;
+
 	kobject_get(&dev->kobj);
 
 	remove_queue_kobjects(ndev);