Message ID | 20220218065430.2613262-1-eric.dumazet@gmail.com (mailing list archive) |
---|---|
State | Accepted |
Commit | 86213f80da1b1d007721cc22e04b5f5d0da33127 |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [net-next] net: avoid quadratic behavior in netdev_wait_allrefs_any() | expand |
On Thu, 17 Feb 2022 22:54:30 -0800 Eric Dumazet wrote: > From: Eric Dumazet <edumazet@google.com> > > If the list of devices has N elements, netdev_wait_allrefs_any() > is called N times, and linkwatch_forget_dev() is called N*(N-1)/2 times. > > Fix this by calling linkwatch_forget_dev() only once per device. > > Fixes: faab39f63c1f ("net: allow out-of-order netdev unregistration") > Signed-off-by: Eric Dumazet <edumazet@google.com> Yup, I was on the fence on this one, I went for keeping all linkwatch stuff in one function and minimal changes. Clearly underestimated the number of netdevs your cases are destroying at once :)
Hello: This patch was applied to netdev/net-next.git (master) by Jakub Kicinski <kuba@kernel.org>: On Thu, 17 Feb 2022 22:54:30 -0800 you wrote: > From: Eric Dumazet <edumazet@google.com> > > If the list of devices has N elements, netdev_wait_allrefs_any() > is called N times, and linkwatch_forget_dev() is called N*(N-1)/2 times. > > Fix this by calling linkwatch_forget_dev() only once per device. > > [...] Here is the summary with links: - [net-next] net: avoid quadratic behavior in netdev_wait_allrefs_any() https://git.kernel.org/netdev/net-next/c/86213f80da1b You are awesome, thank you!
diff --git a/net/core/dev.c b/net/core/dev.c index 05fa867f18787e709dcaccfea1df350c424eff80..acd884910e12a040841e1e0525e0d4bc5e3ee799 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -9828,9 +9828,6 @@ static struct net_device *netdev_wait_allrefs_any(struct list_head *list) struct net_device *dev; int wait = 0; - list_for_each_entry(dev, list, todo_list) - linkwatch_forget_dev(dev); - rebroadcast_time = warning_time = jiffies; list_for_each_entry(dev, list, todo_list) @@ -9951,6 +9948,7 @@ void netdev_run_todo(void) } dev->reg_state = NETREG_UNREGISTERED; + linkwatch_forget_dev(dev); } while (!list_empty(&list)) {