Subject: [RFC 2/2] udp: udp_lib_get_port start at a different bucket on different processors

From: Lucian Adrian Grijincu <[email-masked]>
Date: Wed, 16 Dec 2009 21:24:44 +0200

On SMP, when ports are not allocated randomly, using the same starting
port on all processors will lead to bad performance as all processors
will try to get the same hashbucket spinlock: only one will succeed,
the rest will spin madly.

We solve this problem by making each processor start searching from a
different port. To not skip possibly valid port ranges we renormalize
the hint value too.

Signed-off-by: Lucian Adrian Grijincu <[email-masked]>
---
  net/ipv4/udp.c |   12 +++++++++---
  1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index f437d9d..5d17c71 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -219,7 +219,9 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
 			first = (((u64)rand * remaining) >> 32) + low;
 		} else {
 			rand = 1;
-			first = hint;
+			first = hint + smp_processor_id();
+			if (first > high)
+				first = low + (first - low) % remaining;
 		}
 		/*
 		 * force rand to be an odd multiple of UDP_HTABLE_SIZE
@@ -243,8 +245,12 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
 			do {
 				if (low <= snum && snum <= high &&
 				    !test_bit(snum >> udptable->log, bitmap)) {
-					if (unlikely(!sysctl_udp_port_randomization))
-						hint = snum;
+					if (unlikely(!sysctl_udp_port_randomization)) {
+						int cur_hint = snum - smp_processor_id();
+						if (cur_hint < low)
+							cur_hint = high - (low - cur_hint) % remaining;
+						hint = cur_hint;
+					}
 					goto found;
 				}
 				snum += rand;