ipv6: no more dev_put() in inet6_bind()
authorEric Dumazet <eric.dumazet@gmail.com>
Mon, 2 Nov 2009 11:10:39 +0000 (12:10 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 2 Nov 2009 11:42:41 +0000 (03:42 -0800)
Avoids touching device refcount in inet6_bind(), thanks to RCU

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/af_inet6.c

index b6d0588..9105b25 100644 (file)
@@ -314,6 +314,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                if (addr_type != IPV6_ADDR_ANY) {
                        struct net_device *dev = NULL;
 
+                       rcu_read_lock();
                        if (addr_type & IPV6_ADDR_LINKLOCAL) {
                                if (addr_len >= sizeof(struct sockaddr_in6) &&
                                    addr->sin6_scope_id) {
@@ -326,12 +327,12 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                                /* Binding to link-local address requires an interface */
                                if (!sk->sk_bound_dev_if) {
                                        err = -EINVAL;
-                                       goto out;
+                                       goto out_unlock;
                                }
-                               dev = dev_get_by_index(net, sk->sk_bound_dev_if);
+                               dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
                                if (!dev) {
                                        err = -ENODEV;
-                                       goto out;
+                                       goto out_unlock;
                                }
                        }
 
@@ -342,14 +343,11 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                        if (!(addr_type & IPV6_ADDR_MULTICAST)) {
                                if (!ipv6_chk_addr(net, &addr->sin6_addr,
                                                   dev, 0)) {
-                                       if (dev)
-                                               dev_put(dev);
                                        err = -EADDRNOTAVAIL;
-                                       goto out;
+                                       goto out_unlock;
                                }
                        }
-                       if (dev)
-                               dev_put(dev);
+                       rcu_read_unlock();
                }
        }
 
@@ -381,6 +379,9 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 out:
        release_sock(sk);
        return err;
+out_unlock:
+       rcu_read_unlock();
+       goto out;
 }
 
 EXPORT_SYMBOL(inet6_bind);