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