hashtab.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Implementation of the hash table type.
  4. *
  5. * Author : Stephen Smalley, <[email protected]>
  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,
  45. void *key, 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,
  75. int (*apply)(void *k, void *d, void *args),
  76. void *args)
  77. {
  78. u32 i;
  79. int ret;
  80. struct hashtab_node *cur;
  81. for (i = 0; i < h->size; i++) {
  82. cur = h->htable[i];
  83. while (cur) {
  84. ret = apply(cur->key, cur->datum, args);
  85. if (ret)
  86. return ret;
  87. cur = cur->next;
  88. }
  89. }
  90. return 0;
  91. }
  92. void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
  93. {
  94. u32 i, chain_len, slots_used, max_chain_len;
  95. struct hashtab_node *cur;
  96. slots_used = 0;
  97. max_chain_len = 0;
  98. for (i = 0; i < h->size; i++) {
  99. cur = h->htable[i];
  100. if (cur) {
  101. slots_used++;
  102. chain_len = 0;
  103. while (cur) {
  104. chain_len++;
  105. cur = cur->next;
  106. }
  107. if (chain_len > max_chain_len)
  108. max_chain_len = chain_len;
  109. }
  110. }
  111. info->slots_used = slots_used;
  112. info->max_chain_len = max_chain_len;
  113. }
  114. int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
  115. int (*copy)(struct hashtab_node *new,
  116. struct hashtab_node *orig, void *args),
  117. int (*destroy)(void *k, void *d, void *args),
  118. void *args)
  119. {
  120. struct hashtab_node *cur, *tmp, *tail;
  121. int i, rc;
  122. memset(new, 0, sizeof(*new));
  123. new->htable = kcalloc(orig->size, sizeof(*new->htable), GFP_KERNEL);
  124. if (!new->htable)
  125. return -ENOMEM;
  126. new->size = orig->size;
  127. for (i = 0; i < orig->size; i++) {
  128. tail = NULL;
  129. for (cur = orig->htable[i]; cur; cur = cur->next) {
  130. tmp = kmem_cache_zalloc(hashtab_node_cachep,
  131. GFP_KERNEL);
  132. if (!tmp)
  133. goto error;
  134. rc = copy(tmp, cur, args);
  135. if (rc) {
  136. kmem_cache_free(hashtab_node_cachep, tmp);
  137. goto error;
  138. }
  139. tmp->next = NULL;
  140. if (!tail)
  141. new->htable[i] = tmp;
  142. else
  143. tail->next = tmp;
  144. tail = tmp;
  145. new->nel++;
  146. }
  147. }
  148. return 0;
  149. error:
  150. for (i = 0; i < new->size; i++) {
  151. for (cur = new->htable[i]; cur; cur = tmp) {
  152. tmp = cur->next;
  153. destroy(cur->key, cur->datum, args);
  154. kmem_cache_free(hashtab_node_cachep, cur);
  155. }
  156. }
  157. kfree(new->htable);
  158. memset(new, 0, sizeof(*new));
  159. return -ENOMEM;
  160. }
  161. void __init hashtab_cache_init(void)
  162. {
  163. hashtab_node_cachep = kmem_cache_create("hashtab_node",
  164. sizeof(struct hashtab_node),
  165. 0, SLAB_PANIC, NULL);
  166. }