1 // SPDX-License-Identifier: GPL-2.0
3 * Implementation of the hash table type.
5 * Author : Stephen Smalley, <sds@tycho.nsa.gov>
7 #include <linux/kernel.h>
8 #include <linux/slab.h>
9 #include <linux/errno.h>
10 #include <linux/sched.h>
13 static struct kmem_cache
*hashtab_node_cachep
;
16 * Here we simply round the number of elements up to the nearest power of two.
17 * I tried also other options like rouding down or rounding to the closest
18 * power of two (up or down based on which is closer), but I was unable to
19 * find any significant difference in lookup/insert performance that would
20 * justify switching to a different (less intuitive) formula. It could be that
21 * a different formula is actually more optimal, but any future changes here
22 * should be supported with performance/memory usage data.
24 * The total memory used by the htable arrays (only) with Fedora policy loaded
25 * is approximately 163 KB at the time of writing.
27 static u32
hashtab_compute_size(u32 nel
)
29 return nel
== 0 ? 0 : roundup_pow_of_two(nel
);
32 struct hashtab
*hashtab_create(u32 (*hash_value
)(struct hashtab
*h
, const void *key
),
33 int (*keycmp
)(struct hashtab
*h
, const void *key1
, const void *key2
),
37 u32 i
, size
= hashtab_compute_size(nel_hint
);
39 p
= kzalloc(sizeof(*p
), GFP_KERNEL
);
45 p
->hash_value
= hash_value
;
50 p
->htable
= kmalloc_array(size
, sizeof(*p
->htable
), GFP_KERNEL
);
56 for (i
= 0; i
< size
; i
++)
62 int hashtab_insert(struct hashtab
*h
, void *key
, void *datum
)
65 struct hashtab_node
*prev
, *cur
, *newnode
;
69 if (!h
|| !h
->size
|| h
->nel
== HASHTAB_MAX_NODES
)
72 hvalue
= h
->hash_value(h
, key
);
74 cur
= h
->htable
[hvalue
];
75 while (cur
&& h
->keycmp(h
, key
, cur
->key
) > 0) {
80 if (cur
&& (h
->keycmp(h
, key
, cur
->key
) == 0))
83 newnode
= kmem_cache_zalloc(hashtab_node_cachep
, GFP_KERNEL
);
87 newnode
->datum
= datum
;
89 newnode
->next
= prev
->next
;
92 newnode
->next
= h
->htable
[hvalue
];
93 h
->htable
[hvalue
] = newnode
;
100 void *hashtab_search(struct hashtab
*h
, const void *key
)
103 struct hashtab_node
*cur
;
108 hvalue
= h
->hash_value(h
, key
);
109 cur
= h
->htable
[hvalue
];
110 while (cur
&& h
->keycmp(h
, key
, cur
->key
) > 0)
113 if (!cur
|| (h
->keycmp(h
, key
, cur
->key
) != 0))
119 void hashtab_destroy(struct hashtab
*h
)
122 struct hashtab_node
*cur
, *temp
;
127 for (i
= 0; i
< h
->size
; i
++) {
132 kmem_cache_free(hashtab_node_cachep
, temp
);
143 int hashtab_map(struct hashtab
*h
,
144 int (*apply
)(void *k
, void *d
, void *args
),
149 struct hashtab_node
*cur
;
154 for (i
= 0; i
< h
->size
; i
++) {
157 ret
= apply(cur
->key
, cur
->datum
, args
);
167 void hashtab_stat(struct hashtab
*h
, struct hashtab_info
*info
)
169 u32 i
, chain_len
, slots_used
, max_chain_len
;
170 struct hashtab_node
*cur
;
174 for (i
= 0; i
< h
->size
; i
++) {
184 if (chain_len
> max_chain_len
)
185 max_chain_len
= chain_len
;
189 info
->slots_used
= slots_used
;
190 info
->max_chain_len
= max_chain_len
;
193 void __init
hashtab_cache_init(void)
195 hashtab_node_cachep
= kmem_cache_create("hashtab_node",
196 sizeof(struct hashtab_node
),
197 0, SLAB_PANIC
, NULL
);