test_static_keys.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * Kernel module for testing static keys.
  3. *
  4. * Copyright 2015 Akamai Technologies Inc. All Rights Reserved
  5. *
  6. * Authors:
  7. * Jason Baron <jbaron@akamai.com>
  8. *
  9. * This software is licensed under the terms of the GNU General Public
  10. * License version 2, as published by the Free Software Foundation, and
  11. * may be copied, distributed, and modified under those terms.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. */
  18. #include <linux/module.h>
  19. #include <linux/jump_label.h>
  20. /* old keys */
  21. struct static_key old_true_key = STATIC_KEY_INIT_TRUE;
  22. struct static_key old_false_key = STATIC_KEY_INIT_FALSE;
  23. /* new api */
  24. DEFINE_STATIC_KEY_TRUE(true_key);
  25. DEFINE_STATIC_KEY_FALSE(false_key);
  26. /* external */
  27. extern struct static_key base_old_true_key;
  28. extern struct static_key base_inv_old_true_key;
  29. extern struct static_key base_old_false_key;
  30. extern struct static_key base_inv_old_false_key;
  31. /* new api */
  32. extern struct static_key_true base_true_key;
  33. extern struct static_key_true base_inv_true_key;
  34. extern struct static_key_false base_false_key;
  35. extern struct static_key_false base_inv_false_key;
  36. struct test_key {
  37. bool init_state;
  38. struct static_key *key;
  39. bool (*test_key)(void);
  40. };
  41. #define test_key_func(key, branch) \
  42. ({bool func(void) { return branch(key); } func; })
  43. static void invert_key(struct static_key *key)
  44. {
  45. if (static_key_enabled(key))
  46. static_key_disable(key);
  47. else
  48. static_key_enable(key);
  49. }
  50. static void invert_keys(struct test_key *keys, int size)
  51. {
  52. struct static_key *previous = NULL;
  53. int i;
  54. for (i = 0; i < size; i++) {
  55. if (previous != keys[i].key) {
  56. invert_key(keys[i].key);
  57. previous = keys[i].key;
  58. }
  59. }
  60. }
  61. static int verify_keys(struct test_key *keys, int size, bool invert)
  62. {
  63. int i;
  64. bool ret, init;
  65. for (i = 0; i < size; i++) {
  66. ret = static_key_enabled(keys[i].key);
  67. init = keys[i].init_state;
  68. if (ret != (invert ? !init : init))
  69. return -EINVAL;
  70. ret = keys[i].test_key();
  71. if (static_key_enabled(keys[i].key)) {
  72. if (!ret)
  73. return -EINVAL;
  74. } else {
  75. if (ret)
  76. return -EINVAL;
  77. }
  78. }
  79. return 0;
  80. }
  81. static int __init test_static_key_init(void)
  82. {
  83. int ret;
  84. int size;
  85. struct test_key static_key_tests[] = {
  86. /* internal keys - old keys */
  87. {
  88. .init_state = true,
  89. .key = &old_true_key,
  90. .test_key = test_key_func(&old_true_key, static_key_true),
  91. },
  92. {
  93. .init_state = false,
  94. .key = &old_false_key,
  95. .test_key = test_key_func(&old_false_key, static_key_false),
  96. },
  97. /* internal keys - new keys */
  98. {
  99. .init_state = true,
  100. .key = &true_key.key,
  101. .test_key = test_key_func(&true_key, static_branch_likely),
  102. },
  103. {
  104. .init_state = true,
  105. .key = &true_key.key,
  106. .test_key = test_key_func(&true_key, static_branch_unlikely),
  107. },
  108. {
  109. .init_state = false,
  110. .key = &false_key.key,
  111. .test_key = test_key_func(&false_key, static_branch_likely),
  112. },
  113. {
  114. .init_state = false,
  115. .key = &false_key.key,
  116. .test_key = test_key_func(&false_key, static_branch_unlikely),
  117. },
  118. /* external keys - old keys */
  119. {
  120. .init_state = true,
  121. .key = &base_old_true_key,
  122. .test_key = test_key_func(&base_old_true_key, static_key_true),
  123. },
  124. {
  125. .init_state = false,
  126. .key = &base_inv_old_true_key,
  127. .test_key = test_key_func(&base_inv_old_true_key, static_key_true),
  128. },
  129. {
  130. .init_state = false,
  131. .key = &base_old_false_key,
  132. .test_key = test_key_func(&base_old_false_key, static_key_false),
  133. },
  134. {
  135. .init_state = true,
  136. .key = &base_inv_old_false_key,
  137. .test_key = test_key_func(&base_inv_old_false_key, static_key_false),
  138. },
  139. /* external keys - new keys */
  140. {
  141. .init_state = true,
  142. .key = &base_true_key.key,
  143. .test_key = test_key_func(&base_true_key, static_branch_likely),
  144. },
  145. {
  146. .init_state = true,
  147. .key = &base_true_key.key,
  148. .test_key = test_key_func(&base_true_key, static_branch_unlikely),
  149. },
  150. {
  151. .init_state = false,
  152. .key = &base_inv_true_key.key,
  153. .test_key = test_key_func(&base_inv_true_key, static_branch_likely),
  154. },
  155. {
  156. .init_state = false,
  157. .key = &base_inv_true_key.key,
  158. .test_key = test_key_func(&base_inv_true_key, static_branch_unlikely),
  159. },
  160. {
  161. .init_state = false,
  162. .key = &base_false_key.key,
  163. .test_key = test_key_func(&base_false_key, static_branch_likely),
  164. },
  165. {
  166. .init_state = false,
  167. .key = &base_false_key.key,
  168. .test_key = test_key_func(&base_false_key, static_branch_unlikely),
  169. },
  170. {
  171. .init_state = true,
  172. .key = &base_inv_false_key.key,
  173. .test_key = test_key_func(&base_inv_false_key, static_branch_likely),
  174. },
  175. {
  176. .init_state = true,
  177. .key = &base_inv_false_key.key,
  178. .test_key = test_key_func(&base_inv_false_key, static_branch_unlikely),
  179. },
  180. };
  181. size = ARRAY_SIZE(static_key_tests);
  182. ret = verify_keys(static_key_tests, size, false);
  183. if (ret)
  184. goto out;
  185. invert_keys(static_key_tests, size);
  186. ret = verify_keys(static_key_tests, size, true);
  187. if (ret)
  188. goto out;
  189. invert_keys(static_key_tests, size);
  190. ret = verify_keys(static_key_tests, size, false);
  191. if (ret)
  192. goto out;
  193. return 0;
  194. out:
  195. return ret;
  196. }
  197. static void __exit test_static_key_exit(void)
  198. {
  199. }
  200. module_init(test_static_key_init);
  201. module_exit(test_static_key_exit);
  202. MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>");
  203. MODULE_LICENSE("GPL");