static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE];
static DEFINE_RWLOCK(addrconf_hash_lock);
-/* Protects inet6 devices */
-DEFINE_RWLOCK(addrconf_lock);
-
static void addrconf_verify(unsigned long);
static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0);
/* Nobody refers to this device, we may destroy it. */
+static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
+{
+ struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
+ kfree(idev);
+}
+
void in6_dev_finish_destroy(struct inet6_dev *idev)
{
struct net_device *dev = idev->dev;
return;
}
snmp6_free_dev(idev);
- kfree(idev);
+ call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
}
static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
if (netif_carrier_ok(dev))
ndev->if_flags |= IF_READY;
- write_lock_bh(&addrconf_lock);
- dev->ip6_ptr = ndev;
- write_unlock_bh(&addrconf_lock);
+ /* protected by rtnl_lock */
+ rcu_assign_pointer(dev->ip6_ptr, ndev);
ipv6_mc_init_dev(ndev);
ndev->tstamp = jiffies;
read_lock(&dev_base_lock);
for (dev=dev_base; dev; dev=dev->next) {
- read_lock(&addrconf_lock);
+ rcu_read_lock();
idev = __in6_dev_get(dev);
if (idev) {
int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding);
if (changed)
dev_forward_change(idev);
}
- read_unlock(&addrconf_lock);
+ rcu_read_unlock();
}
read_unlock(&dev_base_lock);
}
int hash;
int err = 0;
- read_lock_bh(&addrconf_lock);
+ rcu_read_lock_bh();
if (idev->dead) {
err = -ENODEV; /*XXX*/
goto out2;
in6_ifa_hold(ifa);
write_unlock(&idev->lock);
out2:
- read_unlock_bh(&addrconf_lock);
+ rcu_read_unlock_bh();
if (likely(err == 0))
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
memset(&hiscore, 0, sizeof(hiscore));
read_lock(&dev_base_lock);
- read_lock(&addrconf_lock);
+ rcu_read_lock();
for (dev = dev_base; dev; dev=dev->next) {
struct inet6_dev *idev;
}
read_unlock_bh(&idev->lock);
}
- read_unlock(&addrconf_lock);
+ rcu_read_unlock();
read_unlock(&dev_base_lock);
if (!ifa_result)
struct inet6_dev *idev;
int err = -EADDRNOTAVAIL;
- read_lock(&addrconf_lock);
+ rcu_read_lock();
if ((idev = __in6_dev_get(dev)) != NULL) {
struct inet6_ifaddr *ifp;
}
read_unlock_bh(&idev->lock);
}
- read_unlock(&addrconf_lock);
+ rcu_read_unlock();
return err;
}
struct inet6_dev *idev = (struct inet6_dev *) data;
unsigned long expires;
- read_lock_bh(&addrconf_lock);
+ rcu_read_lock_bh();
write_lock_bh(&idev->lock);
if (idev->dead)
out:
write_unlock_bh(&idev->lock);
- read_unlock_bh(&addrconf_lock);
+ rcu_read_unlock_bh();
in6_dev_put(idev);
}
Do not dev_put!
*/
if (how == 1) {
- write_lock_bh(&addrconf_lock);
- dev->ip6_ptr = NULL;
idev->dead = 1;
- write_unlock_bh(&addrconf_lock);
+
+ /* protected by rtnl_lock */
+ rcu_assign_pointer(dev->ip6_ptr, NULL);
/* Step 1.5: remove snmp6 entry */
snmp6_unregister_dev(idev);
static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{
- read_lock_bh(&addrconf_lock);
+ rcu_read_lock_bh();
if (likely(ifp->idev->dead == 0))
__ipv6_ifa_notify(event, ifp);
- read_unlock_bh(&addrconf_lock);
+ rcu_read_unlock_bh();
}
#ifdef CONFIG_SYSCTL