diff mbox series

[net-next,05/16] bonding: use exit_batch_rtnl() method

Message ID 20240201170937.3549878-6-edumazet@google.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series net: more factorization in cleanup_net() paths | expand

Checks

Context Check Description
netdev/series_format fail Series longer than 15 patches (and no cover letter)
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1048 this patch: 1048
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 0 of 0 maintainers
netdev/build_clang success Errors and warnings before: 1065 this patch: 1065
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1065 this patch: 1065
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 44 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Eric Dumazet Feb. 1, 2024, 5:09 p.m. UTC
exit_batch_rtnl() is called while RTNL is held,
and devices to be unregistered can be queued in the dev_kill_list.

This saves one rtnl_lock()/rtnl_unlock() pair,
and one unregister_netdevice_many() call.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 drivers/net/bonding/bond_main.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

Comments

Antoine Tenart Feb. 2, 2024, 2:29 p.m. UTC | #1
Hello,

Quoting Eric Dumazet (2024-02-01 18:09:26)
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 4e0600c7b050f21c82a8862e224bb055e95d5039..181da7ea389312d7c851ca51c35b871c07144b6b 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -6419,34 +6419,34 @@ static void __net_exit bond_net_exit_batch(struct list_head *net_list)
>  {
>         struct bond_net *bn;
>         struct net *net;
> -       LIST_HEAD(list);
>  
>         list_for_each_entry(net, net_list, exit_list) {
>                 bn = net_generic(net, bond_net_id);
>                 bond_destroy_sysfs(bn);
> +               bond_destroy_proc_dir(bn);
>         }
> +}
> +
> +static void __net_exit bond_net_exit_batch_rtnl(struct list_head *net_list,
> +                                               struct list_head *dev_kill_list)
> +{
> +       struct bond_net *bn;
> +       struct net *net;
>  
>         /* Kill off any bonds created after unregistering bond rtnl ops */
> -       rtnl_lock();
>         list_for_each_entry(net, net_list, exit_list) {
>                 struct bonding *bond, *tmp_bond;
>  
>                 bn = net_generic(net, bond_net_id);
>                 list_for_each_entry_safe(bond, tmp_bond, &bn->dev_list, bond_list)
> -                       unregister_netdevice_queue(bond->dev, &list);
> -       }
> -       unregister_netdevice_many(&list);
> -       rtnl_unlock();
> -
> -       list_for_each_entry(net, net_list, exit_list) {
> -               bn = net_generic(net, bond_net_id);
> -               bond_destroy_proc_dir(bn);
> +                       unregister_netdevice_queue(bond->dev, dev_kill_list);
>         }
>  }

This changes the logic of how bond net & devices are destroyed. Before
this patch the logic was:

1. bond_destroy_sysfs; called first so no new bond devices can be
   registered later.
2. unregister_netdevice; cleans up any new bond device added before 1.

This now is:
1. unregister_netdevice
// Here new bond devices can still be registered.
2. bond_destroy_sysfs

Looking briefly at the history, the above is done on purpose to avoid
issues when unloading the bonding module. See 23fa5c2caae0 and
especially 69b0216ac255.

