ipv6: add a missing unregister_pernet_subsys call

Clean up a missing exit path in the ipv6 module init routines. In
addrconf_init we call ipv6_addr_label_init which calls register_pernet_subsys
for the ipv6_addr_label_ops structure. But if module loading fails, or if the
ipv6 module is removed, there is no corresponding unregister_pernet_subsys call,
which leaves a now-bogus address on the pernet_list, leading to oopses in
subsequent registrations. This patch cleans up both the failed load path and
the unload path. Tested by myself with good results.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>

include/net/addrconf.h | 1 +
net/ipv6/addrconf.c | 11 ++++++++---
net/ipv6/addrlabel.c | 5 +++++
3 files changed, 14 insertions(+), 3 deletions(-)
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Neil Horman and committed by David S. Miller 2cc6d2bf bc68580d

+14 -3
+1
include/net/addrconf.h
··· 121 * IPv6 Address Label subsystem (addrlabel.c) 122 */ 123 extern int ipv6_addr_label_init(void); 124 extern void ipv6_addr_label_rtnl_register(void); 125 extern u32 ipv6_addr_label(struct net *net, 126 const struct in6_addr *addr,
··· 121 * IPv6 Address Label subsystem (addrlabel.c) 122 */ 123 extern int ipv6_addr_label_init(void); 124 + extern void ipv6_addr_label_cleanup(void); 125 extern void ipv6_addr_label_rtnl_register(void); 126 extern u32 ipv6_addr_label(struct net *net, 127 const struct in6_addr *addr,
+8 -3
net/ipv6/addrconf.c
··· 4637 if (err < 0) { 4638 printk(KERN_CRIT "IPv6 Addrconf:" 4639 " cannot initialize default policy table: %d.\n", err); 4640 - return err; 4641 } 4642 4643 - register_pernet_subsys(&addrconf_ops); 4644 4645 /* The addrconf netdev notifier requires that loopback_dev 4646 * has it's ipv6 private information allocated and setup ··· 4694 unregister_netdevice_notifier(&ipv6_dev_notf); 4695 errlo: 4696 unregister_pernet_subsys(&addrconf_ops); 4697 - 4698 return err; 4699 } 4700 ··· 4707 4708 unregister_netdevice_notifier(&ipv6_dev_notf); 4709 unregister_pernet_subsys(&addrconf_ops); 4710 4711 rtnl_lock(); 4712
··· 4637 if (err < 0) { 4638 printk(KERN_CRIT "IPv6 Addrconf:" 4639 " cannot initialize default policy table: %d.\n", err); 4640 + goto out; 4641 } 4642 4643 + err = register_pernet_subsys(&addrconf_ops); 4644 + if (err < 0) 4645 + goto out_addrlabel; 4646 4647 /* The addrconf netdev notifier requires that loopback_dev 4648 * has it's ipv6 private information allocated and setup ··· 4692 unregister_netdevice_notifier(&ipv6_dev_notf); 4693 errlo: 4694 unregister_pernet_subsys(&addrconf_ops); 4695 + out_addrlabel: 4696 + ipv6_addr_label_cleanup(); 4697 + out: 4698 return err; 4699 } 4700 ··· 4703 4704 unregister_netdevice_notifier(&ipv6_dev_notf); 4705 unregister_pernet_subsys(&addrconf_ops); 4706 + ipv6_addr_label_cleanup(); 4707 4708 rtnl_lock(); 4709
+5
net/ipv6/addrlabel.c
··· 393 return register_pernet_subsys(&ipv6_addr_label_ops); 394 } 395 396 static const struct nla_policy ifal_policy[IFAL_MAX+1] = { 397 [IFAL_ADDRESS] = { .len = sizeof(struct in6_addr), }, 398 [IFAL_LABEL] = { .len = sizeof(u32), },
··· 393 return register_pernet_subsys(&ipv6_addr_label_ops); 394 } 395 396 + void ipv6_addr_label_cleanup(void) 397 + { 398 + unregister_pernet_subsys(&ipv6_addr_label_ops); 399 + } 400 + 401 static const struct nla_policy ifal_policy[IFAL_MAX+1] = { 402 [IFAL_ADDRESS] = { .len = sizeof(struct in6_addr), }, 403 [IFAL_LABEL] = { .len = sizeof(u32), },