xref: /openbmc/linux/security/selinux/ss/hashtab.c (revision ed1c9642)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Implementation of the hash table type.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds #include <linux/kernel.h>
71da177e4SLinus Torvalds #include <linux/slab.h>
81da177e4SLinus Torvalds #include <linux/errno.h>
9ed1c9642SDave Jones #include <linux/sched.h>
101da177e4SLinus Torvalds #include "hashtab.h"
111da177e4SLinus Torvalds 
12bb242497SChad Sellers struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
13bb242497SChad Sellers 			       int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
141da177e4SLinus Torvalds 			       u32 size)
151da177e4SLinus Torvalds {
161da177e4SLinus Torvalds 	struct hashtab *p;
171da177e4SLinus Torvalds 	u32 i;
181da177e4SLinus Torvalds 
1989d155efSJames Morris 	p = kzalloc(sizeof(*p), GFP_KERNEL);
201da177e4SLinus Torvalds 	if (p == NULL)
211da177e4SLinus Torvalds 		return p;
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds 	p->size = size;
241da177e4SLinus Torvalds 	p->nel = 0;
251da177e4SLinus Torvalds 	p->hash_value = hash_value;
261da177e4SLinus Torvalds 	p->keycmp = keycmp;
271da177e4SLinus Torvalds 	p->htable = kmalloc(sizeof(*(p->htable)) * size, GFP_KERNEL);
281da177e4SLinus Torvalds 	if (p->htable == NULL) {
291da177e4SLinus Torvalds 		kfree(p);
301da177e4SLinus Torvalds 		return NULL;
311da177e4SLinus Torvalds 	}
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds 	for (i = 0; i < size; i++)
341da177e4SLinus Torvalds 		p->htable[i] = NULL;
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds 	return p;
371da177e4SLinus Torvalds }
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds int hashtab_insert(struct hashtab *h, void *key, void *datum)
401da177e4SLinus Torvalds {
411da177e4SLinus Torvalds 	u32 hvalue;
421da177e4SLinus Torvalds 	struct hashtab_node *prev, *cur, *newnode;
431da177e4SLinus Torvalds 
44ed1c9642SDave Jones 	cond_resched();
45ed1c9642SDave Jones 
461da177e4SLinus Torvalds 	if (!h || h->nel == HASHTAB_MAX_NODES)
471da177e4SLinus Torvalds 		return -EINVAL;
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds 	hvalue = h->hash_value(h, key);
501da177e4SLinus Torvalds 	prev = NULL;
511da177e4SLinus Torvalds 	cur = h->htable[hvalue];
521da177e4SLinus Torvalds 	while (cur && h->keycmp(h, key, cur->key) > 0) {
531da177e4SLinus Torvalds 		prev = cur;
541da177e4SLinus Torvalds 		cur = cur->next;
551da177e4SLinus Torvalds 	}
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds 	if (cur && (h->keycmp(h, key, cur->key) == 0))
581da177e4SLinus Torvalds 		return -EEXIST;
591da177e4SLinus Torvalds 
6089d155efSJames Morris 	newnode = kzalloc(sizeof(*newnode), GFP_KERNEL);
611da177e4SLinus Torvalds 	if (newnode == NULL)
621da177e4SLinus Torvalds 		return -ENOMEM;
631da177e4SLinus Torvalds 	newnode->key = key;
641da177e4SLinus Torvalds 	newnode->datum = datum;
651da177e4SLinus Torvalds 	if (prev) {
661da177e4SLinus Torvalds 		newnode->next = prev->next;
671da177e4SLinus Torvalds 		prev->next = newnode;
681da177e4SLinus Torvalds 	} else {
691da177e4SLinus Torvalds 		newnode->next = h->htable[hvalue];
701da177e4SLinus Torvalds 		h->htable[hvalue] = newnode;
711da177e4SLinus Torvalds 	}
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 	h->nel++;
741da177e4SLinus Torvalds 	return 0;
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds 
77bb242497SChad Sellers void *hashtab_search(struct hashtab *h, const void *key)
781da177e4SLinus Torvalds {
791da177e4SLinus Torvalds 	u32 hvalue;
801da177e4SLinus Torvalds 	struct hashtab_node *cur;
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds 	if (!h)
831da177e4SLinus Torvalds 		return NULL;
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds 	hvalue = h->hash_value(h, key);
861da177e4SLinus Torvalds 	cur = h->htable[hvalue];
87dbc74c65SVesa-Matti Kari 	while (cur && h->keycmp(h, key, cur->key) > 0)
881da177e4SLinus Torvalds 		cur = cur->next;
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds 	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
911da177e4SLinus Torvalds 		return NULL;
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 	return cur->datum;
941da177e4SLinus Torvalds }
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds void hashtab_destroy(struct hashtab *h)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds 	u32 i;
991da177e4SLinus Torvalds 	struct hashtab_node *cur, *temp;
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 	if (!h)
1021da177e4SLinus Torvalds 		return;
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 	for (i = 0; i < h->size; i++) {
1051da177e4SLinus Torvalds 		cur = h->htable[i];
106dbc74c65SVesa-Matti Kari 		while (cur) {
1071da177e4SLinus Torvalds 			temp = cur;
1081da177e4SLinus Torvalds 			cur = cur->next;
1091da177e4SLinus Torvalds 			kfree(temp);
1101da177e4SLinus Torvalds 		}
1111da177e4SLinus Torvalds 		h->htable[i] = NULL;
1121da177e4SLinus Torvalds 	}
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	kfree(h->htable);
1151da177e4SLinus Torvalds 	h->htable = NULL;
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds 	kfree(h);
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds int hashtab_map(struct hashtab *h,
1211da177e4SLinus Torvalds 		int (*apply)(void *k, void *d, void *args),
1221da177e4SLinus Torvalds 		void *args)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds 	u32 i;
1251da177e4SLinus Torvalds 	int ret;
1261da177e4SLinus Torvalds 	struct hashtab_node *cur;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 	if (!h)
1291da177e4SLinus Torvalds 		return 0;
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 	for (i = 0; i < h->size; i++) {
1321da177e4SLinus Torvalds 		cur = h->htable[i];
133dbc74c65SVesa-Matti Kari 		while (cur) {
1341da177e4SLinus Torvalds 			ret = apply(cur->key, cur->datum, args);
1351da177e4SLinus Torvalds 			if (ret)
1361da177e4SLinus Torvalds 				return ret;
1371da177e4SLinus Torvalds 			cur = cur->next;
1381da177e4SLinus Torvalds 		}
1391da177e4SLinus Torvalds 	}
1401da177e4SLinus Torvalds 	return 0;
1411da177e4SLinus Torvalds }
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
1451da177e4SLinus Torvalds {
1461da177e4SLinus Torvalds 	u32 i, chain_len, slots_used, max_chain_len;
1471da177e4SLinus Torvalds 	struct hashtab_node *cur;
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds 	slots_used = 0;
1501da177e4SLinus Torvalds 	max_chain_len = 0;
1511da177e4SLinus Torvalds 	for (slots_used = max_chain_len = i = 0; i < h->size; i++) {
1521da177e4SLinus Torvalds 		cur = h->htable[i];
1531da177e4SLinus Torvalds 		if (cur) {
1541da177e4SLinus Torvalds 			slots_used++;
1551da177e4SLinus Torvalds 			chain_len = 0;
1561da177e4SLinus Torvalds 			while (cur) {
1571da177e4SLinus Torvalds 				chain_len++;
1581da177e4SLinus Torvalds 				cur = cur->next;
1591da177e4SLinus Torvalds 			}
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 			if (chain_len > max_chain_len)
1621da177e4SLinus Torvalds 				max_chain_len = chain_len;
1631da177e4SLinus Torvalds 		}
1641da177e4SLinus Torvalds 	}
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	info->slots_used = slots_used;
1671da177e4SLinus Torvalds 	info->max_chain_len = max_chain_len;
1681da177e4SLinus Torvalds }
169