aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/raw.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-11-06 02:01:17 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-08 03:43:18 -0500
commitfd5c00276127661f12e0315e3bbec41a1c0be376 (patch)
treec144a45e26dadf3654336604a131c2c53e5235c4 /net/ipv6/raw.c
parent18294ad1ecccffe6a91f6914dc1f4acd8995736a (diff)
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.c23
1 files changed, 11 insertions, 12 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 818ef21ba76d..926ce8eeffaf 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)
249 249
250 /* Raw sockets are IPv6 only */ 250 /* Raw sockets are IPv6 only */
251 if (addr_type == IPV6_ADDR_MAPPED) 251 if (addr_type == IPV6_ADDR_MAPPED)
252 return(-EADDRNOTAVAIL); 252 return -EADDRNOTAVAIL;
253 253
254 lock_sock(sk); 254 lock_sock(sk);
255 255
@@ -257,6 +257,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
257 if (sk->sk_state != TCP_CLOSE) 257 if (sk->sk_state != TCP_CLOSE)
258 goto out; 258 goto out;
259 259
260 rcu_read_lock();
260 /* Check if the address belongs to the host. */ 261 /* Check if the address belongs to the host. */
261 if (addr_type != IPV6_ADDR_ANY) { 262 if (addr_type != IPV6_ADDR_ANY) {
262 struct net_device *dev = NULL; 263 struct net_device *dev = NULL;
@@ -272,13 +273,13 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
272 273
273 /* Binding to link-local address requires an interface */ 274 /* Binding to link-local address requires an interface */
274 if (!sk->sk_bound_dev_if) 275 if (!sk->sk_bound_dev_if)
275 goto out; 276 goto out_unlock;
276 277
277 dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); 278 err = -ENODEV;
278 if (!dev) { 279 dev = dev_get_by_index_rcu(sock_net(sk),
279 err = -ENODEV; 280 sk->sk_bound_dev_if);
280 goto out; 281 if (!dev)
281 } 282 goto out_unlock;
282 } 283 }
283 284
284 /* ipv4 addr of the socket is invalid. Only the 285 /* 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 err = -EADDRNOTAVAIL; 290 err = -EADDRNOTAVAIL;
290 if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, 291 if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr,
291 dev, 0)) { 292 dev, 0)) {
292 if (dev) 293 goto out_unlock;
293 dev_put(dev);
294 goto out;
295 } 294 }
296 } 295 }
297 if (dev)
298 dev_put(dev);
299 } 296 }
300 297
301 inet->inet_rcv_saddr = inet->inet_saddr = v4addr; 298 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 if (!(addr_type & IPV6_ADDR_MULTICAST)) 300 if (!(addr_type & IPV6_ADDR_MULTICAST))
304 ipv6_addr_copy(&np->saddr, &addr->sin6_addr); 301 ipv6_addr_copy(&np->saddr, &addr->sin6_addr);
305 err = 0; 302 err = 0;
303out_unlock:
304 rcu_read_unlock();
306out: 305out:
307 release_sock(sk); 306 release_sock(sk);
308 return err; 307 return err;