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 ({bool func(void) { return branch(key); } func; }) 51 52 static void invert_key(struct static_key *key) 53 { 54 if (static_key_enabled(key)) 55 static_key_disable(key); 56 else 57 static_key_enable(key); 58 } 59 60 static void invert_keys(struct test_key *keys, int size) 61 { 62 struct static_key *previous = NULL; 63 int i; 64 65 for (i = 0; i < size; i++) { 66 if (previous != keys[i].key) { 67 invert_key(keys[i].key); 68 previous = keys[i].key; 69 } 70 } 71 } 72 73 static int verify_keys(struct test_key *keys, int size, bool invert) 74 { 75 int i; 76 bool ret, init; 77 78 for (i = 0; i < size; i++) { 79 ret = static_key_enabled(keys[i].key); 80 init = keys[i].init_state; 81 if (ret != (invert ? !init : init)) 82 return -EINVAL; 83 ret = keys[i].test_key(); 84 if (static_key_enabled(keys[i].key)) { 85 if (!ret) 86 return -EINVAL; 87 } else { 88 if (ret) 89 return -EINVAL; 90 } 91 } 92 return 0; 93 } 94 95 static int __init test_static_key_init(void) 96 { 97 int ret; 98 int size; 99 100 struct test_key static_key_tests[] = { 101 /* internal keys - old keys */ 102 { 103 .init_state = true, 104 .key = &old_true_key, 105 .test_key = test_key_func(&old_true_key, static_key_true), 106 }, 107 { 108 .init_state = false, 109 .key = &old_false_key, 110 .test_key = test_key_func(&old_false_key, static_key_false), 111 }, 112 /* internal keys - new keys */ 113 { 114 .init_state = true, 115 .key = &true_key.key, 116 .test_key = test_key_func(&true_key, static_branch_likely), 117 }, 118 { 119 .init_state = true, 120 .key = &true_key.key, 121 .test_key = test_key_func(&true_key, static_branch_unlikely), 122 }, 123 { 124 .init_state = false, 125 .key = &false_key.key, 126 .test_key = test_key_func(&false_key, static_branch_likely), 127 }, 128 { 129 .init_state = false, 130 .key = &false_key.key, 131 .test_key = test_key_func(&false_key, static_branch_unlikely), 132 }, 133 /* external keys - old keys */ 134 { 135 .init_state = true, 136 .key = &base_old_true_key, 137 .test_key = test_key_func(&base_old_true_key, static_key_true), 138 }, 139 { 140 .init_state = false, 141 .key = &base_inv_old_true_key, 142 .test_key = test_key_func(&base_inv_old_true_key, static_key_true), 143 }, 144 { 145 .init_state = false, 146 .key = &base_old_false_key, 147 .test_key = test_key_func(&base_old_false_key, static_key_false), 148 }, 149 { 150 .init_state = true, 151 .key = &base_inv_old_false_key, 152 .test_key = test_key_func(&base_inv_old_false_key, static_key_false), 153 }, 154 /* external keys - new keys */ 155 { 156 .init_state = true, 157 .key = &base_true_key.key, 158 .test_key = test_key_func(&base_true_key, static_branch_likely), 159 }, 160 { 161 .init_state = true, 162 .key = &base_true_key.key, 163 .test_key = test_key_func(&base_true_key, static_branch_unlikely), 164 }, 165 { 166 .init_state = false, 167 .key = &base_inv_true_key.key, 168 .test_key = test_key_func(&base_inv_true_key, static_branch_likely), 169 }, 170 { 171 .init_state = false, 172 .key = &base_inv_true_key.key, 173 .test_key = test_key_func(&base_inv_true_key, static_branch_unlikely), 174 }, 175 { 176 .init_state = false, 177 .key = &base_false_key.key, 178 .test_key = test_key_func(&base_false_key, static_branch_likely), 179 }, 180 { 181 .init_state = false, 182 .key = &base_false_key.key, 183 .test_key = test_key_func(&base_false_key, static_branch_unlikely), 184 }, 185 { 186 .init_state = true, 187 .key = &base_inv_false_key.key, 188 .test_key = test_key_func(&base_inv_false_key, static_branch_likely), 189 }, 190 { 191 .init_state = true, 192 .key = &base_inv_false_key.key, 193 .test_key = test_key_func(&base_inv_false_key, static_branch_unlikely), 194 }, 195 }; 196 197 size = ARRAY_SIZE(static_key_tests); 198 199 ret = verify_keys(static_key_tests, size, false); 200 if (ret) 201 goto out; 202 203 invert_keys(static_key_tests, size); 204 ret = verify_keys(static_key_tests, size, true); 205 if (ret) 206 goto out; 207 208 invert_keys(static_key_tests, size); 209 ret = verify_keys(static_key_tests, size, false); 210 if (ret) 211 goto out; 212 return 0; 213 out: 214 return ret; 215 } 216 217 static void __exit test_static_key_exit(void) 218 { 219 } 220 221 module_init(test_static_key_init); 222 module_exit(test_static_key_exit); 223 224 MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>"); 225 MODULE_LICENSE("GPL"); 226