~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/selinux/ss/hashtab.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Implementation of the hash table type.
  4  *
  5  * Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
  6  */
  7 
  8 #include <linux/kernel.h>
  9 #include <linux/slab.h>
 10 #include <linux/errno.h>
 11 #include "hashtab.h"
 12 #include "security.h"
 13 
 14 static struct kmem_cache *hashtab_node_cachep __ro_after_init;
 15 
 16 /*
 17  * Here we simply round the number of elements up to the nearest power of two.
 18  * I tried also other options like rounding down or rounding to the closest
 19  * power of two (up or down based on which is closer), but I was unable to
 20  * find any significant difference in lookup/insert performance that would
 21  * justify switching to a different (less intuitive) formula. It could be that
 22  * a different formula is actually more optimal, but any future changes here
 23  * should be supported with performance/memory usage data.
 24  *
 25  * The total memory used by the htable arrays (only) with Fedora policy loaded
 26  * is approximately 163 KB at the time of writing.
 27  */
 28 static u32 hashtab_compute_size(u32 nel)
 29 {
 30         return nel == 0 ? 0 : roundup_pow_of_two(nel);
 31 }
 32 
 33 int hashtab_init(struct hashtab *h, u32 nel_hint)
 34 {
 35         u32 size = hashtab_compute_size(nel_hint);
 36 
 37         /* should already be zeroed, but better be safe */
 38         h->nel = 0;
 39         h->size = 0;
 40         h->htable = NULL;
 41 
 42         if (size) {
 43                 h->htable = kcalloc(size, sizeof(*h->htable), GFP_KERNEL);
 44                 if (!h->htable)
 45                         return -ENOMEM;
 46                 h->size = size;
 47         }
 48         return 0;
 49 }
 50 
 51 int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst, void *key,
 52                      void *datum)
 53 {
 54         struct hashtab_node *newnode;
 55 
 56         newnode = kmem_cache_zalloc(hashtab_node_cachep, GFP_KERNEL);
 57         if (!newnode)
 58                 return -ENOMEM;
 59         newnode->key = key;
 60         newnode->datum = datum;
 61         newnode->next = *dst;
 62         *dst = newnode;
 63 
 64         h->nel++;
 65         return 0;
 66 }
 67 
 68 void hashtab_destroy(struct hashtab *h)
 69 {
 70         u32 i;
 71         struct hashtab_node *cur, *temp;
 72 
 73         for (i = 0; i < h->size; i++) {
 74                 cur = h->htable[i];
 75                 while (cur) {
 76                         temp = cur;
 77                         cur = cur->next;
 78                         kmem_cache_free(hashtab_node_cachep, temp);
 79                 }
 80                 h->htable[i] = NULL;
 81         }
 82 
 83         kfree(h->htable);
 84         h->htable = NULL;
 85 }
 86 
 87 int hashtab_map(struct hashtab *h, int (*apply)(void *k, void *d, void *args),
 88                 void *args)
 89 {
 90         u32 i;
 91         int ret;
 92         struct hashtab_node *cur;
 93 
 94         for (i = 0; i < h->size; i++) {
 95                 cur = h->htable[i];
 96                 while (cur) {
 97                         ret = apply(cur->key, cur->datum, args);
 98                         if (ret)
 99                                 return ret;
100                         cur = cur->next;
101                 }
102         }
103         return 0;
104 }
105 
106 #ifdef CONFIG_SECURITY_SELINUX_DEBUG
107 void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
108 {
109         u32 i, chain_len, slots_used, max_chain_len;
110         u64 chain2_len_sum;
111         struct hashtab_node *cur;
112 
113         slots_used = 0;
114         max_chain_len = 0;
115         chain2_len_sum = 0;
116         for (i = 0; i < h->size; i++) {
117                 cur = h->htable[i];
118                 if (cur) {
119                         slots_used++;
120                         chain_len = 0;
121                         while (cur) {
122                                 chain_len++;
123                                 cur = cur->next;
124                         }
125 
126                         if (chain_len > max_chain_len)
127                                 max_chain_len = chain_len;
128 
129                         chain2_len_sum += (u64)chain_len * chain_len;
130                 }
131         }
132 
133         info->slots_used = slots_used;
134         info->max_chain_len = max_chain_len;
135         info->chain2_len_sum = chain2_len_sum;
136 }
137 #endif /* CONFIG_SECURITY_SELINUX_DEBUG */
138 
139 int hashtab_duplicate(struct hashtab *new, const struct hashtab *orig,
140                       int (*copy)(struct hashtab_node *new,
141                                   const struct hashtab_node *orig, void *args),
142                       int (*destroy)(void *k, void *d, void *args), void *args)
143 {
144         const struct hashtab_node *orig_cur;
145         struct hashtab_node *cur, *tmp, *tail;
146         u32 i;
147         int rc;
148 
149         memset(new, 0, sizeof(*new));
150 
151         new->htable = kcalloc(orig->size, sizeof(*new->htable), GFP_KERNEL);
152         if (!new->htable)
153                 return -ENOMEM;
154 
155         new->size = orig->size;
156 
157         for (i = 0; i < orig->size; i++) {
158                 tail = NULL;
159                 for (orig_cur = orig->htable[i]; orig_cur;
160                      orig_cur = orig_cur->next) {
161                         tmp = kmem_cache_zalloc(hashtab_node_cachep,
162                                                 GFP_KERNEL);
163                         if (!tmp)
164                                 goto error;
165                         rc = copy(tmp, orig_cur, args);
166                         if (rc) {
167                                 kmem_cache_free(hashtab_node_cachep, tmp);
168                                 goto error;
169                         }
170                         tmp->next = NULL;
171                         if (!tail)
172                                 new->htable[i] = tmp;
173                         else
174                                 tail->next = tmp;
175                         tail = tmp;
176                         new->nel++;
177                 }
178         }
179 
180         return 0;
181 
182 error:
183         for (i = 0; i < new->size; i++) {
184                 for (cur = new->htable[i]; cur; cur = tmp) {
185                         tmp = cur->next;
186                         destroy(cur->key, cur->datum, args);
187                         kmem_cache_free(hashtab_node_cachep, cur);
188                 }
189         }
190         kfree(new->htable);
191         memset(new, 0, sizeof(*new));
192         return -ENOMEM;
193 }
194 
195 void __init hashtab_cache_init(void)
196 {
197         hashtab_node_cachep = kmem_cache_create("hashtab_node",
198                                                 sizeof(struct hashtab_node), 0,
199                                                 SLAB_PANIC, NULL);
200 }
201 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php