xref: /openbmc/linux/security/selinux/ss/hashtab.c (revision dbc74c65)
1 /*
2  * Implementation of the hash table type.
3  *
4  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5  */
6 #include <linux/kernel.h>
7 #include <linux/slab.h>
8 #include <linux/errno.h>
9 #include "hashtab.h"
10 
11 struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
12 			       int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
13 			       u32 size)
14 {
15 	struct hashtab *p;
16 	u32 i;
17 
18 	p = kzalloc(sizeof(*p), GFP_KERNEL);
19 	if (p == NULL)
20 		return p;
21 
22 	p->size = size;
23 	p->nel = 0;
24 	p->hash_value = hash_value;
25 	p->keycmp = keycmp;
26 	p->htable = kmalloc(sizeof(*(p->htable)) * size, GFP_KERNEL);
27 	if (p->htable == NULL) {
28 		kfree(p);
29 		return NULL;
30 	}
31 
32 	for (i = 0; i < size; i++)
33 		p->htable[i] = NULL;
34 
35 	return p;
36 }
37 
38 int hashtab_insert(struct hashtab *h, void *key, void *datum)
39 {
40 	u32 hvalue;
41 	struct hashtab_node *prev, *cur, *newnode;
42 
43 	if (!h || h->nel == HASHTAB_MAX_NODES)
44 		return -EINVAL;
45 
46 	hvalue = h->hash_value(h, key);
47 	prev = NULL;
48 	cur = h->htable[hvalue];
49 	while (cur && h->keycmp(h, key, cur->key) > 0) {
50 		prev = cur;
51 		cur = cur->next;
52 	}
53 
54 	if (cur && (h->keycmp(h, key, cur->key) == 0))
55 		return -EEXIST;
56 
57 	newnode = kzalloc(sizeof(*newnode), GFP_KERNEL);
58 	if (newnode == NULL)
59 		return -ENOMEM;
60 	newnode->key = key;
61 	newnode->datum = datum;
62 	if (prev) {
63 		newnode->next = prev->next;
64 		prev->next = newnode;
65 	} else {
66 		newnode->next = h->htable[hvalue];
67 		h->htable[hvalue] = newnode;
68 	}
69 
70 	h->nel++;
71 	return 0;
72 }
73 
74 void *hashtab_search(struct hashtab *h, const void *key)
75 {
76 	u32 hvalue;
77 	struct hashtab_node *cur;
78 
79 	if (!h)
80 		return NULL;
81 
82 	hvalue = h->hash_value(h, key);
83 	cur = h->htable[hvalue];
84 	while (cur && h->keycmp(h, key, cur->key) > 0)
85 		cur = cur->next;
86 
87 	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
88 		return NULL;
89 
90 	return cur->datum;
91 }
92 
93 void hashtab_destroy(struct hashtab *h)
94 {
95 	u32 i;
96 	struct hashtab_node *cur, *temp;
97 
98 	if (!h)
99 		return;
100 
101 	for (i = 0; i < h->size; i++) {
102 		cur = h->htable[i];
103 		while (cur) {
104 			temp = cur;
105 			cur = cur->next;
106 			kfree(temp);
107 		}
108 		h->htable[i] = NULL;
109 	}
110 
111 	kfree(h->htable);
112 	h->htable = NULL;
113 
114 	kfree(h);
115 }
116 
117 int hashtab_map(struct hashtab *h,
118 		int (*apply)(void *k, void *d, void *args),
119 		void *args)
120 {
121 	u32 i;
122 	int ret;
123 	struct hashtab_node *cur;
124 
125 	if (!h)
126 		return 0;
127 
128 	for (i = 0; i < h->size; i++) {
129 		cur = h->htable[i];
130 		while (cur) {
131 			ret = apply(cur->key, cur->datum, args);
132 			if (ret)
133 				return ret;
134 			cur = cur->next;
135 		}
136 	}
137 	return 0;
138 }
139 
140 
141 void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
142 {
143 	u32 i, chain_len, slots_used, max_chain_len;
144 	struct hashtab_node *cur;
145 
146 	slots_used = 0;
147 	max_chain_len = 0;
148 	for (slots_used = max_chain_len = i = 0; i < h->size; i++) {
149 		cur = h->htable[i];
150 		if (cur) {
151 			slots_used++;
152 			chain_len = 0;
153 			while (cur) {
154 				chain_len++;
155 				cur = cur->next;
156 			}
157 
158 			if (chain_len > max_chain_len)
159 				max_chain_len = chain_len;
160 		}
161 	}
162 
163 	info->slots_used = slots_used;
164 	info->max_chain_len = max_chain_len;
165 }
166