]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/ipv6/anycast.c
Merge branch 'omap-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mv-sheeva.git] / net / ipv6 / anycast.c
index b5b07054508a5154315c99f0da67b903e9ce46ee..0e5e943446f08c60690170c4e8af6fdc962a645e 100644 (file)
@@ -77,41 +77,40 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
        pac->acl_next = NULL;
        ipv6_addr_copy(&pac->acl_addr, addr);
 
+       rcu_read_lock();
        if (ifindex == 0) {
                struct rt6_info *rt;
 
                rt = rt6_lookup(net, addr, NULL, 0, 0);
                if (rt) {
                        dev = rt->rt6i_dev;
-                       dev_hold(dev);
-                       dst_release(&rt->u.dst);
+                       dst_release(&rt->dst);
                } else if (ishost) {
                        err = -EADDRNOTAVAIL;
-                       goto out_free_pac;
+                       goto error;
                } else {
                        /* router, no matching interface: just pick one */
-
-                       dev = dev_get_by_flags(net, IFF_UP, IFF_UP|IFF_LOOPBACK);
+                       dev = dev_get_by_flags_rcu(net, IFF_UP,
+                                                  IFF_UP | IFF_LOOPBACK);
                }
        } else
-               dev = dev_get_by_index(net, ifindex);
+               dev = dev_get_by_index_rcu(net, ifindex);
 
        if (dev == NULL) {
                err = -ENODEV;
-               goto out_free_pac;
+               goto error;
        }
 
-       idev = in6_dev_get(dev);
+       idev = __in6_dev_get(dev);
        if (!idev) {
                if (ifindex)
                        err = -ENODEV;
                else
                        err = -EADDRNOTAVAIL;
-               goto out_dev_put;
+               goto error;
        }
        /* reset ishost, now that we have a specific device */
        ishost = !idev->cnf.forwarding;
-       in6_dev_put(idev);
 
        pac->acl_ifindex = dev->ifindex;
 
@@ -124,26 +123,22 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
                if (ishost)
                        err = -EADDRNOTAVAIL;
                if (err)
-                       goto out_dev_put;
+                       goto error;
        }
 
        err = ipv6_dev_ac_inc(dev, addr);
-       if (err)
-               goto out_dev_put;
-
-       write_lock_bh(&ipv6_sk_ac_lock);
-       pac->acl_next = np->ipv6_ac_list;
-       np->ipv6_ac_list = pac;
-       write_unlock_bh(&ipv6_sk_ac_lock);
-
-       dev_put(dev);
-
-       return 0;
+       if (!err) {
+               write_lock_bh(&ipv6_sk_ac_lock);
+               pac->acl_next = np->ipv6_ac_list;
+               np->ipv6_ac_list = pac;
+               write_unlock_bh(&ipv6_sk_ac_lock);
+               pac = NULL;
+       }
 
-out_dev_put:
-       dev_put(dev);
-out_free_pac:
-       sock_kfree_s(sk, pac, sizeof(*pac));
+error:
+       rcu_read_unlock();
+       if (pac)
+               sock_kfree_s(sk, pac, sizeof(*pac));
        return err;
 }
 
@@ -176,11 +171,12 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
 
        write_unlock_bh(&ipv6_sk_ac_lock);
 
-       dev = dev_get_by_index(net, pac->acl_ifindex);
-       if (dev) {
+       rcu_read_lock();
+       dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
+       if (dev)
                ipv6_dev_ac_dec(dev, &pac->acl_addr);
-               dev_put(dev);
-       }
+       rcu_read_unlock();
+
        sock_kfree_s(sk, pac, sizeof(*pac));
        return 0;
 }
@@ -199,13 +195,12 @@ void ipv6_sock_ac_close(struct sock *sk)
        write_unlock_bh(&ipv6_sk_ac_lock);
 
        prev_index = 0;
+       rcu_read_lock();
        while (pac) {
                struct ipv6_ac_socklist *next = pac->acl_next;
 
                if (pac->acl_ifindex != prev_index) {
-                       if (dev)
-                               dev_put(dev);
-                       dev = dev_get_by_index(net, pac->acl_ifindex);
+                       dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
                        prev_index = pac->acl_ifindex;
                }
                if (dev)
@@ -213,8 +208,7 @@ void ipv6_sock_ac_close(struct sock *sk)
                sock_kfree_s(sk, pac, sizeof(*pac));
                pac = next;
        }
-       if (dev)
-               dev_put(dev);
+       rcu_read_unlock();
 }
 
 #if 0
@@ -250,7 +244,7 @@ static void aca_put(struct ifacaddr6 *ac)
 {
        if (atomic_dec_and_test(&ac->aca_refcnt)) {
                in6_dev_put(ac->aca_idev);
-               dst_release(&ac->aca_rt->u.dst);
+               dst_release(&ac->aca_rt->dst);
                kfree(ac);
        }
 }
@@ -356,40 +350,39 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr)
        write_unlock_bh(&idev->lock);
        addrconf_leave_solict(idev, &aca->aca_addr);
 
-       dst_hold(&aca->aca_rt->u.dst);
+       dst_hold(&aca->aca_rt->dst);
        ip6_del_rt(aca->aca_rt);
 
        aca_put(aca);
        return 0;
 }
 
+/* called with rcu_read_lock() */
 static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
 {
-       int ret;
-       struct inet6_dev *idev = in6_dev_get(dev);
+       struct inet6_dev *idev = __in6_dev_get(dev);
+
        if (idev == NULL)
                return -ENODEV;
-       ret = __ipv6_dev_ac_dec(idev, addr);
-       in6_dev_put(idev);
-       return ret;
+       return __ipv6_dev_ac_dec(idev, addr);
 }
 
 /*
  *     check if the interface has this anycast address
+ *     called with rcu_read_lock()
  */
 static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
 {
        struct inet6_dev *idev;
        struct ifacaddr6 *aca;
 
-       idev = in6_dev_get(dev);
+       idev = __in6_dev_get(dev);
        if (idev) {
                read_lock_bh(&idev->lock);
                for (aca = idev->ac_list; aca; aca = aca->aca_next)
                        if (ipv6_addr_equal(&aca->aca_addr, addr))
                                break;
                read_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
                return aca != NULL;
        }
        return 0;
@@ -403,14 +396,15 @@ int ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
 {
        int found = 0;
 
-       if (dev)
-               return ipv6_chk_acast_dev(dev, addr);
        rcu_read_lock();
-       for_each_netdev_rcu(net, dev)
-               if (ipv6_chk_acast_dev(dev, addr)) {
-                       found = 1;
-                       break;
-               }
+       if (dev)
+               found = ipv6_chk_acast_dev(dev, addr);
+       else
+               for_each_netdev_rcu(net, dev)
+                       if (ipv6_chk_acast_dev(dev, addr)) {
+                               found = 1;
+                               break;
+                       }
        rcu_read_unlock();
        return found;
 }