diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2006-09-22 17:44:24 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 18:20:26 -0400 |
commit | 8814c4b533817df825485ff32ce6ac406c3a54d1 (patch) | |
tree | b72cc3513e7dc4b60e98c7ddebe76bca188f88fc /net/ipv6/addrconf.c | |
parent | fbea49e1e2404baa2d88ab47e2db89e49551b53b (diff) |
[IPV6] ADDRCONF: Convert addrconf_lock to RCU.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 46 |
1 files changed, 24 insertions, 22 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 825a291d5aa5..c09ebb7bb98a 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -119,9 +119,6 @@ static int ipv6_count_addresses(struct inet6_dev *idev); | |||
119 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; | 119 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; |
120 | static DEFINE_RWLOCK(addrconf_hash_lock); | 120 | static DEFINE_RWLOCK(addrconf_hash_lock); |
121 | 121 | ||
122 | /* Protects inet6 devices */ | ||
123 | DEFINE_RWLOCK(addrconf_lock); | ||
124 | |||
125 | static void addrconf_verify(unsigned long); | 122 | static void addrconf_verify(unsigned long); |
126 | 123 | ||
127 | static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0); | 124 | static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0); |
@@ -318,6 +315,12 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
318 | 315 | ||
319 | /* Nobody refers to this device, we may destroy it. */ | 316 | /* Nobody refers to this device, we may destroy it. */ |
320 | 317 | ||
318 | static void in6_dev_finish_destroy_rcu(struct rcu_head *head) | ||
319 | { | ||
320 | struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu); | ||
321 | kfree(idev); | ||
322 | } | ||
323 | |||
321 | void in6_dev_finish_destroy(struct inet6_dev *idev) | 324 | void in6_dev_finish_destroy(struct inet6_dev *idev) |
322 | { | 325 | { |
323 | struct net_device *dev = idev->dev; | 326 | struct net_device *dev = idev->dev; |
@@ -332,7 +335,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) | |||
332 | return; | 335 | return; |
333 | } | 336 | } |
334 | snmp6_free_dev(idev); | 337 | snmp6_free_dev(idev); |
335 | kfree(idev); | 338 | call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); |
336 | } | 339 | } |
337 | 340 | ||
338 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | 341 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) |
@@ -408,9 +411,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
408 | if (netif_carrier_ok(dev)) | 411 | if (netif_carrier_ok(dev)) |
409 | ndev->if_flags |= IF_READY; | 412 | ndev->if_flags |= IF_READY; |
410 | 413 | ||
411 | write_lock_bh(&addrconf_lock); | 414 | /* protected by rtnl_lock */ |
412 | dev->ip6_ptr = ndev; | 415 | rcu_assign_pointer(dev->ip6_ptr, ndev); |
413 | write_unlock_bh(&addrconf_lock); | ||
414 | 416 | ||
415 | ipv6_mc_init_dev(ndev); | 417 | ipv6_mc_init_dev(ndev); |
416 | ndev->tstamp = jiffies; | 418 | ndev->tstamp = jiffies; |
@@ -474,7 +476,7 @@ static void addrconf_forward_change(void) | |||
474 | 476 | ||
475 | read_lock(&dev_base_lock); | 477 | read_lock(&dev_base_lock); |
476 | for (dev=dev_base; dev; dev=dev->next) { | 478 | for (dev=dev_base; dev; dev=dev->next) { |
477 | read_lock(&addrconf_lock); | 479 | rcu_read_lock(); |
478 | idev = __in6_dev_get(dev); | 480 | idev = __in6_dev_get(dev); |
479 | if (idev) { | 481 | if (idev) { |
480 | int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding); | 482 | int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding); |
@@ -482,7 +484,7 @@ static void addrconf_forward_change(void) | |||
482 | if (changed) | 484 | if (changed) |
483 | dev_forward_change(idev); | 485 | dev_forward_change(idev); |
484 | } | 486 | } |
485 | read_unlock(&addrconf_lock); | 487 | rcu_read_unlock(); |
486 | } | 488 | } |
487 | read_unlock(&dev_base_lock); | 489 | read_unlock(&dev_base_lock); |
488 | } | 490 | } |
@@ -543,7 +545,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
543 | int hash; | 545 | int hash; |
544 | int err = 0; | 546 | int err = 0; |
545 | 547 | ||
546 | read_lock_bh(&addrconf_lock); | 548 | rcu_read_lock_bh(); |
547 | if (idev->dead) { | 549 | if (idev->dead) { |
548 | err = -ENODEV; /*XXX*/ | 550 | err = -ENODEV; /*XXX*/ |
549 | goto out2; | 551 | goto out2; |
@@ -612,7 +614,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
612 | in6_ifa_hold(ifa); | 614 | in6_ifa_hold(ifa); |
613 | write_unlock(&idev->lock); | 615 | write_unlock(&idev->lock); |
614 | out2: | 616 | out2: |
615 | read_unlock_bh(&addrconf_lock); | 617 | rcu_read_unlock_bh(); |
616 | 618 | ||
617 | if (likely(err == 0)) | 619 | if (likely(err == 0)) |
618 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); | 620 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); |
@@ -915,7 +917,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
915 | memset(&hiscore, 0, sizeof(hiscore)); | 917 | memset(&hiscore, 0, sizeof(hiscore)); |
916 | 918 | ||
917 | read_lock(&dev_base_lock); | 919 | read_lock(&dev_base_lock); |
918 | read_lock(&addrconf_lock); | 920 | rcu_read_lock(); |
919 | 921 | ||
920 | for (dev = dev_base; dev; dev=dev->next) { | 922 | for (dev = dev_base; dev; dev=dev->next) { |
921 | struct inet6_dev *idev; | 923 | struct inet6_dev *idev; |
@@ -1127,7 +1129,7 @@ record_it: | |||
1127 | } | 1129 | } |
1128 | read_unlock_bh(&idev->lock); | 1130 | read_unlock_bh(&idev->lock); |
1129 | } | 1131 | } |
1130 | read_unlock(&addrconf_lock); | 1132 | rcu_read_unlock(); |
1131 | read_unlock(&dev_base_lock); | 1133 | read_unlock(&dev_base_lock); |
1132 | 1134 | ||
1133 | if (!ifa_result) | 1135 | if (!ifa_result) |
@@ -1151,7 +1153,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | |||
1151 | struct inet6_dev *idev; | 1153 | struct inet6_dev *idev; |
1152 | int err = -EADDRNOTAVAIL; | 1154 | int err = -EADDRNOTAVAIL; |
1153 | 1155 | ||
1154 | read_lock(&addrconf_lock); | 1156 | rcu_read_lock(); |
1155 | if ((idev = __in6_dev_get(dev)) != NULL) { | 1157 | if ((idev = __in6_dev_get(dev)) != NULL) { |
1156 | struct inet6_ifaddr *ifp; | 1158 | struct inet6_ifaddr *ifp; |
1157 | 1159 | ||
@@ -1165,7 +1167,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | |||
1165 | } | 1167 | } |
1166 | read_unlock_bh(&idev->lock); | 1168 | read_unlock_bh(&idev->lock); |
1167 | } | 1169 | } |
1168 | read_unlock(&addrconf_lock); | 1170 | rcu_read_unlock(); |
1169 | return err; | 1171 | return err; |
1170 | } | 1172 | } |
1171 | 1173 | ||
@@ -1466,7 +1468,7 @@ static void ipv6_regen_rndid(unsigned long data) | |||
1466 | struct inet6_dev *idev = (struct inet6_dev *) data; | 1468 | struct inet6_dev *idev = (struct inet6_dev *) data; |
1467 | unsigned long expires; | 1469 | unsigned long expires; |
1468 | 1470 | ||
1469 | read_lock_bh(&addrconf_lock); | 1471 | rcu_read_lock_bh(); |
1470 | write_lock_bh(&idev->lock); | 1472 | write_lock_bh(&idev->lock); |
1471 | 1473 | ||
1472 | if (idev->dead) | 1474 | if (idev->dead) |
@@ -1490,7 +1492,7 @@ static void ipv6_regen_rndid(unsigned long data) | |||
1490 | 1492 | ||
1491 | out: | 1493 | out: |
1492 | write_unlock_bh(&idev->lock); | 1494 | write_unlock_bh(&idev->lock); |
1493 | read_unlock_bh(&addrconf_lock); | 1495 | rcu_read_unlock_bh(); |
1494 | in6_dev_put(idev); | 1496 | in6_dev_put(idev); |
1495 | } | 1497 | } |
1496 | 1498 | ||
@@ -2342,10 +2344,10 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2342 | Do not dev_put! | 2344 | Do not dev_put! |
2343 | */ | 2345 | */ |
2344 | if (how == 1) { | 2346 | if (how == 1) { |
2345 | write_lock_bh(&addrconf_lock); | ||
2346 | dev->ip6_ptr = NULL; | ||
2347 | idev->dead = 1; | 2347 | idev->dead = 1; |
2348 | write_unlock_bh(&addrconf_lock); | 2348 | |
2349 | /* protected by rtnl_lock */ | ||
2350 | rcu_assign_pointer(dev->ip6_ptr, NULL); | ||
2349 | 2351 | ||
2350 | /* Step 1.5: remove snmp6 entry */ | 2352 | /* Step 1.5: remove snmp6 entry */ |
2351 | snmp6_unregister_dev(idev); | 2353 | snmp6_unregister_dev(idev); |
@@ -3573,10 +3575,10 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
3573 | 3575 | ||
3574 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 3576 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
3575 | { | 3577 | { |
3576 | read_lock_bh(&addrconf_lock); | 3578 | rcu_read_lock_bh(); |
3577 | if (likely(ifp->idev->dead == 0)) | 3579 | if (likely(ifp->idev->dead == 0)) |
3578 | __ipv6_ifa_notify(event, ifp); | 3580 | __ipv6_ifa_notify(event, ifp); |
3579 | read_unlock_bh(&addrconf_lock); | 3581 | rcu_read_unlock_bh(); |
3580 | } | 3582 | } |
3581 | 3583 | ||
3582 | #ifdef CONFIG_SYSCTL | 3584 | #ifdef CONFIG_SYSCTL |