]>
Commit | Line | Data |
---|---|---|
2bf9e0ab IM |
1 | /* |
2 | * Kernel module for testing static keys. | |
3 | * | |
4 | * Copyright 2015 Akamai Technologies Inc. All Rights Reserved | |
5 | * | |
6 | * Authors: | |
7 | * Jason Baron <[email protected]> | |
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 */ | |
23 | struct static_key old_true_key = STATIC_KEY_INIT_TRUE; | |
24 | struct static_key old_false_key = STATIC_KEY_INIT_FALSE; | |
25 | ||
26 | /* new api */ | |
27 | DEFINE_STATIC_KEY_TRUE(true_key); | |
28 | DEFINE_STATIC_KEY_FALSE(false_key); | |
29 | ||
30 | /* external */ | |
31 | extern struct static_key base_old_true_key; | |
32 | extern struct static_key base_inv_old_true_key; | |
33 | extern struct static_key base_old_false_key; | |
34 | extern struct static_key base_inv_old_false_key; | |
35 | ||
36 | /* new api */ | |
37 | extern struct static_key_true base_true_key; | |
38 | extern struct static_key_true base_inv_true_key; | |
39 | extern struct static_key_false base_false_key; | |
40 | extern struct static_key_false base_inv_false_key; | |
41 | ||
42 | ||
43 | struct test_key { | |
44 | bool init_state; | |
45 | struct static_key *key; | |
46 | bool (*test_key)(void); | |
47 | }; | |
48 | ||
975db45e AB |
49 | #define test_key_func(key, branch) \ |
50 | static bool key ## _ ## branch(void) \ | |
51 | { \ | |
52 | return branch(&key); \ | |
53 | } | |
2bf9e0ab IM |
54 | |
55 | static 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 | ||
63 | static 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 | ||
20f9ed15 | 76 | static int verify_keys(struct test_key *keys, int size, bool invert) |
2bf9e0ab IM |
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 | ||
975db45e AB |
98 | test_key_func(old_true_key, static_key_true) |
99 | test_key_func(old_false_key, static_key_false) | |
100 | test_key_func(true_key, static_branch_likely) | |
101 | test_key_func(true_key, static_branch_unlikely) | |
102 | test_key_func(false_key, static_branch_likely) | |
103 | test_key_func(false_key, static_branch_unlikely) | |
104 | test_key_func(base_old_true_key, static_key_true) | |
105 | test_key_func(base_inv_old_true_key, static_key_true) | |
106 | test_key_func(base_old_false_key, static_key_false) | |
107 | test_key_func(base_inv_old_false_key, static_key_false) | |
108 | test_key_func(base_true_key, static_branch_likely) | |
109 | test_key_func(base_true_key, static_branch_unlikely) | |
110 | test_key_func(base_inv_true_key, static_branch_likely) | |
111 | test_key_func(base_inv_true_key, static_branch_unlikely) | |
112 | test_key_func(base_false_key, static_branch_likely) | |
113 | test_key_func(base_false_key, static_branch_unlikely) | |
114 | test_key_func(base_inv_false_key, static_branch_likely) | |
115 | test_key_func(base_inv_false_key, static_branch_unlikely) | |
116 | ||
2bf9e0ab IM |
117 | static 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, | |
975db45e | 127 | .test_key = &old_true_key_static_key_true, |
2bf9e0ab IM |
128 | }, |
129 | { | |
130 | .init_state = false, | |
131 | .key = &old_false_key, | |
975db45e | 132 | .test_key = &old_false_key_static_key_false, |
2bf9e0ab IM |
133 | }, |
134 | /* internal keys - new keys */ | |
135 | { | |
136 | .init_state = true, | |
137 | .key = &true_key.key, | |
975db45e | 138 | .test_key = &true_key_static_branch_likely, |
2bf9e0ab IM |
139 | }, |
140 | { | |
141 | .init_state = true, | |
142 | .key = &true_key.key, | |
975db45e | 143 | .test_key = &true_key_static_branch_unlikely, |
2bf9e0ab IM |
144 | }, |
145 | { | |
146 | .init_state = false, | |
147 | .key = &false_key.key, | |
975db45e | 148 | .test_key = &false_key_static_branch_likely, |
2bf9e0ab IM |
149 | }, |
150 | { | |
151 | .init_state = false, | |
152 | .key = &false_key.key, | |
975db45e | 153 | .test_key = &false_key_static_branch_unlikely, |
2bf9e0ab IM |
154 | }, |
155 | /* external keys - old keys */ | |
156 | { | |
157 | .init_state = true, | |
158 | .key = &base_old_true_key, | |
975db45e | 159 | .test_key = &base_old_true_key_static_key_true, |
2bf9e0ab IM |
160 | }, |
161 | { | |
162 | .init_state = false, | |
163 | .key = &base_inv_old_true_key, | |
975db45e | 164 | .test_key = &base_inv_old_true_key_static_key_true, |
2bf9e0ab IM |
165 | }, |
166 | { | |
167 | .init_state = false, | |
168 | .key = &base_old_false_key, | |
975db45e | 169 | .test_key = &base_old_false_key_static_key_false, |
2bf9e0ab IM |
170 | }, |
171 | { | |
172 | .init_state = true, | |
173 | .key = &base_inv_old_false_key, | |
975db45e | 174 | .test_key = &base_inv_old_false_key_static_key_false, |
2bf9e0ab IM |
175 | }, |
176 | /* external keys - new keys */ | |
177 | { | |
178 | .init_state = true, | |
179 | .key = &base_true_key.key, | |
975db45e | 180 | .test_key = &base_true_key_static_branch_likely, |
2bf9e0ab IM |
181 | }, |
182 | { | |
183 | .init_state = true, | |
184 | .key = &base_true_key.key, | |
975db45e | 185 | .test_key = &base_true_key_static_branch_unlikely, |
2bf9e0ab IM |
186 | }, |
187 | { | |
188 | .init_state = false, | |
189 | .key = &base_inv_true_key.key, | |
975db45e | 190 | .test_key = &base_inv_true_key_static_branch_likely, |
2bf9e0ab IM |
191 | }, |
192 | { | |
193 | .init_state = false, | |
194 | .key = &base_inv_true_key.key, | |
975db45e | 195 | .test_key = &base_inv_true_key_static_branch_unlikely, |
2bf9e0ab IM |
196 | }, |
197 | { | |
198 | .init_state = false, | |
199 | .key = &base_false_key.key, | |
975db45e | 200 | .test_key = &base_false_key_static_branch_likely, |
2bf9e0ab IM |
201 | }, |
202 | { | |
203 | .init_state = false, | |
204 | .key = &base_false_key.key, | |
975db45e | 205 | .test_key = &base_false_key_static_branch_unlikely, |
2bf9e0ab IM |
206 | }, |
207 | { | |
208 | .init_state = true, | |
209 | .key = &base_inv_false_key.key, | |
975db45e | 210 | .test_key = &base_inv_false_key_static_branch_likely, |
2bf9e0ab IM |
211 | }, |
212 | { | |
213 | .init_state = true, | |
214 | .key = &base_inv_false_key.key, | |
975db45e | 215 | .test_key = &base_inv_false_key_static_branch_unlikely, |
2bf9e0ab IM |
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; | |
235 | out: | |
236 | return ret; | |
237 | } | |
238 | ||
239 | static void __exit test_static_key_exit(void) | |
240 | { | |
241 | } | |
242 | ||
243 | module_init(test_static_key_init); | |
244 | module_exit(test_static_key_exit); | |
245 | ||
246 | MODULE_AUTHOR("Jason Baron <[email protected]>"); | |
247 | MODULE_LICENSE("GPL"); |