xref: /openbmc/linux/security/selinux/ss/hashtab.c (revision 89d155ef)
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>
91da177e4SLinus Torvalds #include "hashtab.h"
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
121da177e4SLinus Torvalds                                int (*keycmp)(struct hashtab *h, void *key1, void *key2),
131da177e4SLinus Torvalds                                u32 size)
141da177e4SLinus Torvalds {
151da177e4SLinus Torvalds 	struct hashtab *p;
161da177e4SLinus Torvalds 	u32 i;
171da177e4SLinus Torvalds 
1889d155efSJames Morris 	p = kzalloc(sizeof(*p), GFP_KERNEL);
191da177e4SLinus Torvalds 	if (p == NULL)
201da177e4SLinus Torvalds 		return p;
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds 	p->size = size;
231da177e4SLinus Torvalds 	p->nel = 0;
241da177e4SLinus Torvalds 	p->hash_value = hash_value;
251da177e4SLinus Torvalds 	p->keycmp = keycmp;
261da177e4SLinus Torvalds 	p->htable = kmalloc(sizeof(*(p->htable)) * size, GFP_KERNEL);
271da177e4SLinus Torvalds 	if (p->htable == NULL) {
281da177e4SLinus Torvalds 		kfree(p);
291da177e4SLinus Torvalds 		return NULL;
301da177e4SLinus Torvalds 	}
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds 	for (i = 0; i < size; i++)
331da177e4SLinus Torvalds 		p->htable[i] = NULL;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds 	return p;
361da177e4SLinus Torvalds }
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds int hashtab_insert(struct hashtab *h, void *key, void *datum)
391da177e4SLinus Torvalds {
401da177e4SLinus Torvalds 	u32 hvalue;
411da177e4SLinus Torvalds 	struct hashtab_node *prev, *cur, *newnode;
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 	if (!h || h->nel == HASHTAB_MAX_NODES)
441da177e4SLinus Torvalds 		return -EINVAL;
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds 	hvalue = h->hash_value(h, key);
471da177e4SLinus Torvalds 	prev = NULL;
481da177e4SLinus Torvalds 	cur = h->htable[hvalue];
491da177e4SLinus Torvalds 	while (cur && h->keycmp(h, key, cur->key) > 0) {
501da177e4SLinus Torvalds 		prev = cur;
511da177e4SLinus Torvalds 		cur = cur->next;
521da177e4SLinus Torvalds 	}
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds 	if (cur && (h->keycmp(h, key, cur->key) == 0))
551da177e4SLinus Torvalds 		return -EEXIST;
561da177e4SLinus Torvalds 
5789d155efSJames Morris 	newnode = kzalloc(sizeof(*newnode), GFP_KERNEL);
581da177e4SLinus Torvalds 	if (newnode == NULL)
591da177e4SLinus Torvalds 		return -ENOMEM;
601da177e4SLinus Torvalds 	newnode->key = key;
611da177e4SLinus Torvalds 	newnode->datum = datum;
621da177e4SLinus Torvalds 	if (prev) {
631da177e4SLinus Torvalds 		newnode->next = prev->next;
641da177e4SLinus Torvalds 		prev->next = newnode;
651da177e4SLinus Torvalds 	} else {
661da177e4SLinus Torvalds 		newnode->next = h->htable[hvalue];
671da177e4SLinus Torvalds 		h->htable[hvalue] = newnode;
681da177e4SLinus Torvalds 	}
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	h->nel++;
711da177e4SLinus Torvalds 	return 0;
721da177e4SLinus Torvalds }
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds void *hashtab_search(struct hashtab *h, void *key)
751da177e4SLinus Torvalds {
761da177e4SLinus Torvalds 	u32 hvalue;
771da177e4SLinus Torvalds 	struct hashtab_node *cur;
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	if (!h)
801da177e4SLinus Torvalds 		return NULL;
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds 	hvalue = h->hash_value(h, key);
831da177e4SLinus Torvalds 	cur = h->htable[hvalue];
841da177e4SLinus Torvalds 	while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
851da177e4SLinus Torvalds 		cur = cur->next;
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
881da177e4SLinus Torvalds 		return NULL;
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds 	return cur->datum;
911da177e4SLinus Torvalds }
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds void hashtab_destroy(struct hashtab *h)
941da177e4SLinus Torvalds {
951da177e4SLinus Torvalds 	u32 i;
961da177e4SLinus Torvalds 	struct hashtab_node *cur, *temp;
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds 	if (!h)
991da177e4SLinus Torvalds 		return;
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 	for (i = 0; i < h->size; i++) {
1021da177e4SLinus Torvalds 		cur = h->htable[i];
1031da177e4SLinus Torvalds 		while (cur != NULL) {
1041da177e4SLinus Torvalds 			temp = cur;
1051da177e4SLinus Torvalds 			cur = cur->next;
1061da177e4SLinus Torvalds 			kfree(temp);
1071da177e4SLinus Torvalds 		}
1081da177e4SLinus Torvalds 		h->htable[i] = NULL;
1091da177e4SLinus Torvalds 	}
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds 	kfree(h->htable);
1121da177e4SLinus Torvalds 	h->htable = NULL;
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	kfree(h);
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds int hashtab_map(struct hashtab *h,
1181da177e4SLinus Torvalds 		int (*apply)(void *k, void *d, void *args),
1191da177e4SLinus Torvalds 		void *args)
1201da177e4SLinus Torvalds {
1211da177e4SLinus Torvalds 	u32 i;
1221da177e4SLinus Torvalds 	int ret;
1231da177e4SLinus Torvalds 	struct hashtab_node *cur;
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 	if (!h)
1261da177e4SLinus Torvalds 		return 0;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 	for (i = 0; i < h->size; i++) {
1291da177e4SLinus Torvalds 		cur = h->htable[i];
1301da177e4SLinus Torvalds 		while (cur != NULL) {
1311da177e4SLinus Torvalds 			ret = apply(cur->key, cur->datum, args);
1321da177e4SLinus Torvalds 			if (ret)
1331da177e4SLinus Torvalds 				return ret;
1341da177e4SLinus Torvalds 			cur = cur->next;
1351da177e4SLinus Torvalds 		}
1361da177e4SLinus Torvalds 	}
1371da177e4SLinus Torvalds 	return 0;
1381da177e4SLinus Torvalds }
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
1421da177e4SLinus Torvalds {
1431da177e4SLinus Torvalds 	u32 i, chain_len, slots_used, max_chain_len;
1441da177e4SLinus Torvalds 	struct hashtab_node *cur;
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds 	slots_used = 0;
1471da177e4SLinus Torvalds 	max_chain_len = 0;
1481da177e4SLinus Torvalds 	for (slots_used = max_chain_len = i = 0; i < h->size; i++) {
1491da177e4SLinus Torvalds 		cur = h->htable[i];
1501da177e4SLinus Torvalds 		if (cur) {
1511da177e4SLinus Torvalds 			slots_used++;
1521da177e4SLinus Torvalds 			chain_len = 0;
1531da177e4SLinus Torvalds 			while (cur) {
1541da177e4SLinus Torvalds 				chain_len++;
1551da177e4SLinus Torvalds 				cur = cur->next;
1561da177e4SLinus Torvalds 			}
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds 			if (chain_len > max_chain_len)
1591da177e4SLinus Torvalds 				max_chain_len = chain_len;
1601da177e4SLinus Torvalds 		}
1611da177e4SLinus Torvalds 	}
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	info->slots_used = slots_used;
1641da177e4SLinus Torvalds 	info->max_chain_len = max_chain_len;
1651da177e4SLinus Torvalds }
166