Commit 80f968c0 authored by Hideaki Yoshifuji's avatar Hideaki Yoshifuji

[IPV6] Clean-up locking in ipv6_add_addr().

Use addrconf_hash_lock instead of private lock.
Signed-off-by: default avatarHideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
parent 4709b4fd
...@@ -487,10 +487,15 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, ...@@ -487,10 +487,15 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
struct inet6_ifaddr *ifa = NULL; struct inet6_ifaddr *ifa = NULL;
struct rt6_info *rt; struct rt6_info *rt;
int hash; int hash;
static spinlock_t lock = SPIN_LOCK_UNLOCKED;
int err = 0; int err = 0;
spin_lock_bh(&lock); read_lock_bh(&addrconf_lock);
if (idev->dead) {
err = -ENODEV; /*XXX*/
goto out2;
}
write_lock(&addrconf_hash_lock);
/* Ignore adding duplicate addresses on an interface */ /* Ignore adding duplicate addresses on an interface */
if (ipv6_chk_same_addr(addr, idev->dev)) { if (ipv6_chk_same_addr(addr, idev->dev)) {
...@@ -524,13 +529,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, ...@@ -524,13 +529,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
ifa->flags = flags | IFA_F_TENTATIVE; ifa->flags = flags | IFA_F_TENTATIVE;
ifa->cstamp = ifa->tstamp = jiffies; ifa->cstamp = ifa->tstamp = jiffies;
read_lock(&addrconf_lock);
if (idev->dead) {
read_unlock(&addrconf_lock);
err = -ENODEV; /*XXX*/
goto out;
}
inet6_ifa_count++; inet6_ifa_count++;
ifa->idev = idev; ifa->idev = idev;
in6_dev_hold(idev); in6_dev_hold(idev);
...@@ -540,35 +538,30 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, ...@@ -540,35 +538,30 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
/* Add to big hash table */ /* Add to big hash table */
hash = ipv6_addr_hash(addr); hash = ipv6_addr_hash(addr);
write_lock_bh(&addrconf_hash_lock);
ifa->lst_next = inet6_addr_lst[hash]; ifa->lst_next = inet6_addr_lst[hash];
inet6_addr_lst[hash] = ifa; inet6_addr_lst[hash] = ifa;
in6_ifa_hold(ifa); in6_ifa_hold(ifa);
write_unlock_bh(&addrconf_hash_lock); write_unlock(&addrconf_hash_lock);
write_lock_bh(&idev->lock); write_lock(&idev->lock);
/* Add to inet6_dev unicast addr list. */ /* Add to inet6_dev unicast addr list. */
ifa->if_next = idev->addr_list; ifa->if_next = idev->addr_list;
idev->addr_list = ifa; idev->addr_list = ifa;
#ifdef CONFIG_IPV6_PRIVACY #ifdef CONFIG_IPV6_PRIVACY
ifa->regen_count = 0;
if (ifa->flags&IFA_F_TEMPORARY) { if (ifa->flags&IFA_F_TEMPORARY) {
ifa->tmp_next = idev->tempaddr_list; ifa->tmp_next = idev->tempaddr_list;
idev->tempaddr_list = ifa; idev->tempaddr_list = ifa;
in6_ifa_hold(ifa); in6_ifa_hold(ifa);
} else {
ifa->tmp_next = NULL;
} }
#endif #endif
ifa->rt = rt; ifa->rt = rt;
in6_ifa_hold(ifa); in6_ifa_hold(ifa);
write_unlock_bh(&idev->lock); write_unlock(&idev->lock);
read_unlock(&addrconf_lock); out2:
out: read_unlock_bh(&addrconf_lock);
spin_unlock_bh(&lock);
if (unlikely(err == 0)) if (unlikely(err == 0))
notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
...@@ -578,6 +571,9 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, ...@@ -578,6 +571,9 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
} }
return ifa; return ifa;
out:
write_unlock(&addrconf_hash_lock);
goto out2;
} }
/* This function wants to get referenced ifp and releases it before return */ /* This function wants to get referenced ifp and releases it before return */
......
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