ipv6: avoid dev_hold()/dev_put() in rawv6_bind()
Subsystems (2)
PATCH 1/1 ipv6: avoid dev_hold()/dev_put() in rawv6_bind()
Using RCU helps not touching device refcount in rawv6_bind()
--- net/ipv6/raw.c | 23 +++++++++++------------ 1 files changed, 11 insertions(+), 12 deletions(-)
net/ipv6/raw.c +11 -12
@@ -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_unlock ();/* 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;
net/ipv6/raw.c static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) · line 263
Quoted 8 lines · Eric Dumazet
net/ipv6/raw.c +1
-0@@ -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_unlock ();/* Check if the address belongs to the host. */ if (addr_type !=IPV6_ADDR_ANY ) {struct net_device *dev =NULL ;
This was supposed to be rcu_read_lock(), right?
-Brian
Quoted 5 lines · Brian Haley
Quoted 4 lines · Eric Dumazet
(quoted diff) +0
-0@@ -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;
Quoted 7 lines
Review static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) · line 263
Quoted 4 lines
(quoted diff) +1
-0+ rcu_read_unlock(); /* Check if the address belongs to the host. */ if (addr_type != IPV6_ADDR_ANY) { struct net_device *dev = NULL;This was supposed to be
rcu_read_lock(), right?
Oops ! Indeed ! Thanks for spotting this Brian.
[PATCH net-next2.6] ipv6: avoid dev_hold()/dev_put() in rawv6_bind()
Using RCU helps not touching device refcount in rawv6_bind()
--- net/ipv6/raw.c | 23 +++++++++++------------ 1 files changed, 11 insertions(+), 12 deletions(-)
net/ipv6/raw.c +11 -12
@@ -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;
From: Eric Dumazet <[email protected]>
Date: Fri, 06 Nov 2009 18:01:17 +0100
Quoted 5 lines
[PATCH net-next2.6] ipv6: avoid dev_hold()/dev_put() in
rawv6_bind()Using RCU helps not touching device refcount in
rawv6_bind()Signed-off-by Eric Dumazet <[email protected]>
Applied, thanks.