Skip to content

Commit 355ef8e

Browse files
committed
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: David Howells <[email protected]>
1 parent f771fde commit 355ef8e

File tree

4 files changed

+25
-16
lines changed

4 files changed

+25
-16
lines changed

include/linux/key.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ struct keyring_list;
8686
struct keyring_name;
8787

8888
struct keyring_index_key {
89+
/* [!] If this structure is altered, the union in struct key must change too! */
90+
unsigned long hash; /* Hash value */
8991
union {
9092
struct {
9193
#ifdef __LITTLE_ENDIAN /* Put desc_len at the LSB of x */
@@ -213,6 +215,7 @@ struct key {
213215
union {
214216
struct keyring_index_key index_key;
215217
struct {
218+
unsigned long hash;
216219
unsigned long len_desc;
217220
struct key_type *type; /* type of key */
218221
char *description;

security/keys/internal.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,7 @@ extern spinlock_t key_serial_lock;
8989
extern struct mutex key_construction_mutex;
9090
extern wait_queue_head_t request_key_conswq;
9191

92-
93-
static inline void key_set_index_key(struct keyring_index_key *index_key)
94-
{
95-
size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc));
96-
memcpy(index_key->desc, index_key->description, n);
97-
}
98-
92+
extern void key_set_index_key(struct keyring_index_key *index_key);
9993
extern struct key_type *key_type_lookup(const char *type);
10094
extern void key_type_put(struct key_type *ktype);
10195

security/keys/key.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,12 +285,12 @@ struct key *key_alloc(struct key_type *type, const char *desc,
285285
key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL);
286286
if (!key->index_key.description)
287287
goto no_memory_3;
288+
key->index_key.type = type;
288289
key_set_index_key(&key->index_key);
289290

290291
refcount_set(&key->usage, 1);
291292
init_rwsem(&key->sem);
292293
lockdep_set_class(&key->sem, &type->lock_class);
293-
key->index_key.type = type;
294294
key->user = user;
295295
key->quotalen = quotalen;
296296
key->datalen = type->def_datalen;

security/keys/keyring.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ static u64 mult_64x32_and_fold(u64 x, u32 y)
168168
/*
169169
* Hash a key type and description.
170170
*/
171-
static unsigned long hash_key_type_and_desc(const struct keyring_index_key *index_key)
171+
static void hash_key_type_and_desc(struct keyring_index_key *index_key)
172172
{
173173
const unsigned level_shift = ASSOC_ARRAY_LEVEL_STEP;
174174
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
206206
* zero for keyrings and non-zero otherwise.
207207
*/
208208
if (index_key->type != &key_type_keyring && (hash & fan_mask) == 0)
209-
return hash | (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1;
210-
if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0)
211-
return (hash + (hash << level_shift)) & ~fan_mask;
212-
return hash;
209+
hash |= (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1;
210+
else if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0)
211+
hash = (hash + (hash << level_shift)) & ~fan_mask;
212+
index_key->hash = hash;
213+
}
214+
215+
/*
216+
* Finalise an index key to include a part of the description actually in the
217+
* index key and to add in the hash too.
218+
*/
219+
void key_set_index_key(struct keyring_index_key *index_key)
220+
{
221+
size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc));
222+
memcpy(index_key->desc, index_key->description, n);
223+
224+
hash_key_type_and_desc(index_key);
213225
}
214226

215227
/*
@@ -227,7 +239,7 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)
227239
level /= ASSOC_ARRAY_KEY_CHUNK_SIZE;
228240
switch (level) {
229241
case 0:
230-
return hash_key_type_and_desc(index_key);
242+
return index_key->hash;
231243
case 1:
232244
return index_key->x;
233245
case 2:
@@ -280,8 +292,8 @@ static int keyring_diff_objects(const void *object, const void *data)
280292
int level, i;
281293

282294
level = 0;
283-
seg_a = hash_key_type_and_desc(a);
284-
seg_b = hash_key_type_and_desc(b);
295+
seg_a = a->hash;
296+
seg_b = b->hash;
285297
if ((seg_a ^ seg_b) != 0)
286298
goto differ;
287299
level += ASSOC_ARRAY_KEY_CHUNK_SIZE / 8;

0 commit comments

Comments
 (0)