| 1 | |
| 2 | |
| 3 | * Kernel module for testing static keys.
|
| 4 | *
|
| 5 | * Copyright 2015 Akamai Technologies Inc. All Rights Reserved
|
| 6 | *
|
| 7 | * Authors:
|
| 8 | * Jason Baron <[email protected]>
|
| 9 |
|
| 10 |
|
| 11 | #include <linux/module.h>
|
| 12 | #include <linux/jump_label.h>
|
| 13 |
|
| 14 |
|
| 15 | struct static_key old_true_key = STATIC_KEY_INIT_TRUE;
|
| 16 | struct static_key old_false_key = STATIC_KEY_INIT_FALSE;
|
| 17 |
|
| 18 |
|
| 19 | DEFINE_STATIC_KEY_TRUE(true_key);
|
| 20 | DEFINE_STATIC_KEY_FALSE(false_key);
|
| 21 |
|
| 22 |
|
| 23 | extern struct static_key base_old_true_key;
|
| 24 | extern struct static_key base_inv_old_true_key;
|
| 25 | extern struct static_key base_old_false_key;
|
| 26 | extern struct static_key base_inv_old_false_key;
|
| 27 |
|
| 28 |
|
| 29 | extern struct static_key_true base_true_key;
|
| 30 | extern struct static_key_true base_inv_true_key;
|
| 31 | extern struct static_key_false base_false_key;
|
| 32 | extern struct static_key_false base_inv_false_key;
|
| 33 |
|
| 34 |
|
| 35 | struct 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) \
|
| 42 | static bool key ## _ ## branch(void) \
|
| 43 | { \
|
| 44 | return branch(&key); \
|
| 45 | }
|
| 46 |
|
| 47 | static 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 |
|
| 55 | static 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 |
|
| 68 | static 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 |
|
| 90 | test_key_func(old_true_key, static_key_true)
|
| 91 | test_key_func(old_false_key, static_key_false)
|
| 92 | test_key_func(true_key, static_branch_likely)
|
| 93 | test_key_func(true_key, static_branch_unlikely)
|
| 94 | test_key_func(false_key, static_branch_likely)
|
| 95 | test_key_func(false_key, static_branch_unlikely)
|
| 96 | test_key_func(base_old_true_key, static_key_true)
|
| 97 | test_key_func(base_inv_old_true_key, static_key_true)
|
| 98 | test_key_func(base_old_false_key, static_key_false)
|
| 99 | test_key_func(base_inv_old_false_key, static_key_false)
|
| 100 | test_key_func(base_true_key, static_branch_likely)
|
| 101 | test_key_func(base_true_key, static_branch_unlikely)
|
| 102 | test_key_func(base_inv_true_key, static_branch_likely)
|
| 103 | test_key_func(base_inv_true_key, static_branch_unlikely)
|
| 104 | test_key_func(base_false_key, static_branch_likely)
|
| 105 | test_key_func(base_false_key, static_branch_unlikely)
|
| 106 | test_key_func(base_inv_false_key, static_branch_likely)
|
| 107 | test_key_func(base_inv_false_key, static_branch_unlikely)
|
| 108 |
|
| 109 | static int __init test_static_key_init(void)
|
| 110 | {
|
| 111 | int ret;
|
| 112 | int size;
|
| 113 |
|
| 114 | struct test_key static_key_tests[] = {
|
| 115 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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;
|
| 227 | out:
|
| 228 | return ret;
|
| 229 | }
|
| 230 |
|
| 231 | static void __exit test_static_key_exit(void)
|
| 232 | {
|
| 233 | }
|
| 234 |
|
| 235 | module_init(test_static_key_init);
|
| 236 | module_exit(test_static_key_exit);
|
| 237 |
|
| 238 | MODULE_AUTHOR("Jason Baron <[email protected]>");
|
| 239 | MODULE_DESCRIPTION("Kernel module for testing static keys");
|
| 240 | MODULE_LICENSE("GPL");
|