diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2009-11-06 07:01:17 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-08 00:43:18 -0800 |
commit | fd5c00276127661f12e0315e3bbec41a1c0be376 (patch) | |
tree | c144a45e26dadf3654336604a131c2c53e5235c4 /net/ipv6/raw.c | |
parent | 18294ad1ecccffe6a91f6914dc1f4acd8995736a (diff) | |
download | op-kernel-dev-fd5c00276127661f12e0315e3bbec41a1c0be376.zip op-kernel-dev-fd5c00276127661f12e0315e3bbec41a1c0be376.tar.gz |
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>
Diffstat (limited to 'net/ipv6/raw.c')
-rw-r--r-- | net/ipv6/raw.c | 23 |
1 files changed, 11 insertions, 12 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 818ef21..926ce8e 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -249,7 +249,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) /* Raw sockets are IPv6 only */ if (addr_type == IPV6_ADDR_MAPPED) - return(-EADDRNOTAVAIL); + return -EADDRNOTAVAIL; 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) goto out; + rcu_read_lock(); /* Check if the address belongs to the host. */ if (addr_type != IPV6_ADDR_ANY) { 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 */ 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; - goto out; - } + err = -ENODEV; + 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 @@ -289,13 +290,9 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) err = -EADDRNOTAVAIL; if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, dev, 0)) { - if (dev) - dev_put(dev); - goto out; + goto out_unlock; } } - if (dev) - dev_put(dev); } 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)) ipv6_addr_copy(&np->saddr, &addr->sin6_addr); err = 0; +out_unlock: + rcu_read_unlock(); out: release_sock(sk); return err; |