Thanks,
Antoine
Eric Dumazet Feb. 2, 2024, 2:51 p.m. UTC | #2
On Fri, Feb 2, 2024 at 3:29 PM Antoine Tenart <atenart@kernel.org> wrote:
>
> Hello,
>
> Quoting Eric Dumazet (2024-02-01 18:09:26)
> > diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> > index 4e0600c7b050f21c82a8862e224bb055e95d5039..181da7ea389312d7c851ca51c35b871c07144b6b 100644
> > --- a/drivers/net/bonding/bond_main.c
> > +++ b/drivers/net/bonding/bond_main.c
> > @@ -6419,34 +6419,34 @@ static void __net_exit bond_net_exit_batch(struct list_head *net_list)
> >  {
> >         struct bond_net *bn;
> >         struct net *net;
> > -       LIST_HEAD(list);
> >
> >         list_for_each_entry(net, net_list, exit_list) {
> >                 bn = net_generic(net, bond_net_id);
> >                 bond_destroy_sysfs(bn);
> > +               bond_destroy_proc_dir(bn);
> >         }
> > +}
> > +
> > +static void __net_exit bond_net_exit_batch_rtnl(struct list_head *net_list,
> > +                                               struct list_head *dev_kill_list)
> > +{
> > +       struct bond_net *bn;
> > +       struct net *net;
> >
> >         /* Kill off any bonds created after unregistering bond rtnl ops */
> > -       rtnl_lock();
> >         list_for_each_entry(net, net_list, exit_list) {
> >                 struct bonding *bond, *tmp_bond;
> >
> >                 bn = net_generic(net, bond_net_id);
> >                 list_for_each_entry_safe(bond, tmp_bond, &bn->dev_list, bond_list)
> > -                       unregister_netdevice_queue(bond->dev, &list);
> > -       }
> > -       unregister_netdevice_many(&list);
> > -       rtnl_unlock();
> > -
> > -       list_for_each_entry(net, net_list, exit_list) {
> > -               bn = net_generic(net, bond_net_id);
> > -               bond_destroy_proc_dir(bn);
> > +                       unregister_netdevice_queue(bond->dev, dev_kill_list);
> >         }
> >  }
>
> This changes the logic of how bond net & devices are destroyed. Before
> this patch the logic was:
>
> 1. bond_destroy_sysfs; called first so no new bond devices can be
>    registered later.
> 2. unregister_netdevice; cleans up any new bond device added before 1.
>
> This now is:
> 1. unregister_netdevice
> // Here new bond devices can still be registered.
> 2. bond_destroy_sysfs
>
> Looking briefly at the history, the above is done on purpose to avoid
> issues when unloading the bonding module. See 23fa5c2caae0 and
> especially 69b0216ac255.

Nice catch, thanks.

Hmmm, it seems we should perform the  bond_destroy_sysfs(bn) call earlier then,
from the pre_exit() method...

Order of calls is :
1) pre_exit()
2) exit_batch_rtnl()
3) exit(), exit_batch()

Something like the following (that I would squash on the current patch)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 181da7ea389312d7c851ca51c35b871c07144b6b..7edd3daa7e6d977e6b0220226b3cd4f8f67a7952
100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -6415,6 +6415,13 @@ static int __net_init bond_net_init(struct net *net)
        return 0;
 }

+static void __net_exit bond_net_pre_exit(struct net *net)
+{
+       struct bond_net *bn = net_generic(net, bond_net_id);
+
+       bond_destroy_sysfs(bn);
+}
+
 static void __net_exit bond_net_exit_batch(struct list_head *net_list)
 {
        struct bond_net *bn;
@@ -6422,7 +6429,6 @@ static void __net_exit
bond_net_exit_batch(struct list_head *net_list)

        list_for_each_entry(net, net_list, exit_list) {
                bn = net_generic(net, bond_net_id);
-               bond_destroy_sysfs(bn);
                bond_destroy_proc_dir(bn);
        }
 }
@@ -6445,8 +6451,9 @@ static void __net_exit
bond_net_exit_batch_rtnl(struct list_head *net_list,

 static struct pernet_operations bond_net_ops = {
        .init = bond_net_init,
-       .exit_batch = bond_net_exit_batch,
+       .pre_exit = bond_net_pre_exit,
        .exit_batch_rtnl = bond_net_exit_batch_rtnl,
+       .exit_batch = bond_net_exit_batch,
        .id   = &bond_net_id,
        .size = sizeof(struct bond_net),
 };
Antoine Tenart Feb. 2, 2024, 3:05 p.m. UTC | #3
Quoting Eric Dumazet (2024-02-02 15:51:43)
> On Fri, Feb 2, 2024 at 3:29 PM Antoine Tenart <atenart@kernel.org> wrote:
> > Quoting Eric Dumazet (2024-02-01 18:09:26)
> >
> > This changes the logic of how bond net & devices are destroyed. Before
> > this patch the logic was:
> >
> > 1. bond_destroy_sysfs; called first so no new bond devices can be
> >    registered later.
> > 2. unregister_netdevice; cleans up any new bond device added before 1.
> >
> > This now is:
> > 1. unregister_netdevice
> > // Here new bond devices can still be registered.
> > 2. bond_destroy_sysfs
> >
> > Looking briefly at the history, the above is done on purpose to avoid
> > issues when unloading the bonding module. See 23fa5c2caae0 and
> > especially 69b0216ac255.
> 
> Nice catch, thanks.
> 
> Hmmm, it seems we should perform the  bond_destroy_sysfs(bn) call earlier then,
> from the pre_exit() method...
> 
> Order of calls is :
> 1) pre_exit()
> 2) exit_batch_rtnl()
> 3) exit(), exit_batch()
> 
> Something like the following (that I would squash on the current patch)

