0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/slab.h>
0009 #include <linux/errno.h>
0010 #include "hashtab.h"
0011 #include "security.h"
0012
0013 static struct kmem_cache *hashtab_node_cachep __ro_after_init;
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 static u32 hashtab_compute_size(u32 nel)
0028 {
0029 return nel == 0 ? 0 : roundup_pow_of_two(nel);
0030 }
0031
0032 int hashtab_init(struct hashtab *h, u32 nel_hint)
0033 {
0034 u32 size = hashtab_compute_size(nel_hint);
0035
0036
0037 h->nel = 0;
0038 h->size = 0;
0039 h->htable = NULL;
0040
0041 if (size) {
0042 h->htable = kcalloc(size, sizeof(*h->htable), GFP_KERNEL);
0043 if (!h->htable)
0044 return -ENOMEM;
0045 h->size = size;
0046 }
0047 return 0;
0048 }
0049
0050 int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst,
0051 void *key, void *datum)
0052 {
0053 struct hashtab_node *newnode;
0054
0055 newnode = kmem_cache_zalloc(hashtab_node_cachep, GFP_KERNEL);
0056 if (!newnode)
0057 return -ENOMEM;
0058 newnode->key = key;
0059 newnode->datum = datum;
0060 newnode->next = *dst;
0061 *dst = newnode;
0062
0063 h->nel++;
0064 return 0;
0065 }
0066
0067 void hashtab_destroy(struct hashtab *h)
0068 {
0069 u32 i;
0070 struct hashtab_node *cur, *temp;
0071
0072 for (i = 0; i < h->size; i++) {
0073 cur = h->htable[i];
0074 while (cur) {
0075 temp = cur;
0076 cur = cur->next;
0077 kmem_cache_free(hashtab_node_cachep, temp);
0078 }
0079 h->htable[i] = NULL;
0080 }
0081
0082 kfree(h->htable);
0083 h->htable = NULL;
0084 }
0085
0086 int hashtab_map(struct hashtab *h,
0087 int (*apply)(void *k, void *d, void *args),
0088 void *args)
0089 {
0090 u32 i;
0091 int ret;
0092 struct hashtab_node *cur;
0093
0094 for (i = 0; i < h->size; i++) {
0095 cur = h->htable[i];
0096 while (cur) {
0097 ret = apply(cur->key, cur->datum, args);
0098 if (ret)
0099 return ret;
0100 cur = cur->next;
0101 }
0102 }
0103 return 0;
0104 }
0105
0106
0107 void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
0108 {
0109 u32 i, chain_len, slots_used, max_chain_len;
0110 struct hashtab_node *cur;
0111
0112 slots_used = 0;
0113 max_chain_len = 0;
0114 for (i = 0; i < h->size; i++) {
0115 cur = h->htable[i];
0116 if (cur) {
0117 slots_used++;
0118 chain_len = 0;
0119 while (cur) {
0120 chain_len++;
0121 cur = cur->next;
0122 }
0123
0124 if (chain_len > max_chain_len)
0125 max_chain_len = chain_len;
0126 }
0127 }
0128
0129 info->slots_used = slots_used;
0130 info->max_chain_len = max_chain_len;
0131 }
0132
0133 int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
0134 int (*copy)(struct hashtab_node *new,
0135 struct hashtab_node *orig, void *args),
0136 int (*destroy)(void *k, void *d, void *args),
0137 void *args)
0138 {
0139 struct hashtab_node *cur, *tmp, *tail;
0140 int i, rc;
0141
0142 memset(new, 0, sizeof(*new));
0143
0144 new->htable = kcalloc(orig->size, sizeof(*new->htable), GFP_KERNEL);
0145 if (!new->htable)
0146 return -ENOMEM;
0147
0148 new->size = orig->size;
0149
0150 for (i = 0; i < orig->size; i++) {
0151 tail = NULL;
0152 for (cur = orig->htable[i]; cur; cur = cur->next) {
0153 tmp = kmem_cache_zalloc(hashtab_node_cachep,
0154 GFP_KERNEL);
0155 if (!tmp)
0156 goto error;
0157 rc = copy(tmp, cur, args);
0158 if (rc) {
0159 kmem_cache_free(hashtab_node_cachep, tmp);
0160 goto error;
0161 }
0162 tmp->next = NULL;
0163 if (!tail)
0164 new->htable[i] = tmp;
0165 else
0166 tail->next = tmp;
0167 tail = tmp;
0168 new->nel++;
0169 }
0170 }
0171
0172 return 0;
0173
0174 error:
0175 for (i = 0; i < new->size; i++) {
0176 for (cur = new->htable[i]; cur; cur = tmp) {
0177 tmp = cur->next;
0178 destroy(cur->key, cur->datum, args);
0179 kmem_cache_free(hashtab_node_cachep, cur);
0180 }
0181 }
0182 kfree(new->htable);
0183 memset(new, 0, sizeof(*new));
0184 return -ENOMEM;
0185 }
0186
0187 void __init hashtab_cache_init(void)
0188 {
0189 hashtab_node_cachep = kmem_cache_create("hashtab_node",
0190 sizeof(struct hashtab_node),
0191 0, SLAB_PANIC, NULL);
0192 }