diff options
author | Thomas Graf <tgraf@suug.ch> | 2015-01-02 17:00:14 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-01-03 14:32:56 -0500 |
commit | 8d24c0b43125ec26cc80e04588477a9a2afc025c (patch) | |
tree | d02e1b74bf49017dd4fecdeaf82a1e4f8f64a25d /lib | |
parent | dd9553988879a3ff71a86323b88409e7631c4e5d (diff) |
rhashtable: Do hashing inside of rhashtable_lookup_compare()
Hash the key inside of rhashtable_lookup_compare() like
rhashtable_lookup() does. This allows to simplify the hashing
functions and keep them private.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Cc: netfilter-devel@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rhashtable.c | 91 |
1 files changed, 30 insertions, 61 deletions
diff --git a/lib/rhashtable.c b/lib/rhashtable.c index 6c3c723e902b..1ee0eb636ca3 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c | |||
@@ -42,69 +42,39 @@ static void *rht_obj(const struct rhashtable *ht, const struct rhash_head *he) | |||
42 | return (void *) he - ht->p.head_offset; | 42 | return (void *) he - ht->p.head_offset; |
43 | } | 43 | } |
44 | 44 | ||
45 | static u32 __hashfn(const struct rhashtable *ht, const void *key, | 45 | static u32 rht_bucket_index(const struct bucket_table *tbl, u32 hash) |
46 | u32 len, u32 hsize) | ||
47 | { | 46 | { |
48 | u32 h; | 47 | return hash & (tbl->size - 1); |
49 | |||
50 | h = ht->p.hashfn(key, len, ht->p.hash_rnd); | ||
51 | |||
52 | return h & (hsize - 1); | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * rhashtable_hashfn - compute hash for key of given length | ||
57 | * @ht: hash table to compute for | ||
58 | * @key: pointer to key | ||
59 | * @len: length of key | ||
60 | * | ||
61 | * Computes the hash value using the hash function provided in the 'hashfn' | ||
62 | * of struct rhashtable_params. The returned value is guaranteed to be | ||
63 | * smaller than the number of buckets in the hash table. | ||
64 | */ | ||
65 | u32 rhashtable_hashfn(const struct rhashtable *ht, const void *key, u32 len) | ||
66 | { | ||
67 | struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); | ||
68 | |||
69 | return __hashfn(ht, key, len, tbl->size); | ||
70 | } | 48 | } |
71 | EXPORT_SYMBOL_GPL(rhashtable_hashfn); | ||
72 | 49 | ||
73 | static u32 obj_hashfn(const struct rhashtable *ht, const void *ptr, u32 hsize) | 50 | static u32 obj_raw_hashfn(const struct rhashtable *ht, const void *ptr) |
74 | { | 51 | { |
75 | if (unlikely(!ht->p.key_len)) { | 52 | u32 hash; |
76 | u32 h; | ||
77 | |||
78 | h = ht->p.obj_hashfn(ptr, ht->p.hash_rnd); | ||
79 | 53 | ||
80 | return h & (hsize - 1); | 54 | if (unlikely(!ht->p.key_len)) |
81 | } | 55 | hash = ht->p.obj_hashfn(ptr, ht->p.hash_rnd); |
56 | else | ||
57 | hash = ht->p.hashfn(ptr + ht->p.key_offset, ht->p.key_len, | ||
58 | ht->p.hash_rnd); | ||
82 | 59 | ||
83 | return __hashfn(ht, ptr + ht->p.key_offset, ht->p.key_len, hsize); | 60 | return hash; |
84 | } | 61 | } |
85 | 62 | ||
86 | /** | 63 | static u32 key_hashfn(const struct rhashtable *ht, const void *key, u32 len) |
87 | * rhashtable_obj_hashfn - compute hash for hashed object | ||
88 | * @ht: hash table to compute for | ||
89 | * @ptr: pointer to hashed object | ||
90 | * | ||
91 | * Computes the hash value using the hash function `hashfn` respectively | ||
92 | * 'obj_hashfn' depending on whether the hash table is set up to work with | ||
93 | * a fixed length key. The returned value is guaranteed to be smaller than | ||
94 | * the number of buckets in the hash table. | ||
95 | */ | ||
96 | u32 rhashtable_obj_hashfn(const struct rhashtable *ht, void *ptr) | ||
97 | { | 64 | { |
98 | struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); | 65 | struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); |
66 | u32 hash; | ||
67 | |||
68 | hash = ht->p.hashfn(key, len, ht->p.hash_rnd); | ||
99 | 69 | ||
100 | return obj_hashfn(ht, ptr, tbl->size); | 70 | return rht_bucket_index(tbl, hash); |
101 | } | 71 | } |
102 | EXPORT_SYMBOL_GPL(rhashtable_obj_hashfn); | ||
103 | 72 | ||
104 | static u32 head_hashfn(const struct rhashtable *ht, | 73 | static u32 head_hashfn(const struct rhashtable *ht, |
105 | const struct rhash_head *he, u32 hsize) | 74 | const struct bucket_table *tbl, |
75 | const struct rhash_head *he) | ||
106 | { | 76 | { |
107 | return obj_hashfn(ht, rht_obj(ht, he), hsize); | 77 | return rht_bucket_index(tbl, obj_raw_hashfn(ht, rht_obj(ht, he))); |
108 | } | 78 | } |
109 | 79 | ||
110 | static struct bucket_table *bucket_table_alloc(size_t nbuckets) | 80 | static struct bucket_table *bucket_table_alloc(size_t nbuckets) |
@@ -170,9 +140,9 @@ static void hashtable_chain_unzip(const struct rhashtable *ht, | |||
170 | * reaches a node that doesn't hash to the same bucket as the | 140 | * reaches a node that doesn't hash to the same bucket as the |
171 | * previous node p. Call the previous node p; | 141 | * previous node p. Call the previous node p; |
172 | */ | 142 | */ |
173 | h = head_hashfn(ht, p, new_tbl->size); | 143 | h = head_hashfn(ht, new_tbl, p); |
174 | rht_for_each(he, p->next, ht) { | 144 | rht_for_each(he, p->next, ht) { |
175 | if (head_hashfn(ht, he, new_tbl->size) != h) | 145 | if (head_hashfn(ht, new_tbl, he) != h) |
176 | break; | 146 | break; |
177 | p = he; | 147 | p = he; |
178 | } | 148 | } |
@@ -184,7 +154,7 @@ static void hashtable_chain_unzip(const struct rhashtable *ht, | |||
184 | next = NULL; | 154 | next = NULL; |
185 | if (he) { | 155 | if (he) { |
186 | rht_for_each(he, he->next, ht) { | 156 | rht_for_each(he, he->next, ht) { |
187 | if (head_hashfn(ht, he, new_tbl->size) == h) { | 157 | if (head_hashfn(ht, new_tbl, he) == h) { |
188 | next = he; | 158 | next = he; |
189 | break; | 159 | break; |
190 | } | 160 | } |
@@ -237,9 +207,9 @@ int rhashtable_expand(struct rhashtable *ht) | |||
237 | * single imprecise chain. | 207 | * single imprecise chain. |
238 | */ | 208 | */ |
239 | for (i = 0; i < new_tbl->size; i++) { | 209 | for (i = 0; i < new_tbl->size; i++) { |
240 | h = i & (old_tbl->size - 1); | 210 | h = rht_bucket_index(old_tbl, i); |
241 | rht_for_each(he, old_tbl->buckets[h], ht) { | 211 | rht_for_each(he, old_tbl->buckets[h], ht) { |
242 | if (head_hashfn(ht, he, new_tbl->size) == i) { | 212 | if (head_hashfn(ht, new_tbl, he) == i) { |
243 | RCU_INIT_POINTER(new_tbl->buckets[i], he); | 213 | RCU_INIT_POINTER(new_tbl->buckets[i], he); |
244 | break; | 214 | break; |
245 | } | 215 | } |
@@ -353,7 +323,7 @@ void rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj) | |||
353 | 323 | ||
354 | ASSERT_RHT_MUTEX(ht); | 324 | ASSERT_RHT_MUTEX(ht); |
355 | 325 | ||
356 | hash = head_hashfn(ht, obj, tbl->size); | 326 | hash = head_hashfn(ht, tbl, obj); |
357 | RCU_INIT_POINTER(obj->next, tbl->buckets[hash]); | 327 | RCU_INIT_POINTER(obj->next, tbl->buckets[hash]); |
358 | rcu_assign_pointer(tbl->buckets[hash], obj); | 328 | rcu_assign_pointer(tbl->buckets[hash], obj); |
359 | ht->nelems++; | 329 | ht->nelems++; |
@@ -413,7 +383,7 @@ bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *obj) | |||
413 | 383 | ||
414 | ASSERT_RHT_MUTEX(ht); | 384 | ASSERT_RHT_MUTEX(ht); |
415 | 385 | ||
416 | h = head_hashfn(ht, obj, tbl->size); | 386 | h = head_hashfn(ht, tbl, obj); |
417 | 387 | ||
418 | pprev = &tbl->buckets[h]; | 388 | pprev = &tbl->buckets[h]; |
419 | rht_for_each(he, tbl->buckets[h], ht) { | 389 | rht_for_each(he, tbl->buckets[h], ht) { |
@@ -452,7 +422,7 @@ void *rhashtable_lookup(const struct rhashtable *ht, const void *key) | |||
452 | 422 | ||
453 | BUG_ON(!ht->p.key_len); | 423 | BUG_ON(!ht->p.key_len); |
454 | 424 | ||
455 | h = __hashfn(ht, key, ht->p.key_len, tbl->size); | 425 | h = key_hashfn(ht, key, ht->p.key_len); |
456 | rht_for_each_rcu(he, tbl->buckets[h], ht) { | 426 | rht_for_each_rcu(he, tbl->buckets[h], ht) { |
457 | if (memcmp(rht_obj(ht, he) + ht->p.key_offset, key, | 427 | if (memcmp(rht_obj(ht, he) + ht->p.key_offset, key, |
458 | ht->p.key_len)) | 428 | ht->p.key_len)) |
@@ -467,7 +437,7 @@ EXPORT_SYMBOL_GPL(rhashtable_lookup); | |||
467 | /** | 437 | /** |
468 | * rhashtable_lookup_compare - search hash table with compare function | 438 | * rhashtable_lookup_compare - search hash table with compare function |
469 | * @ht: hash table | 439 | * @ht: hash table |
470 | * @hash: hash value of desired entry | 440 | * @key: the pointer to the key |
471 | * @compare: compare function, must return true on match | 441 | * @compare: compare function, must return true on match |
472 | * @arg: argument passed on to compare function | 442 | * @arg: argument passed on to compare function |
473 | * | 443 | * |
@@ -479,15 +449,14 @@ EXPORT_SYMBOL_GPL(rhashtable_lookup); | |||
479 | * | 449 | * |
480 | * Returns the first entry on which the compare function returned true. | 450 | * Returns the first entry on which the compare function returned true. |
481 | */ | 451 | */ |
482 | void *rhashtable_lookup_compare(const struct rhashtable *ht, u32 hash, | 452 | void *rhashtable_lookup_compare(const struct rhashtable *ht, const void *key, |
483 | bool (*compare)(void *, void *), void *arg) | 453 | bool (*compare)(void *, void *), void *arg) |
484 | { | 454 | { |
485 | const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); | 455 | const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); |
486 | struct rhash_head *he; | 456 | struct rhash_head *he; |
457 | u32 hash; | ||
487 | 458 | ||
488 | if (unlikely(hash >= tbl->size)) | 459 | hash = key_hashfn(ht, key, ht->p.key_len); |
489 | return NULL; | ||
490 | |||
491 | rht_for_each_rcu(he, tbl->buckets[hash], ht) { | 460 | rht_for_each_rcu(he, tbl->buckets[hash], ht) { |
492 | if (!compare(rht_obj(ht, he), arg)) | 461 | if (!compare(rht_obj(ht, he), arg)) |
493 | continue; | 462 | continue; |