@@ -24,25 +24,27 @@ static struct kmem_cache *hashtab_node_cachep __ro_after_init;
* The total memory used by the htable arrays (only) with Fedora policy loaded
* is approximately 163 KB at the time of writing.
*/
-static u32 hashtab_compute_size(u32 nel)
+static u32 hashtab_compute_hbits(u32 nel)
{
- return nel == 0 ? 0 : roundup_pow_of_two(nel);
+ if (nel <= 1)
+ return nel;
+ return ilog2(nel - 1) + 1;
}
int hashtab_init(struct hashtab *h, u32 nel_hint)
{
- u32 size = hashtab_compute_size(nel_hint);
+ u32 hbits = hashtab_compute_hbits(nel_hint);
/* should already be zeroed, but better be safe */
h->nel = 0;
- h->size = 0;
+ h->hbits = 0;
h->htable = NULL;
- if (size) {
- h->htable = kcalloc(size, sizeof(*h->htable), GFP_KERNEL);
+ if (hbits) {
+ h->htable = kcalloc(1 << hbits, sizeof(*h->htable), GFP_KERNEL);
if (!h->htable)
return -ENOMEM;
- h->size = size;
+ h->hbits = hbits;
}
return 0;
}
@@ -66,10 +68,11 @@ int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst,
void hashtab_destroy(struct hashtab *h)
{
- u32 i;
- struct hashtab_node *cur, *temp;
+ u32 size = hashtab_size(h);
+
+ for (u32 i = 0; i < size; i++) {
+ struct hashtab_node *cur, *temp;
- for (i = 0; i < h->size; i++) {
cur = h->htable[i];
while (cur) {
temp = cur;
@@ -81,20 +84,19 @@ void hashtab_destroy(struct hashtab *h)
kfree(h->htable);
h->htable = NULL;
+ h->hbits = 0;
}
int hashtab_map(struct hashtab *h,
int (*apply)(void *k, void *d, void *args),
void *args)
{
- u32 i;
- int ret;
- struct hashtab_node *cur;
+ u32 size = hashtab_size(h);
- for (i = 0; i < h->size; i++) {
- cur = h->htable[i];
+ for (u32 i = 0; i < size; i++) {
+ struct hashtab_node *cur = cur = h->htable[i];
while (cur) {
- ret = apply(cur->key, cur->datum, args);
+ int ret = apply(cur->key, cur->datum, args);
if (ret)
return ret;
cur = cur->next;
@@ -106,18 +108,18 @@ int hashtab_map(struct hashtab *h,
#ifdef CONFIG_SECURITY_SELINUX_DEBUG
void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
{
- u32 i, chain_len, slots_used, max_chain_len;
+ u32 size = hashtab_size(h);
+ u32 slots_used, max_chain_len;
u64 chain2_len_sum;
- struct hashtab_node *cur;
slots_used = 0;
max_chain_len = 0;
chain2_len_sum = 0;
- for (i = 0; i < h->size; i++) {
- cur = h->htable[i];
+ for (u32 i = 0; i < size; i++) {
+ struct hashtab_node *cur = h->htable[i];
if (cur) {
+ u32 chain_len = 0;
slots_used++;
- chain_len = 0;
while (cur) {
chain_len++;
cur = cur->next;
@@ -142,36 +144,35 @@ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
int (*destroy)(void *k, void *d, void *args),
void *args)
{
- struct hashtab_node *cur, *tmp, *tail;
- u32 i;
- int rc;
+ u32 size = hashtab_size(orig);
memset(new, 0, sizeof(*new));
- new->htable = kcalloc(orig->size, sizeof(*new->htable), GFP_KERNEL);
- if (!new->htable)
- return -ENOMEM;
+ if (size) {
+ new->htable = kcalloc(size, sizeof(*new->htable), GFP_KERNEL);
+ if (!new->htable)
+ return -ENOMEM;
+ new->hbits = orig->hbits;
+ }
- new->size = orig->size;
+ for (u32 i = 0; i < size; i++) {
+ struct hashtab_node *cur, **tailp;
+ tailp = new->htable + i;
- for (i = 0; i < orig->size; i++) {
- tail = NULL;
for (cur = orig->htable[i]; cur; cur = cur->next) {
+ struct hashtab_node *tmp;
+
tmp = kmem_cache_zalloc(hashtab_node_cachep,
GFP_KERNEL);
if (!tmp)
goto error;
- rc = copy(tmp, cur, args);
- if (rc) {
+ if (copy(tmp, cur, args)) {
kmem_cache_free(hashtab_node_cachep, tmp);
goto error;
}
tmp->next = NULL;
- if (!tail)
- new->htable[i] = tmp;
- else
- tail->next = tmp;
- tail = tmp;
+ *tailp = tmp;
+ tailp = &tmp->next;
new->nel++;
}
}
@@ -179,7 +180,8 @@ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
return 0;
error:
- for (i = 0; i < new->size; i++) {
+ for (u32 i = 0; i < size; i++) {
+ struct hashtab_node *cur, *tmp;
for (cur = new->htable[i]; cur; cur = tmp) {
tmp = cur->next;
destroy(cur->key, cur->datum, args);
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
+#include <linux/hash.h>
#define HASHTAB_MAX_NODES U32_MAX
@@ -31,7 +32,7 @@ struct hashtab_node {
struct hashtab {
struct hashtab_node **htable; /* hash table */
- u32 size; /* number of slots in hash table */
+ u32 hbits; /* number of slots in hash table */
u32 nel; /* number of elements in hash table */
};
@@ -41,6 +42,11 @@ struct hashtab_info {
u64 chain2_len_sum;
};
+static inline u32 hashtab_size(const struct hashtab *h)
+{
+ return h->hbits ? 1 << h->hbits : 0;
+}
+
/*
* Initializes a new hash table with the specified characteristics.
*
@@ -51,6 +57,12 @@ int hashtab_init(struct hashtab *h, u32 nel_hint);
int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst,
void *key, void *datum);
+static inline struct hashtab_node **hashtab_entry(struct hashtab *h,
+ const void *key, const struct hashtab_key_params key_params)
+{
+ return h->htable + hash_32(key_params.hash(key), h->hbits);
+}
+
/*
* Inserts the specified (key, datum) pair into the specified hash table.
*
@@ -60,32 +72,27 @@ int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst,
0 otherwise.
*/
static inline int hashtab_insert(struct hashtab *h, void *key, void *datum,
- struct hashtab_key_params key_params)
+ const struct hashtab_key_params key_params)
{
- u32 hvalue;
- struct hashtab_node *prev, *cur;
+ struct hashtab_node **pprev;
cond_resched();
- if (!h->size || h->nel == HASHTAB_MAX_NODES)
+ if (!h->hbits || h->nel == HASHTAB_MAX_NODES)
return -EINVAL;
- hvalue = key_params.hash(key) & (h->size - 1);
- prev = NULL;
- cur = h->htable[hvalue];
- while (cur) {
+ pprev = hashtab_entry(h, key, key_params);
+ for (struct hashtab_node *cur; (cur = *pprev) != NULL; ) {
int cmp = key_params.cmp(key, cur->key);
if (cmp == 0)
return -EEXIST;
if (cmp < 0)
break;
- prev = cur;
- cur = cur->next;
+ pprev = &cur->next;
}
- return __hashtab_insert(h, prev ? &prev->next : &h->htable[hvalue],
- key, datum);
+ return __hashtab_insert(h, pprev, key, datum);
}
/*
@@ -95,16 +102,14 @@ static inline int hashtab_insert(struct hashtab *h, void *key, void *datum,
* the datum of the entry otherwise.
*/
static inline void *hashtab_search(struct hashtab *h, const void *key,
- struct hashtab_key_params key_params)
+ const struct hashtab_key_params key_params)
{
- u32 hvalue;
struct hashtab_node *cur;
- if (!h->size)
+ if (!h->hbits)
return NULL;
- hvalue = key_params.hash(key) & (h->size - 1);
- cur = h->htable[hvalue];
+ cur = *hashtab_entry(h, key, key_params);
while (cur) {
int cmp = key_params.cmp(key, cur->key);
@@ -685,7 +685,7 @@ static void hash_eval(struct hashtab *h, const char *hash_name)
hashtab_stat(h, &info);
pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n",
- hash_name, h->nel, info.slots_used, h->size,
+ hash_name, h->nel, info.slots_used, hashtab_size(h),
info.max_chain_len, info.chain2_len_sum);
}
From: Linus Torvalds <torvalds@linux-foundation.org> This is an inline patch version of a patch submitted by Linus in the thread below. Do not merge this patch anywhere without additional testing or a proper commit message. * https://lore.kernel.org/selinux/20231111160954.45911-2-paul@paul-moore.com --- security/selinux/ss/hashtab.c | 78 +++++++++++++++++----------------- security/selinux/ss/hashtab.h | 41 ++++++++++-------- security/selinux/ss/policydb.c | 2 +- 3 files changed, 64 insertions(+), 57 deletions(-)