Commit fd5c0027 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

ipv6: avoid dev_hold()/dev_put() in rawv6_bind()

Using RCU helps not touching device refcount in rawv6_bind()
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 18294ad1
...@@ -249,7 +249,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -249,7 +249,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
/* Raw sockets are IPv6 only */ /* Raw sockets are IPv6 only */
if (addr_type == IPV6_ADDR_MAPPED) if (addr_type == IPV6_ADDR_MAPPED)
return(-EADDRNOTAVAIL); return -EADDRNOTAVAIL;
lock_sock(sk); lock_sock(sk);
...@@ -257,6 +257,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -257,6 +257,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (sk->sk_state != TCP_CLOSE) if (sk->sk_state != TCP_CLOSE)
goto out; goto out;
rcu_read_lock();
/* Check if the address belongs to the host. */ /* Check if the address belongs to the host. */
if (addr_type != IPV6_ADDR_ANY) { if (addr_type != IPV6_ADDR_ANY) {
struct net_device *dev = NULL; struct net_device *dev = NULL;
...@@ -272,13 +273,13 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -272,13 +273,13 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
/* Binding to link-local address requires an interface */ /* Binding to link-local address requires an interface */
if (!sk->sk_bound_dev_if) if (!sk->sk_bound_dev_if)
goto out; goto out_unlock;
dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
if (!dev) {
err = -ENODEV; err = -ENODEV;
goto out; dev = dev_get_by_index_rcu(sock_net(sk),
} sk->sk_bound_dev_if);
if (!dev)
goto out_unlock;
} }
/* ipv4 addr of the socket is invalid. Only the /* ipv4 addr of the socket is invalid. Only the
...@@ -289,13 +290,9 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -289,13 +290,9 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr,
dev, 0)) { dev, 0)) {
if (dev) goto out_unlock;
dev_put(dev);
goto out;
} }
} }
if (dev)
dev_put(dev);
} }
inet->inet_rcv_saddr = inet->inet_saddr = v4addr; inet->inet_rcv_saddr = inet->inet_saddr = v4addr;
...@@ -303,6 +300,8 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -303,6 +300,8 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (!(addr_type & IPV6_ADDR_MULTICAST)) if (!(addr_type & IPV6_ADDR_MULTICAST))
ipv6_addr_copy(&np->saddr, &addr->sin6_addr); ipv6_addr_copy(&np->saddr, &addr->sin6_addr);
err = 0; err = 0;
out_unlock:
rcu_read_unlock();
out: out:
release_sock(sk); release_sock(sk);
return err; return err;
......
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