1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Kernel module for testing static keys. 4 * 5 * Copyright 2015 Akamai Technologies Inc. All Rights Reserved 6 * 7 * Authors: 8 * Jason Baron <jbaron@akamai.com> 9 */ 10 11 #include <linux/module.h> 12 #include <linux/jump_label.h> 13 14 /* old keys */ 15 struct static_key old_true_key = STATIC_KEY_INIT_TRUE; 16 struct static_key old_false_key = STATIC_KEY_INIT_FALSE; 17 18 /* new api */ 19 DEFINE_STATIC_KEY_TRUE(true_key); 20 DEFINE_STATIC_KEY_FALSE(false_key); 21 22 /* external */ 23 extern struct static_key base_old_true_key; 24 extern struct static_key base_inv_old_true_key; 25 extern struct static_key base_old_false_key; 26 extern struct static_key base_inv_old_false_key; 27 28 /* new api */ 29 extern struct static_key_true base_true_key; 30 extern struct static_key_true base_inv_true_key; 31 extern struct static_key_false base_false_key; 32 extern struct static_key_false base_inv_false_key; 33 34 35 struct test_key { 36 bool init_state; 37 struct static_key *key; 38 bool (*test_key)(void); 39 }; 40 41 #define test_key_func(key, branch) \ 42 static bool key ## _ ## branch(void) \ 43 { \ 44 return branch(&key); \ 45 } 46 47 static void invert_key(struct static_key *key) 48 { 49 if (static_key_enabled(key)) 50 static_key_disable(key); 51 else 52 static_key_enable(key); 53 } 54 55 static void invert_keys(struct test_key *keys, int size) 56 { 57 struct static_key *previous = NULL; 58 int i; 59 60 for (i = 0; i < size; i++) { 61 if (previous != keys[i].key) { 62 invert_key(keys[i].key); 63 previous = keys[i].key; 64 } 65 } 66 } 67 68 static int verify_keys(struct test_key *keys, int size, bool invert) 69 { 70 int i; 71 bool ret, init; 72 73 for (i = 0; i < size; i++) { 74 ret = static_key_enabled(keys[i].key); 75 init = keys[i].init_state; 76 if (ret != (invert ? !init : init)) 77 return -EINVAL; 78 ret = keys[i].test_key(); 79 if (static_key_enabled(keys[i].key)) { 80 if (!ret) 81 return -EINVAL; 82 } else { 83 if (ret) 84 return -EINVAL; 85 } 86 } 87 return 0; 88 } 89 90 test_key_func(old_true_key, static_key_true) 91 test_key_func(old_false_key, static_key_false) 92 test_key_func(true_key, static_branch_likely) 93 test_key_func(true_key, static_branch_unlikely) 94 test_key_func(false_key, static_branch_likely) 95 test_key_func(false_key, static_branch_unlikely) 96 test_key_func(base_old_true_key, static_key_true) 97 test_key_func(base_inv_old_true_key, static_key_true) 98 test_key_func(base_old_false_key, static_key_false) 99 test_key_func(base_inv_old_false_key, static_key_false) 100 test_key_func(base_true_key, static_branch_likely) 101 test_key_func(base_true_key, static_branch_unlikely) 102 test_key_func(base_inv_true_key, static_branch_likely) 103 test_key_func(base_inv_true_key, static_branch_unlikely) 104 test_key_func(base_false_key, static_branch_likely) 105 test_key_func(base_false_key, static_branch_unlikely) 106 test_key_func(base_inv_false_key, static_branch_likely) 107 test_key_func(base_inv_false_key, static_branch_unlikely) 108 109 static int __init test_static_key_init(void) 110 { 111 int ret; 112 int size; 113 114 struct test_key static_key_tests[] = { 115 /* internal keys - old keys */ 116 { 117 .init_state = true, 118 .key = &old_true_key, 119 .test_key = &old_true_key_static_key_true, 120 }, 121 { 122 .init_state = false, 123 .key = &old_false_key, 124 .test_key = &old_false_key_static_key_false, 125 }, 126 /* internal keys - new keys */ 127 { 128 .init_state = true, 129 .key = &true_key.key, 130 .test_key = &true_key_static_branch_likely, 131 }, 132 { 133 .init_state = true, 134 .key = &true_key.key, 135 .test_key = &true_key_static_branch_unlikely, 136 }, 137 { 138 .init_state = false, 139 .key = &false_key.key, 140 .test_key = &false_key_static_branch_likely, 141 }, 142 { 143 .init_state = false, 144 .key = &false_key.key, 145 .test_key = &false_key_static_branch_unlikely, 146 }, 147 /* external keys - old keys */ 148 { 149 .init_state = true, 150 .key = &base_old_true_key, 151 .test_key = &base_old_true_key_static_key_true, 152 }, 153 { 154 .init_state = false, 155 .key = &base_inv_old_true_key, 156 .test_key = &base_inv_old_true_key_static_key_true, 157 }, 158 { 159 .init_state = false, 160 .key = &base_old_false_key, 161 .test_key = &base_old_false_key_static_key_false, 162 }, 163 { 164 .init_state = true, 165 .key = &base_inv_old_false_key, 166 .test_key = &base_inv_old_false_key_static_key_false, 167 }, 168 /* external keys - new keys */ 169 { 170 .init_state = true, 171 .key = &base_true_key.key, 172 .test_key = &base_true_key_static_branch_likely, 173 }, 174 { 175 .init_state = true, 176 .key = &base_true_key.key, 177 .test_key = &base_true_key_static_branch_unlikely, 178 }, 179 { 180 .init_state = false, 181 .key = &base_inv_true_key.key, 182 .test_key = &base_inv_true_key_static_branch_likely, 183 }, 184 { 185 .init_state = false, 186 .key = &base_inv_true_key.key, 187 .test_key = &base_inv_true_key_static_branch_unlikely, 188 }, 189 { 190 .init_state = false, 191 .key = &base_false_key.key, 192 .test_key = &base_false_key_static_branch_likely, 193 }, 194 { 195 .init_state = false, 196 .key = &base_false_key.key, 197 .test_key = &base_false_key_static_branch_unlikely, 198 }, 199 { 200 .init_state = true, 201 .key = &base_inv_false_key.key, 202 .test_key = &base_inv_false_key_static_branch_likely, 203 }, 204 { 205 .init_state = true, 206 .key = &base_inv_false_key.key, 207 .test_key = &base_inv_false_key_static_branch_unlikely, 208 }, 209 }; 210 211 size = ARRAY_SIZE(static_key_tests); 212 213 ret = verify_keys(static_key_tests, size, false); 214 if (ret) 215 goto out; 216 217 invert_keys(static_key_tests, size); 218 ret = verify_keys(static_key_tests, size, true); 219 if (ret) 220 goto out; 221 222 invert_keys(static_key_tests, size); 223 ret = verify_keys(static_key_tests, size, false); 224 if (ret) 225 goto out; 226 return 0; 227 out: 228 return ret; 229 } 230 231 static void __exit test_static_key_exit(void) 232 { 233 } 234 235 module_init(test_static_key_init); 236 module_exit(test_static_key_exit); 237 238 MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>"); 239 MODULE_LICENSE("GPL"); 240