diff options
author | Daniel Lezcano <dlezcano@fr.ibm.com> | 2009-03-03 04:06:45 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-03 04:06:45 -0500 |
commit | 176c39af29bc4edaf37f663553eeaacd47b5bc9c (patch) | |
tree | 03395c5761d2ed623f5705493eaa5deef416959d /net/ipv6/addrconf.c | |
parent | b325fddb7f869e6c95a88dc6573220f162e5b89f (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/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 39 |
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 | ||
4449 | EXPORT_SYMBOL(unregister_inet6addr_notifier); | 4446 | EXPORT_SYMBOL(unregister_inet6addr_notifier); |
4450 | 4447 | ||
4451 | static 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 | |||
4466 | static 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: | |||
4541 | void addrconf_cleanup(void) | 4515 | void 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 | } |