test_static_keys.c (5731B)
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 */ 15struct static_key old_true_key = STATIC_KEY_INIT_TRUE; 16struct static_key old_false_key = STATIC_KEY_INIT_FALSE; 17 18/* new api */ 19DEFINE_STATIC_KEY_TRUE(true_key); 20DEFINE_STATIC_KEY_FALSE(false_key); 21 22/* external */ 23extern struct static_key base_old_true_key; 24extern struct static_key base_inv_old_true_key; 25extern struct static_key base_old_false_key; 26extern struct static_key base_inv_old_false_key; 27 28/* new api */ 29extern struct static_key_true base_true_key; 30extern struct static_key_true base_inv_true_key; 31extern struct static_key_false base_false_key; 32extern struct static_key_false base_inv_false_key; 33 34 35struct 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) \ 42static bool key ## _ ## branch(void) \ 43{ \ 44 return branch(&key); \ 45} 46 47static 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 55static 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 68static 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 90test_key_func(old_true_key, static_key_true) 91test_key_func(old_false_key, static_key_false) 92test_key_func(true_key, static_branch_likely) 93test_key_func(true_key, static_branch_unlikely) 94test_key_func(false_key, static_branch_likely) 95test_key_func(false_key, static_branch_unlikely) 96test_key_func(base_old_true_key, static_key_true) 97test_key_func(base_inv_old_true_key, static_key_true) 98test_key_func(base_old_false_key, static_key_false) 99test_key_func(base_inv_old_false_key, static_key_false) 100test_key_func(base_true_key, static_branch_likely) 101test_key_func(base_true_key, static_branch_unlikely) 102test_key_func(base_inv_true_key, static_branch_likely) 103test_key_func(base_inv_true_key, static_branch_unlikely) 104test_key_func(base_false_key, static_branch_likely) 105test_key_func(base_false_key, static_branch_unlikely) 106test_key_func(base_inv_false_key, static_branch_likely) 107test_key_func(base_inv_false_key, static_branch_unlikely) 108 109static 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; 227out: 228 return ret; 229} 230 231static void __exit test_static_key_exit(void) 232{ 233} 234 235module_init(test_static_key_init); 236module_exit(test_static_key_exit); 237 238MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>"); 239MODULE_LICENSE("GPL");