Looks good, thanks!

> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 181da7ea389312d7c851ca51c35b871c07144b6b..7edd3daa7e6d977e6b0220226b3cd4f8f67a7952
> 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -6415,6 +6415,13 @@ static int __net_init bond_net_init(struct net *net)
>         return 0;
>  }
> 
> +static void __net_exit bond_net_pre_exit(struct net *net)
> +{
> +       struct bond_net *bn = net_generic(net, bond_net_id);
> +
> +       bond_destroy_sysfs(bn);
> +}
> +
>  static void __net_exit bond_net_exit_batch(struct list_head *net_list)
>  {
>         struct bond_net *bn;
> @@ -6422,7 +6429,6 @@ static void __net_exit
> bond_net_exit_batch(struct list_head *net_list)
> 
>         list_for_each_entry(net, net_list, exit_list) {
>                 bn = net_generic(net, bond_net_id);
> -               bond_destroy_sysfs(bn);
>                 bond_destroy_proc_dir(bn);
>         }
>  }
> @@ -6445,8 +6451,9 @@ static void __net_exit
> bond_net_exit_batch_rtnl(struct list_head *net_list,
> 
>  static struct pernet_operations bond_net_ops = {
>         .init = bond_net_init,
> -       .exit_batch = bond_net_exit_batch,
> +       .pre_exit = bond_net_pre_exit,
>         .exit_batch_rtnl = bond_net_exit_batch_rtnl,
> +       .exit_batch = bond_net_exit_batch,
>         .id   = &bond_net_id,
>         .size = sizeof(struct bond_net),
>  };
>
diff mbox series

Patch

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 4e0600c7b050f21c82a8862e224bb055e95d5039..181da7ea389312d7c851ca51c35b871c07144b6b 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -6419,34 +6419,34 @@  static void __net_exit bond_net_exit_batch(struct list_head *net_list)
 {
 	struct bond_net *bn;
 	struct net *net;
-	LIST_HEAD(list);
 
 	list_for_each_entry(net, net_list, exit_list) {
 		bn = net_generic(net, bond_net_id);
 		bond_destroy_sysfs(bn);
+		bond_destroy_proc_dir(bn);
 	}
+}
+
+static void __net_exit bond_net_exit_batch_rtnl(struct list_head *net_list,
+						struct list_head *dev_kill_list)
+{
+	struct bond_net *bn;
+	struct net *net;
 
 	/* Kill off any bonds created after unregistering bond rtnl ops */
-	rtnl_lock();
 	list_for_each_entry(net, net_list, exit_list) {
 		struct bonding *bond, *tmp_bond;
 
 		bn = net_generic(net, bond_net_id);
 		list_for_each_entry_safe(bond, tmp_bond, &bn->dev_list, bond_list)
-			unregister_netdevice_queue(bond->dev, &list);
-	}
-	unregister_netdevice_many(&list);
-	rtnl_unlock();
-
-	list_for_each_entry(net, net_list, exit_list) {
-		bn = net_generic(net, bond_net_id);
-		bond_destroy_proc_dir(bn);
+			unregister_netdevice_queue(bond->dev, dev_kill_list);
 	}
 }
 
 static struct pernet_operations bond_net_ops = {
 	.init = bond_net_init,
 	.exit_batch = bond_net_exit_batch,
+	.exit_batch_rtnl = bond_net_exit_batch_rtnl,
 	.id   = &bond_net_id,
 	.size = sizeof(struct bond_net),
 };