From: Heinz Mauelshagen <heinzm@redhat.com>

Instead of using a fixed prime for the region hash buckets, select one from
a sequence of primes, each one roughly twice the last one and mid-way
between each pair of powers of 2.

[Hoping for some real-world evidence this improves performance - AGK]

Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com>
Signed-off-by: agk@redhat.com
---
 drivers/md/dm-region-hash.c |   19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

Index: linux-2.6.30/drivers/md/dm-region-hash.c
===================================================================
--- linux-2.6.30.orig/drivers/md/dm-region-hash.c
+++ linux-2.6.30/drivers/md/dm-region-hash.c
@@ -148,11 +148,16 @@ sector_t dm_rh_get_region_size(struct dm
 EXPORT_SYMBOL_GPL(dm_rh_get_region_size);
 
 /*
+ * Table of primes for rh_hash/table size optimization.
+ */
+static const unsigned dm_region_hash_primes[] = {
+	3, 7, 13, 27, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
+};
+
+/*
  * FIXME: shall we pass in a structure instead of all these args to
  * dm_region_hash_create()????
- */
-#define RH_HASH_MULT 2654435387U
-#define RH_HASH_SHIFT 12
+*/
 
 #define MIN_REGIONS 64
 struct dm_region_hash *dm_region_hash_create(
@@ -196,8 +201,12 @@ struct dm_region_hash *dm_region_hash_cr
 	rh->mask = nr_buckets - 1;
 	rh->nr_buckets = nr_buckets;
 
-	rh->shift = RH_HASH_SHIFT;
-	rh->prime = RH_HASH_MULT;
+	rh->shift = ffs(nr_buckets);
+	if (rh->shift - 1 > ARRAY_SIZE(dm_region_hash_primes))
+		i = ARRAY_SIZE(dm_region_hash_primes);
+	else
+		i = rh->shift - 1;
+	rh->prime = dm_region_hash_primes[i - 1];
 
 	rh->buckets = vmalloc(nr_buckets * sizeof(*rh->buckets));
 	if (!rh->buckets) {