Skip to content

Commit

Permalink
rhashtable: Allow hashfn to be unset
Browse files Browse the repository at this point in the history
Since every current rhashtable user uses jhash as their hash
function, the fact that jhash is an inline function causes each
user to generate a copy of its code.

This function provides a solution to this problem by allowing
hashfn to be unset.  In which case rhashtable will automatically
set it to jhash.  Furthermore, if the key length is a multiple
of 4, we will switch over to jhash2.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Acked-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Herbert Xu authored and David S. Miller committed Mar 24, 2015
1 parent de91b25 commit 31ccde2
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 7 deletions.
33 changes: 27 additions & 6 deletions include/linux/rhashtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/jhash.h>
#include <linux/list_nulls.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
Expand Down Expand Up @@ -103,7 +104,7 @@ struct rhashtable;
* @min_size: Minimum size while shrinking
* @nulls_base: Base value to generate nulls marker
* @locks_mul: Number of bucket locks to allocate per cpu (default: 128)
* @hashfn: Function to hash key
* @hashfn: Hash function (default: jhash2 if !(key_len % 4), or jhash)
* @obj_hashfn: Function to hash object
* @obj_cmpfn: Function to compare key with object
*/
Expand All @@ -125,6 +126,7 @@ struct rhashtable_params {
* struct rhashtable - Hash table handle
* @tbl: Bucket table
* @nelems: Number of elements in table
* @key_len: Key length for hashfn
* @p: Configuration parameters
* @run_work: Deferred worker to expand/shrink asynchronously
* @mutex: Mutex to protect current/future table swapping
Expand All @@ -134,6 +136,7 @@ struct rhashtable {
struct bucket_table __rcu *tbl;
atomic_t nelems;
bool being_destroyed;
unsigned int key_len;
struct rhashtable_params p;
struct work_struct run_work;
struct mutex mutex;
Expand Down Expand Up @@ -199,13 +202,31 @@ static inline unsigned int rht_key_hashfn(
struct rhashtable *ht, const struct bucket_table *tbl,
const void *key, const struct rhashtable_params params)
{
unsigned hash;

/* params must be equal to ht->p if it isn't constant. */
unsigned key_len = __builtin_constant_p(params.key_len) ?
(params.key_len ?: ht->p.key_len) :
params.key_len;
if (!__builtin_constant_p(params.key_len))
hash = ht->p.hashfn(key, ht->key_len, tbl->hash_rnd);
else if (params.key_len) {
unsigned key_len = params.key_len;

if (params.hashfn)
hash = params.hashfn(key, key_len, tbl->hash_rnd);
else if (key_len & (sizeof(u32) - 1))
hash = jhash(key, key_len, tbl->hash_rnd);
else
hash = jhash2(key, key_len / sizeof(u32),
tbl->hash_rnd);
} else {
unsigned key_len = ht->p.key_len;

if (params.hashfn)
hash = params.hashfn(key, key_len, tbl->hash_rnd);
else
hash = jhash(key, key_len, tbl->hash_rnd);
}

return rht_bucket_index(tbl, params.hashfn(key, key_len,
tbl->hash_rnd));
return rht_bucket_index(tbl, hash);
}

static inline unsigned int rht_head_hashfn(
Expand Down
17 changes: 16 additions & 1 deletion lib/rhashtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,11 @@ static size_t rounded_hashtable_size(const struct rhashtable_params *params)
(unsigned long)params->min_size);
}

static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed)
{
return jhash2(key, length, seed);
}

/**
* rhashtable_init - initialize a new hash table
* @ht: hash table to be initialized
Expand Down Expand Up @@ -583,7 +588,7 @@ int rhashtable_init(struct rhashtable *ht,

size = HASH_DEFAULT_SIZE;

if ((!(params->key_len && params->hashfn) && !params->obj_hashfn) ||
if ((!params->key_len && !params->obj_hashfn) ||
(params->obj_hashfn && !params->obj_cmpfn))
return -EINVAL;

Expand All @@ -610,6 +615,16 @@ int rhashtable_init(struct rhashtable *ht,
else
ht->p.locks_mul = BUCKET_LOCKS_PER_CPU;

ht->key_len = ht->p.key_len;
if (!params->hashfn) {
ht->p.hashfn = jhash;

if (!(ht->key_len & (sizeof(u32) - 1))) {
ht->key_len /= sizeof(u32);
ht->p.hashfn = rhashtable_jhash2;
}
}

tbl = bucket_table_alloc(ht, size);
if (tbl == NULL)
return -ENOMEM;
Expand Down

0 comments on commit 31ccde2

Please sign in to comment.