hashtab.c 4.4 KB

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