]>
Commit | Line | Data |
---|---|---|
9c92ab61 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2bf9e0ab IM |
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> | |
2bf9e0ab IM |
9 | */ |
10 | ||
11 | #include <linux/module.h> | |
12 | #include <linux/jump_label.h> | |
13 | ||
14 | /* old keys */ | |
15 | struct static_key old_true_key = STATIC_KEY_INIT_TRUE; | |
16 | struct static_key old_false_key = STATIC_KEY_INIT_FALSE; | |
17 | ||
18 | /* new api */ | |
19 | DEFINE_STATIC_KEY_TRUE(true_key); | |
20 | DEFINE_STATIC_KEY_FALSE(false_key); | |
21 | ||
22 | /* external */ | |
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 | /* new api */ | |
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 | ||
975db45e AB |
41 | #define test_key_func(key, branch) \ |
42 | static bool key ## _ ## branch(void) \ | |
43 | { \ | |
44 | return branch(&key); \ | |
45 | } | |
2bf9e0ab IM |
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 | ||
20f9ed15 | 68 | static int verify_keys(struct test_key *keys, int size, bool invert) |
2bf9e0ab IM |
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 | ||
975db45e AB |
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 | ||
2bf9e0ab IM |
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 | /* internal keys - old keys */ | |
116 | { | |
117 | .init_state = true, | |
118 | .key = &old_true_key, | |
975db45e | 119 | .test_key = &old_true_key_static_key_true, |
2bf9e0ab IM |
120 | }, |
121 | { | |
122 | .init_state = false, | |
123 | .key = &old_false_key, | |
975db45e | 124 | .test_key = &old_false_key_static_key_false, |
2bf9e0ab IM |
125 | }, |
126 | /* internal keys - new keys */ | |
127 | { | |
128 | .init_state = true, | |
129 | .key = &true_key.key, | |
975db45e | 130 | .test_key = &true_key_static_branch_likely, |
2bf9e0ab IM |
131 | }, |
132 | { | |
133 | .init_state = true, | |
134 | .key = &true_key.key, | |
975db45e | 135 | .test_key = &true_key_static_branch_unlikely, |
2bf9e0ab IM |
136 | }, |
137 | { | |
138 | .init_state = false, | |
139 | .key = &false_key.key, | |
975db45e | 140 | .test_key = &false_key_static_branch_likely, |
2bf9e0ab IM |
141 | }, |
142 | { | |
143 | .init_state = false, | |
144 | .key = &false_key.key, | |
975db45e | 145 | .test_key = &false_key_static_branch_unlikely, |
2bf9e0ab IM |
146 | }, |
147 | /* external keys - old keys */ | |
148 | { | |
149 | .init_state = true, | |
150 | .key = &base_old_true_key, | |
975db45e | 151 | .test_key = &base_old_true_key_static_key_true, |
2bf9e0ab IM |
152 | }, |
153 | { | |
154 | .init_state = false, | |
155 | .key = &base_inv_old_true_key, | |
975db45e | 156 | .test_key = &base_inv_old_true_key_static_key_true, |
2bf9e0ab IM |
157 | }, |
158 | { | |
159 | .init_state = false, | |
160 | .key = &base_old_false_key, | |
975db45e | 161 | .test_key = &base_old_false_key_static_key_false, |
2bf9e0ab IM |
162 | }, |
163 | { | |
164 | .init_state = true, | |
165 | .key = &base_inv_old_false_key, | |
975db45e | 166 | .test_key = &base_inv_old_false_key_static_key_false, |
2bf9e0ab IM |
167 | }, |
168 | /* external keys - new keys */ | |
169 | { | |
170 | .init_state = true, | |
171 | .key = &base_true_key.key, | |
975db45e | 172 | .test_key = &base_true_key_static_branch_likely, |
2bf9e0ab IM |
173 | }, |
174 | { | |
175 | .init_state = true, | |
176 | .key = &base_true_key.key, | |
975db45e | 177 | .test_key = &base_true_key_static_branch_unlikely, |
2bf9e0ab IM |
178 | }, |
179 | { | |
180 | .init_state = false, | |
181 | .key = &base_inv_true_key.key, | |
975db45e | 182 | .test_key = &base_inv_true_key_static_branch_likely, |
2bf9e0ab IM |
183 | }, |
184 | { | |
185 | .init_state = false, | |
186 | .key = &base_inv_true_key.key, | |
975db45e | 187 | .test_key = &base_inv_true_key_static_branch_unlikely, |
2bf9e0ab IM |
188 | }, |
189 | { | |
190 | .init_state = false, | |
191 | .key = &base_false_key.key, | |
975db45e | 192 | .test_key = &base_false_key_static_branch_likely, |
2bf9e0ab IM |
193 | }, |
194 | { | |
195 | .init_state = false, | |
196 | .key = &base_false_key.key, | |
975db45e | 197 | .test_key = &base_false_key_static_branch_unlikely, |
2bf9e0ab IM |
198 | }, |
199 | { | |
200 | .init_state = true, | |
201 | .key = &base_inv_false_key.key, | |
975db45e | 202 | .test_key = &base_inv_false_key_static_branch_likely, |
2bf9e0ab IM |
203 | }, |
204 | { | |
205 | .init_state = true, | |
206 | .key = &base_inv_false_key.key, | |
975db45e | 207 | .test_key = &base_inv_false_key_static_branch_unlikely, |
2bf9e0ab IM |
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 <jbaron@akamai.com>"); | |
239 | MODULE_LICENSE("GPL"); |