at v4.8 6.1 kB view raw
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 */ 23struct static_key old_true_key = STATIC_KEY_INIT_TRUE; 24struct static_key old_false_key = STATIC_KEY_INIT_FALSE; 25 26/* new api */ 27DEFINE_STATIC_KEY_TRUE(true_key); 28DEFINE_STATIC_KEY_FALSE(false_key); 29 30/* external */ 31extern struct static_key base_old_true_key; 32extern struct static_key base_inv_old_true_key; 33extern struct static_key base_old_false_key; 34extern struct static_key base_inv_old_false_key; 35 36/* new api */ 37extern struct static_key_true base_true_key; 38extern struct static_key_true base_inv_true_key; 39extern struct static_key_false base_false_key; 40extern struct static_key_false base_inv_false_key; 41 42 43struct 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) \ 50static bool key ## _ ## branch(void) \ 51{ \ 52 return branch(&key); \ 53} 54 55static 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 63static 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 76static 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 98test_key_func(old_true_key, static_key_true) 99test_key_func(old_false_key, static_key_false) 100test_key_func(true_key, static_branch_likely) 101test_key_func(true_key, static_branch_unlikely) 102test_key_func(false_key, static_branch_likely) 103test_key_func(false_key, static_branch_unlikely) 104test_key_func(base_old_true_key, static_key_true) 105test_key_func(base_inv_old_true_key, static_key_true) 106test_key_func(base_old_false_key, static_key_false) 107test_key_func(base_inv_old_false_key, static_key_false) 108test_key_func(base_true_key, static_branch_likely) 109test_key_func(base_true_key, static_branch_unlikely) 110test_key_func(base_inv_true_key, static_branch_likely) 111test_key_func(base_inv_true_key, static_branch_unlikely) 112test_key_func(base_false_key, static_branch_likely) 113test_key_func(base_false_key, static_branch_unlikely) 114test_key_func(base_inv_false_key, static_branch_likely) 115test_key_func(base_inv_false_key, static_branch_unlikely) 116 117static 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; 235out: 236 return ret; 237} 238 239static void __exit test_static_key_exit(void) 240{ 241} 242 243module_init(test_static_key_init); 244module_exit(test_static_key_exit); 245 246MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>"); 247MODULE_LICENSE("GPL");