Skip to content

Commit 748e2d9

Browse files
edumazetdavem330
authored andcommitted
net: reinstate rtnl in call_netdevice_notifiers()
Eric Biederman pointed out that not holding RTNL while calling call_netdevice_notifiers() was racy. This patch is a direct transcription his feedback against commit 0115e8e (net: remove delay at device dismantle) Thanks Eric ! Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Tom Herbert <therbert@google.com> Cc: Mahesh Bandewar <maheshb@google.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Gao feng <gaofeng@cn.fujitsu.com> Acked-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 0fa7fa9 commit 748e2d9

File tree

5 files changed

+12
-19
lines changed

5 files changed

+12
-19
lines changed

net/core/dev.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,8 +1466,7 @@ EXPORT_SYMBOL(unregister_netdevice_notifier);
14661466

14671467
int call_netdevice_notifiers(unsigned long val, struct net_device *dev)
14681468
{
1469-
if (val != NETDEV_UNREGISTER_FINAL)
1470-
ASSERT_RTNL();
1469+
ASSERT_RTNL();
14711470
return raw_notifier_call_chain(&netdev_chain, val, dev);
14721471
}
14731472
EXPORT_SYMBOL(call_netdevice_notifiers);
@@ -5782,7 +5781,11 @@ static void netdev_wait_allrefs(struct net_device *dev)
57825781

57835782
/* Rebroadcast unregister notification */
57845783
call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
5784+
5785+
__rtnl_unlock();
57855786
rcu_barrier();
5787+
rtnl_lock();
5788+
57865789
call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev);
57875790
if (test_bit(__LINK_STATE_LINKWATCH_PENDING,
57885791
&dev->state)) {
@@ -5855,7 +5858,9 @@ void netdev_run_todo(void)
58555858
= list_first_entry(&list, struct net_device, todo_list);
58565859
list_del(&dev->todo_list);
58575860

5861+
rtnl_lock();
58585862
call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev);
5863+
__rtnl_unlock();
58595864

58605865
if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) {
58615866
pr_err("network todo '%s' but state %d\n",

net/core/fib_rules.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -711,16 +711,15 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,
711711
struct net *net = dev_net(dev);
712712
struct fib_rules_ops *ops;
713713

714+
ASSERT_RTNL();
714715

715716
switch (event) {
716717
case NETDEV_REGISTER:
717-
ASSERT_RTNL();
718718
list_for_each_entry(ops, &net->rules_ops, list)
719719
attach_rules(&ops->rules_list, dev);
720720
break;
721721

722722
case NETDEV_UNREGISTER:
723-
ASSERT_RTNL();
724723
list_for_each_entry(ops, &net->rules_ops, list)
725724
detach_rules(&ops->rules_list, dev);
726725
break;

net/ipv4/devinet.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,12 +1147,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
11471147
void *ptr)
11481148
{
11491149
struct net_device *dev = ptr;
1150-
struct in_device *in_dev;
1151-
1152-
if (event == NETDEV_UNREGISTER_FINAL)
1153-
goto out;
1150+
struct in_device *in_dev = __in_dev_get_rtnl(dev);
11541151

1155-
in_dev = __in_dev_get_rtnl(dev);
11561152
ASSERT_RTNL();
11571153

11581154
if (!in_dev) {

net/ipv4/fib_frontend.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,9 +1050,6 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
10501050
return NOTIFY_DONE;
10511051
}
10521052

1053-
if (event == NETDEV_UNREGISTER_FINAL)
1054-
return NOTIFY_DONE;
1055-
10561053
in_dev = __in_dev_get_rtnl(dev);
10571054

10581055
switch (event) {
@@ -1064,14 +1061,14 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
10641061
fib_sync_up(dev);
10651062
#endif
10661063
atomic_inc(&net->ipv4.dev_addr_genid);
1067-
rt_cache_flush(dev_net(dev), -1);
1064+
rt_cache_flush(net, -1);
10681065
break;
10691066
case NETDEV_DOWN:
10701067
fib_disable_ip(dev, 0, 0);
10711068
break;
10721069
case NETDEV_CHANGEMTU:
10731070
case NETDEV_CHANGE:
1074-
rt_cache_flush(dev_net(dev), 0);
1071+
rt_cache_flush(net, 0);
10751072
break;
10761073
}
10771074
return NOTIFY_DONE;

net/ipv6/addrconf.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2566,14 +2566,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
25662566
void *data)
25672567
{
25682568
struct net_device *dev = (struct net_device *) data;
2569-
struct inet6_dev *idev;
2569+
struct inet6_dev *idev = __in6_dev_get(dev);
25702570
int run_pending = 0;
25712571
int err;
25722572

2573-
if (event == NETDEV_UNREGISTER_FINAL)
2574-
return NOTIFY_DONE;
2575-
2576-
idev = __in6_dev_get(dev);
25772573
switch (event) {
25782574
case NETDEV_REGISTER:
25792575
if (!idev && dev->mtu >= IPV6_MIN_MTU) {

0 commit comments

Comments
 (0)