aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDaniel Lezcano <dlezcano@fr.ibm.com>2009-03-03 04:06:45 -0500
committerDavid S. Miller <davem@davemloft.net>2009-03-03 04:06:45 -0500
commit176c39af29bc4edaf37f663553eeaacd47b5bc9c (patch)
tree03395c5761d2ed623f5705493eaa5deef416959d /net
parentb325fddb7f869e6c95a88dc6573220f162e5b89f (diff)
netns: fix addrconf_ifdown kernel panic
When a network namespace is destroyed the network interfaces are all unregistered, making addrconf_ifdown called by the netdevice notifier. In the other hand, the addrconf exit method does a loop on the network devices and does addrconf_ifdown on each of them. But the ordering of the netns subsystem is not right because it uses the register_pernet_device instead of register_pernet_subsys. If we handle the loopback as any network device, we can safely use register_pernet_subsys. But if we use register_pernet_subsys, the addrconf exit method will do exactly what was already done with the unregistering of the network devices. So in definitive, this code is pointless. I removed the netns addrconf exit method and moved the code to the addrconf cleanup function. Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/addrconf.c39
1 files changed, 9 insertions, 30 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 40fabdee42ae..1220e2c7831e 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2611,9 +2611,6 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2611 2611
2612 ASSERT_RTNL(); 2612 ASSERT_RTNL();
2613 2613
2614 if ((dev->flags & IFF_LOOPBACK) && how == 1)
2615 how = 0;
2616
2617 rt6_ifdown(net, dev); 2614 rt6_ifdown(net, dev);
2618 neigh_ifdown(&nd_tbl, dev); 2615 neigh_ifdown(&nd_tbl, dev);
2619 2616
@@ -4448,25 +4445,6 @@ int unregister_inet6addr_notifier(struct notifier_block *nb)
4448 4445
4449EXPORT_SYMBOL(unregister_inet6addr_notifier); 4446EXPORT_SYMBOL(unregister_inet6addr_notifier);
4450 4447
4451static void addrconf_net_exit(struct net *net)
4452{
4453 struct net_device *dev;
4454
4455 rtnl_lock();
4456 /* clean dev list */
4457 for_each_netdev(net, dev) {
4458 if (__in6_dev_get(dev) == NULL)
4459 continue;
4460 addrconf_ifdown(dev, 1);
4461 }
4462 addrconf_ifdown(net->loopback_dev, 2);
4463 rtnl_unlock();
4464}
4465
4466static struct pernet_operations addrconf_net_ops = {
4467 .exit = addrconf_net_exit,
4468};
4469
4470/* 4448/*
4471 * Init / cleanup code 4449 * Init / cleanup code
4472 */ 4450 */
@@ -4508,10 +4486,6 @@ int __init addrconf_init(void)
4508 if (err) 4486 if (err)
4509 goto errlo; 4487 goto errlo;
4510 4488
4511 err = register_pernet_device(&addrconf_net_ops);
4512 if (err)
4513 return err;
4514
4515 register_netdevice_notifier(&ipv6_dev_notf); 4489 register_netdevice_notifier(&ipv6_dev_notf);
4516 4490
4517 addrconf_verify(0); 4491 addrconf_verify(0);
@@ -4541,15 +4515,22 @@ errlo:
4541void addrconf_cleanup(void) 4515void addrconf_cleanup(void)
4542{ 4516{
4543 struct inet6_ifaddr *ifa; 4517 struct inet6_ifaddr *ifa;
4518 struct net_device *dev;
4544 int i; 4519 int i;
4545 4520
4546 unregister_netdevice_notifier(&ipv6_dev_notf); 4521 unregister_netdevice_notifier(&ipv6_dev_notf);
4547 unregister_pernet_device(&addrconf_net_ops);
4548
4549 unregister_pernet_subsys(&addrconf_ops); 4522 unregister_pernet_subsys(&addrconf_ops);
4550 4523
4551 rtnl_lock(); 4524 rtnl_lock();
4552 4525
4526 /* clean dev list */
4527 for_each_netdev(&init_net, dev) {
4528 if (__in6_dev_get(dev) == NULL)
4529 continue;
4530 addrconf_ifdown(dev, 1);
4531 }
4532 addrconf_ifdown(init_net.loopback_dev, 2);
4533
4553 /* 4534 /*
4554 * Check hash table. 4535 * Check hash table.
4555 */ 4536 */
@@ -4570,6 +4551,4 @@ void addrconf_cleanup(void)
4570 4551
4571 del_timer(&addr_chk_timer); 4552 del_timer(&addr_chk_timer);
4572 rtnl_unlock(); 4553 rtnl_unlock();
4573
4574 unregister_pernet_subsys(&addrconf_net_ops);
4575} 4554}