diff options
author | David S. Miller <davem@davemloft.net> | 2010-08-25 02:27:49 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-09-26 17:21:17 -0700 |
commit | a89d316f2bdf5df8f9a109d32f0e7b0940041e7f (patch) | |
tree | 5b6e3a0c5b305d0c7cd8654b4df2b638ce94a300 /include | |
parent | ebde7b9827da782d1fd0a51cdbac81b589552494 (diff) |
tcp: Combat per-cpu skew in orphan tests.
[ Upstream commit ad1af0fedba14f82b240a03fe20eb9b2fdbd0357 ]
As reported by Anton Blanchard when we use
percpu_counter_read_positive() to make our orphan socket limit checks,
the check can be off by up to num_cpus_online() * batch (which is 32
by default) which on a 128 cpu machine can be as large as the default
orphan limit itself.
Fix this by doing the full expensive sum check if the optimized check
triggers.
Reported-by: Anton Blanchard <anton@samba.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'include')
-rw-r--r-- | include/net/tcp.h | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index 842ac4de21c..6bc4ac02de0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -259,11 +259,21 @@ static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) return seq3 - seq2 >= seq1 - seq2; } -static inline int tcp_too_many_orphans(struct sock *sk, int num) +static inline bool tcp_too_many_orphans(struct sock *sk, int shift) { - return (num > sysctl_tcp_max_orphans) || - (sk->sk_wmem_queued > SOCK_MIN_SNDBUF && - atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2]); + struct percpu_counter *ocp = sk->sk_prot->orphan_count; + int orphans = percpu_counter_read_positive(ocp); + + if (orphans << shift > sysctl_tcp_max_orphans) { + orphans = percpu_counter_sum_positive(ocp); + if (orphans << shift > sysctl_tcp_max_orphans) + return true; + } + + if (sk->sk_wmem_queued > SOCK_MIN_SNDBUF && + atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2]) + return true; + return false; } /* syncookies: remember time of last synqueue overflow */ |