0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/jump_label.h>
0013
0014
0015 struct static_key old_true_key = STATIC_KEY_INIT_TRUE;
0016 struct static_key old_false_key = STATIC_KEY_INIT_FALSE;
0017
0018
0019 DEFINE_STATIC_KEY_TRUE(true_key);
0020 DEFINE_STATIC_KEY_FALSE(false_key);
0021
0022
0023 extern struct static_key base_old_true_key;
0024 extern struct static_key base_inv_old_true_key;
0025 extern struct static_key base_old_false_key;
0026 extern struct static_key base_inv_old_false_key;
0027
0028
0029 extern struct static_key_true base_true_key;
0030 extern struct static_key_true base_inv_true_key;
0031 extern struct static_key_false base_false_key;
0032 extern struct static_key_false base_inv_false_key;
0033
0034
0035 struct test_key {
0036 bool init_state;
0037 struct static_key *key;
0038 bool (*test_key)(void);
0039 };
0040
0041 #define test_key_func(key, branch) \
0042 static bool key ## _ ## branch(void) \
0043 { \
0044 return branch(&key); \
0045 }
0046
0047 static void invert_key(struct static_key *key)
0048 {
0049 if (static_key_enabled(key))
0050 static_key_disable(key);
0051 else
0052 static_key_enable(key);
0053 }
0054
0055 static void invert_keys(struct test_key *keys, int size)
0056 {
0057 struct static_key *previous = NULL;
0058 int i;
0059
0060 for (i = 0; i < size; i++) {
0061 if (previous != keys[i].key) {
0062 invert_key(keys[i].key);
0063 previous = keys[i].key;
0064 }
0065 }
0066 }
0067
0068 static int verify_keys(struct test_key *keys, int size, bool invert)
0069 {
0070 int i;
0071 bool ret, init;
0072
0073 for (i = 0; i < size; i++) {
0074 ret = static_key_enabled(keys[i].key);
0075 init = keys[i].init_state;
0076 if (ret != (invert ? !init : init))
0077 return -EINVAL;
0078 ret = keys[i].test_key();
0079 if (static_key_enabled(keys[i].key)) {
0080 if (!ret)
0081 return -EINVAL;
0082 } else {
0083 if (ret)
0084 return -EINVAL;
0085 }
0086 }
0087 return 0;
0088 }
0089
0090 test_key_func(old_true_key, static_key_true)
0091 test_key_func(old_false_key, static_key_false)
0092 test_key_func(true_key, static_branch_likely)
0093 test_key_func(true_key, static_branch_unlikely)
0094 test_key_func(false_key, static_branch_likely)
0095 test_key_func(false_key, static_branch_unlikely)
0096 test_key_func(base_old_true_key, static_key_true)
0097 test_key_func(base_inv_old_true_key, static_key_true)
0098 test_key_func(base_old_false_key, static_key_false)
0099 test_key_func(base_inv_old_false_key, static_key_false)
0100 test_key_func(base_true_key, static_branch_likely)
0101 test_key_func(base_true_key, static_branch_unlikely)
0102 test_key_func(base_inv_true_key, static_branch_likely)
0103 test_key_func(base_inv_true_key, static_branch_unlikely)
0104 test_key_func(base_false_key, static_branch_likely)
0105 test_key_func(base_false_key, static_branch_unlikely)
0106 test_key_func(base_inv_false_key, static_branch_likely)
0107 test_key_func(base_inv_false_key, static_branch_unlikely)
0108
0109 static int __init test_static_key_init(void)
0110 {
0111 int ret;
0112 int size;
0113
0114 struct test_key static_key_tests[] = {
0115
0116 {
0117 .init_state = true,
0118 .key = &old_true_key,
0119 .test_key = &old_true_key_static_key_true,
0120 },
0121 {
0122 .init_state = false,
0123 .key = &old_false_key,
0124 .test_key = &old_false_key_static_key_false,
0125 },
0126
0127 {
0128 .init_state = true,
0129 .key = &true_key.key,
0130 .test_key = &true_key_static_branch_likely,
0131 },
0132 {
0133 .init_state = true,
0134 .key = &true_key.key,
0135 .test_key = &true_key_static_branch_unlikely,
0136 },
0137 {
0138 .init_state = false,
0139 .key = &false_key.key,
0140 .test_key = &false_key_static_branch_likely,
0141 },
0142 {
0143 .init_state = false,
0144 .key = &false_key.key,
0145 .test_key = &false_key_static_branch_unlikely,
0146 },
0147
0148 {
0149 .init_state = true,
0150 .key = &base_old_true_key,
0151 .test_key = &base_old_true_key_static_key_true,
0152 },
0153 {
0154 .init_state = false,
0155 .key = &base_inv_old_true_key,
0156 .test_key = &base_inv_old_true_key_static_key_true,
0157 },
0158 {
0159 .init_state = false,
0160 .key = &base_old_false_key,
0161 .test_key = &base_old_false_key_static_key_false,
0162 },
0163 {
0164 .init_state = true,
0165 .key = &base_inv_old_false_key,
0166 .test_key = &base_inv_old_false_key_static_key_false,
0167 },
0168
0169 {
0170 .init_state = true,
0171 .key = &base_true_key.key,
0172 .test_key = &base_true_key_static_branch_likely,
0173 },
0174 {
0175 .init_state = true,
0176 .key = &base_true_key.key,
0177 .test_key = &base_true_key_static_branch_unlikely,
0178 },
0179 {
0180 .init_state = false,
0181 .key = &base_inv_true_key.key,
0182 .test_key = &base_inv_true_key_static_branch_likely,
0183 },
0184 {
0185 .init_state = false,
0186 .key = &base_inv_true_key.key,
0187 .test_key = &base_inv_true_key_static_branch_unlikely,
0188 },
0189 {
0190 .init_state = false,
0191 .key = &base_false_key.key,
0192 .test_key = &base_false_key_static_branch_likely,
0193 },
0194 {
0195 .init_state = false,
0196 .key = &base_false_key.key,
0197 .test_key = &base_false_key_static_branch_unlikely,
0198 },
0199 {
0200 .init_state = true,
0201 .key = &base_inv_false_key.key,
0202 .test_key = &base_inv_false_key_static_branch_likely,
0203 },
0204 {
0205 .init_state = true,
0206 .key = &base_inv_false_key.key,
0207 .test_key = &base_inv_false_key_static_branch_unlikely,
0208 },
0209 };
0210
0211 size = ARRAY_SIZE(static_key_tests);
0212
0213 ret = verify_keys(static_key_tests, size, false);
0214 if (ret)
0215 goto out;
0216
0217 invert_keys(static_key_tests, size);
0218 ret = verify_keys(static_key_tests, size, true);
0219 if (ret)
0220 goto out;
0221
0222 invert_keys(static_key_tests, size);
0223 ret = verify_keys(static_key_tests, size, false);
0224 if (ret)
0225 goto out;
0226 return 0;
0227 out:
0228 return ret;
0229 }
0230
0231 static void __exit test_static_key_exit(void)
0232 {
0233 }
0234
0235 module_init(test_static_key_init);
0236 module_exit(test_static_key_exit);
0237
0238 MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>");
0239 MODULE_LICENSE("GPL");