]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
udp: inuse checks can quit early for reuseport
authorEric Garver <e@erig.me>
Fri, 6 Jan 2017 01:22:36 +0000 (20:22 -0500)
committerDavid S. Miller <davem@davemloft.net>
Sat, 7 Jan 2017 01:56:48 +0000 (20:56 -0500)
UDP lib inuse checks will walk the entire hash bucket to check if the
portaddr is in use. In the case of reuseport we can stop searching when
we find a matching reuseport.

On a 16-core VM a test program that spawns 16 threads that each bind to
1024 sockets (one per 10ms) takes 1m45s. With this change it takes 11s.

Also add a cond_resched() when the port is not specified.

Signed-off-by: Eric Garver <e@erig.me>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/udp.c

index 1307a7c2e5445d37d1d1c4f5fbfd5bf7c29040d7..4318d72e0248ddf0f1ce5990fb3df60471088dc0 100644 (file)
@@ -153,13 +153,18 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
                    (!sk2->sk_reuse || !sk->sk_reuse) &&
                    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
                     sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
-                   (!sk2->sk_reuseport || !sk->sk_reuseport ||
-                    rcu_access_pointer(sk->sk_reuseport_cb) ||
-                    !uid_eq(uid, sock_i_uid(sk2))) &&
                    saddr_comp(sk, sk2, true)) {
-                       if (!bitmap)
-                               return 1;
-                       __set_bit(udp_sk(sk2)->udp_port_hash >> log, bitmap);
+                       if (sk2->sk_reuseport && sk->sk_reuseport &&
+                           !rcu_access_pointer(sk->sk_reuseport_cb) &&
+                           uid_eq(uid, sock_i_uid(sk2))) {
+                               if (!bitmap)
+                                       return 0;
+                       } else {
+                               if (!bitmap)
+                                       return 1;
+                               __set_bit(udp_sk(sk2)->udp_port_hash >> log,
+                                         bitmap);
+                       }
                }
        }
        return 0;
@@ -188,11 +193,14 @@ static int udp_lib_lport_inuse2(struct net *net, __u16 num,
                    (!sk2->sk_reuse || !sk->sk_reuse) &&
                    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
                     sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
-                   (!sk2->sk_reuseport || !sk->sk_reuseport ||
-                    rcu_access_pointer(sk->sk_reuseport_cb) ||
-                    !uid_eq(uid, sock_i_uid(sk2))) &&
                    saddr_comp(sk, sk2, true)) {
-                       res = 1;
+                       if (sk2->sk_reuseport && sk->sk_reuseport &&
+                           !rcu_access_pointer(sk->sk_reuseport_cb) &&
+                           uid_eq(uid, sock_i_uid(sk2))) {
+                               res = 0;
+                       } else {
+                               res = 1;
+                       }
                        break;
                }
        }
@@ -285,6 +293,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
                                snum += rand;
                        } while (snum != first);
                        spin_unlock_bh(&hslot->lock);
+                       cond_resched();
                } while (++first != last);
                goto fail;
        } else {