Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipmr: Remove RTNL in ipmr_rules_init() and ipmr_net_init().

When ipmr_free_table() is called from ipmr_rules_init() or
ipmr_net_init(), the netns is not yet published.

Thus, no device should have been registered, and
mroute_clean_tables() will not call vif_delete(), so
unregister_netdevice_many() is unnecessary.

unregister_netdevice_many() does nothing if the list is empty,
but it requires RTNL due to the unconditional ASSERT_RTNL()
at the entry of unregister_netdevice_many_notify().

Let's remove unnecessary RTNL and ASSERT_RTNL() and instead
add WARN_ON_ONCE() in ipmr_free_table().

Note that we use a local list for the new WARN_ON_ONCE() because
dev_kill_list passed from ipmr_rules_exit_rtnl() may have some
devices when other ops->init() fails after ipmr durnig setup_net().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260228221800.1082070-11-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Kuniyuki Iwashima and committed by
Jakub Kicinski
4a11adcd b22b0186

+5 -10
+5 -10
net/ipv4/ipmr.c
··· 276 276 return 0; 277 277 278 278 err2: 279 - rtnl_lock(); 280 279 ipmr_free_table(mrt, &dev_kill_list); 281 - unregister_netdevice_many(&dev_kill_list); 282 - rtnl_unlock(); 283 280 err1: 284 281 fib_rules_unregister(ops); 285 282 return err; ··· 287 290 { 288 291 struct mr_table *mrt, *next; 289 292 290 - ASSERT_RTNL(); 291 293 list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) { 292 294 list_del(&mrt->list); 293 295 ipmr_free_table(mrt, dev_kill_list); ··· 351 355 static void __net_exit ipmr_rules_exit_rtnl(struct net *net, 352 356 struct list_head *dev_kill_list) 353 357 { 354 - ASSERT_RTNL(); 355 - 356 358 ipmr_free_table(net->ipv4.mrt, dev_kill_list); 357 359 358 360 net->ipv4.mrt = NULL; ··· 430 436 static void ipmr_free_table(struct mr_table *mrt, struct list_head *dev_kill_list) 431 437 { 432 438 struct net *net = read_pnet(&mrt->net); 439 + LIST_HEAD(ipmr_dev_kill_list); 433 440 434 441 WARN_ON_ONCE(!mr_can_free_table(net)); 435 442 436 443 timer_shutdown_sync(&mrt->ipmr_expire_timer); 437 444 mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC | 438 445 MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC, 439 - dev_kill_list); 446 + &ipmr_dev_kill_list); 440 447 rhltable_destroy(&mrt->mfc_hash); 441 448 kfree(mrt); 449 + 450 + WARN_ON_ONCE(!net_initialized(net) && !list_empty(&ipmr_dev_kill_list)); 451 + list_splice(&ipmr_dev_kill_list, dev_kill_list); 442 452 } 443 453 444 454 /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ ··· 3285 3287 proc_cache_fail: 3286 3288 remove_proc_entry("ip_mr_vif", net->proc_net); 3287 3289 proc_vif_fail: 3288 - rtnl_lock(); 3289 3290 ipmr_rules_exit_rtnl(net, &dev_kill_list); 3290 - unregister_netdevice_many(&dev_kill_list); 3291 - rtnl_unlock(); 3292 3291 #endif 3293 3292 ipmr_rules_fail: 3294 3293 ipmr_notifier_exit(net);