Commit 465edbaa authored by Hideaki Yoshifuji's avatar Hideaki Yoshifuji Committed by David S. Miller

[IPV6]: Unregister per-device snmp6 proc entry earlier.

Do it in addrconf_ifdown.  This fixes OOPSes on shutdown
with 2.6.10
Signed-off-by: default avatarHideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b6f0a1dc
......@@ -149,6 +149,8 @@ extern atomic_t inet6_sock_nr;
int snmp6_register_dev(struct inet6_dev *idev);
int snmp6_unregister_dev(struct inet6_dev *idev);
int snmp6_alloc_dev(struct inet6_dev *idev);
int snmp6_free_dev(struct inet6_dev *idev);
int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign);
void snmp6_mib_free(void *ptr[2]);
......
......@@ -308,7 +308,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
printk("Freeing alive inet6 device %p\n", idev);
return;
}
snmp6_unregister_dev(idev);
snmp6_free_dev(idev);
kfree(idev);
}
......@@ -339,6 +339,16 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
/* We refer to the device */
dev_hold(dev);
if (snmp6_alloc_dev(ndev) < 0) {
ADBG((KERN_WARNING
"%s(): cannot allocate memory for statistics; dev=%s.\n",
__FUNCTION__, dev->name));
neigh_parms_release(&nd_tbl, ndev->nd_parms);
ndev->dead = 1;
in6_dev_finish_destroy(ndev);
return NULL;
}
if (snmp6_register_dev(ndev) < 0) {
ADBG((KERN_WARNING
"%s(): cannot create /proc/net/dev_snmp6/%s\n",
......@@ -2013,6 +2023,10 @@ static int addrconf_ifdown(struct net_device *dev, int how)
dev->ip6_ptr = NULL;
idev->dead = 1;
write_unlock_bh(&addrconf_lock);
/* Step 1.5: remove snmp6 entry */
snmp6_unregister_dev(idev);
}
/* Step 2: clear hash table */
......
......@@ -652,7 +652,9 @@ snmp6_mib_free(void *ptr[2])
{
if (ptr == NULL)
return;
if (ptr[0])
free_percpu(ptr[0]);
if (ptr[1])
free_percpu(ptr[1]);
ptr[0] = ptr[1] = NULL;
}
......
......@@ -201,33 +201,23 @@ static struct file_operations snmp6_seq_fops = {
int snmp6_register_dev(struct inet6_dev *idev)
{
int err = -ENOMEM;
struct proc_dir_entry *p;
if (!idev || !idev->dev)
return -EINVAL;
if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib),
__alignof__(struct icmpv6_mib)) < 0)
goto err_icmp;
if (!proc_net_devsnmp6)
return -ENOENT;
if (!proc_net_devsnmp6) {
err = -ENOENT;
goto err_proc;
}
p = create_proc_entry(idev->dev->name, S_IRUGO, proc_net_devsnmp6);
if (!p)
goto err_proc;
return -ENOMEM;
p->data = idev;
p->proc_fops = &snmp6_seq_fops;
idev->stats.proc_dir_entry = p;
return 0;
err_proc:
snmp6_mib_free((void **)idev->stats.icmpv6);
err_icmp:
return err;
}
int snmp6_unregister_dev(struct inet6_dev *idev)
......@@ -238,8 +228,6 @@ int snmp6_unregister_dev(struct inet6_dev *idev)
return -EINVAL;
remove_proc_entry(idev->stats.proc_dir_entry->name,
proc_net_devsnmp6);
snmp6_mib_free((void **)idev->stats.icmpv6);
return 0;
}
......@@ -279,6 +267,17 @@ void ipv6_misc_proc_exit(void)
int snmp6_register_dev(struct inet6_dev *idev)
{
return 0;
}
int snmp6_unregister_dev(struct inet6_dev *idev)
{
return 0;
}
#endif /* CONFIG_PROC_FS */
int snmp6_alloc_dev(struct inet6_dev *idev)
{
int err = -ENOMEM;
......@@ -295,11 +294,10 @@ int snmp6_register_dev(struct inet6_dev *idev)
return err;
}
int snmp6_unregister_dev(struct inet6_dev *idev)
int snmp6_free_dev(struct inet6_dev *idev)
{
snmp6_mib_free((void **)idev->stats.icmpv6);
return 0;
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment