ipv6: avoid dev_hold()/dev_put() in rawv6_bind()
Using RCU helps not touching device refcount in rawv6_bind() Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
18294ad1ec
commit
fd5c002761
@@ -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)
|
|||||||
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)
|
|||||||
|
|
||||||
/* 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);
|
err = -ENODEV;
|
||||||
if (!dev) {
|
dev = dev_get_by_index_rcu(sock_net(sk),
|
||||||
err = -ENODEV;
|
sk->sk_bound_dev_if);
|
||||||
goto out;
|
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)
|
|||||||
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)
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user