Commit 355ef8e1 authored by David Howells's avatar David Howells

keys: Cache the hash value to avoid lots of recalculation

Cache the hash of the key's type and description in the index key so that
we're not recalculating it every time we look at a key during a search.
The hash function does a bunch of multiplications, so evading those is
probably worthwhile - especially as this is done for every key examined
during a search.

This also allows the methods used by assoc_array to get chunks of index-key
to be simplified.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent f771fde8
...@@ -86,6 +86,8 @@ struct keyring_list; ...@@ -86,6 +86,8 @@ struct keyring_list;
struct keyring_name; struct keyring_name;
struct keyring_index_key { struct keyring_index_key {
/* [!] If this structure is altered, the union in struct key must change too! */
unsigned long hash; /* Hash value */
union { union {
struct { struct {
#ifdef __LITTLE_ENDIAN /* Put desc_len at the LSB of x */ #ifdef __LITTLE_ENDIAN /* Put desc_len at the LSB of x */
...@@ -213,6 +215,7 @@ struct key { ...@@ -213,6 +215,7 @@ struct key {
union { union {
struct keyring_index_key index_key; struct keyring_index_key index_key;
struct { struct {
unsigned long hash;
unsigned long len_desc; unsigned long len_desc;
struct key_type *type; /* type of key */ struct key_type *type; /* type of key */
char *description; char *description;
......
...@@ -89,13 +89,7 @@ extern spinlock_t key_serial_lock; ...@@ -89,13 +89,7 @@ extern spinlock_t key_serial_lock;
extern struct mutex key_construction_mutex; extern struct mutex key_construction_mutex;
extern wait_queue_head_t request_key_conswq; extern wait_queue_head_t request_key_conswq;
extern void key_set_index_key(struct keyring_index_key *index_key);
static inline void key_set_index_key(struct keyring_index_key *index_key)
{
size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc));
memcpy(index_key->desc, index_key->description, n);
}
extern struct key_type *key_type_lookup(const char *type); extern struct key_type *key_type_lookup(const char *type);
extern void key_type_put(struct key_type *ktype); extern void key_type_put(struct key_type *ktype);
......
...@@ -285,12 +285,12 @@ struct key *key_alloc(struct key_type *type, const char *desc, ...@@ -285,12 +285,12 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL); key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL);
if (!key->index_key.description) if (!key->index_key.description)
goto no_memory_3; goto no_memory_3;
key->index_key.type = type;
key_set_index_key(&key->index_key); key_set_index_key(&key->index_key);
refcount_set(&key->usage, 1); refcount_set(&key->usage, 1);
init_rwsem(&key->sem); init_rwsem(&key->sem);
lockdep_set_class(&key->sem, &type->lock_class); lockdep_set_class(&key->sem, &type->lock_class);
key->index_key.type = type;
key->user = user; key->user = user;
key->quotalen = quotalen; key->quotalen = quotalen;
key->datalen = type->def_datalen; key->datalen = type->def_datalen;
......
...@@ -168,7 +168,7 @@ static u64 mult_64x32_and_fold(u64 x, u32 y) ...@@ -168,7 +168,7 @@ static u64 mult_64x32_and_fold(u64 x, u32 y)
/* /*
* Hash a key type and description. * Hash a key type and description.
*/ */
static unsigned long hash_key_type_and_desc(const struct keyring_index_key *index_key) static void hash_key_type_and_desc(struct keyring_index_key *index_key)
{ {
const unsigned level_shift = ASSOC_ARRAY_LEVEL_STEP; const unsigned level_shift = ASSOC_ARRAY_LEVEL_STEP;
const unsigned long fan_mask = ASSOC_ARRAY_FAN_MASK; const unsigned long fan_mask = ASSOC_ARRAY_FAN_MASK;
...@@ -206,10 +206,22 @@ static unsigned long hash_key_type_and_desc(const struct keyring_index_key *inde ...@@ -206,10 +206,22 @@ static unsigned long hash_key_type_and_desc(const struct keyring_index_key *inde
* zero for keyrings and non-zero otherwise. * zero for keyrings and non-zero otherwise.
*/ */
if (index_key->type != &key_type_keyring && (hash & fan_mask) == 0) if (index_key->type != &key_type_keyring && (hash & fan_mask) == 0)
return hash | (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1; hash |= (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1;
if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0) else if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0)
return (hash + (hash << level_shift)) & ~fan_mask; hash = (hash + (hash << level_shift)) & ~fan_mask;
return hash; index_key->hash = hash;
}
/*
* Finalise an index key to include a part of the description actually in the
* index key and to add in the hash too.
*/
void key_set_index_key(struct keyring_index_key *index_key)
{
size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc));
memcpy(index_key->desc, index_key->description, n);
hash_key_type_and_desc(index_key);
} }
/* /*
...@@ -227,7 +239,7 @@ static unsigned long keyring_get_key_chunk(const void *data, int level) ...@@ -227,7 +239,7 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)
level /= ASSOC_ARRAY_KEY_CHUNK_SIZE; level /= ASSOC_ARRAY_KEY_CHUNK_SIZE;
switch (level) { switch (level) {
case 0: case 0:
return hash_key_type_and_desc(index_key); return index_key->hash;
case 1: case 1:
return index_key->x; return index_key->x;
case 2: case 2:
...@@ -280,8 +292,8 @@ static int keyring_diff_objects(const void *object, const void *data) ...@@ -280,8 +292,8 @@ static int keyring_diff_objects(const void *object, const void *data)
int level, i; int level, i;
level = 0; level = 0;
seg_a = hash_key_type_and_desc(a); seg_a = a->hash;
seg_b = hash_key_type_and_desc(b); seg_b = b->hash;
if ((seg_a ^ seg_b) != 0) if ((seg_a ^ seg_b) != 0)
goto differ; goto differ;
level += ASSOC_ARRAY_KEY_CHUNK_SIZE / 8; level += ASSOC_ARRAY_KEY_CHUNK_SIZE / 8;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment