diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2009-11-06 02:01:17 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-08 03:43:18 -0500 |
commit | fd5c00276127661f12e0315e3bbec41a1c0be376 (patch) | |
tree | c144a45e26dadf3654336604a131c2c53e5235c4 /net/ipv6 | |
parent | 18294ad1ecccffe6a91f6914dc1f4acd8995736a (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')
-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 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; |
303 | out_unlock: | ||
304 | rcu_read_unlock(); | ||
306 | out: | 305 | out: |
307 | release_sock(sk); | 306 | release_sock(sk); |
308 | return err; | 307 | return err; |