blob: 915d75df20864d07428376750c1bd148c216a585
1 | /* |
2 | * Kernel module for testing static keys. |
3 | * |
4 | * Copyright 2015 Akamai Technologies Inc. All Rights Reserved |
5 | * |
6 | * Authors: |
7 | * Jason Baron <jbaron@akamai.com> |
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 | |
49 | #define test_key_func(key, branch) \ |
50 | static bool key ## _ ## branch(void) \ |
51 | { \ |
52 | return branch(&key); \ |
53 | } |
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 | |
76 | static int verify_keys(struct test_key *keys, int size, bool invert) |
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 | |
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 | |
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, |
127 | .test_key = &old_true_key_static_key_true, |
128 | }, |
129 | { |
130 | .init_state = false, |
131 | .key = &old_false_key, |
132 | .test_key = &old_false_key_static_key_false, |
133 | }, |
134 | /* internal keys - new keys */ |
135 | { |
136 | .init_state = true, |
137 | .key = &true_key.key, |
138 | .test_key = &true_key_static_branch_likely, |
139 | }, |
140 | { |
141 | .init_state = true, |
142 | .key = &true_key.key, |
143 | .test_key = &true_key_static_branch_unlikely, |
144 | }, |
145 | { |
146 | .init_state = false, |
147 | .key = &false_key.key, |
148 | .test_key = &false_key_static_branch_likely, |
149 | }, |
150 | { |
151 | .init_state = false, |
152 | .key = &false_key.key, |
153 | .test_key = &false_key_static_branch_unlikely, |
154 | }, |
155 | /* external keys - old keys */ |
156 | { |
157 | .init_state = true, |
158 | .key = &base_old_true_key, |
159 | .test_key = &base_old_true_key_static_key_true, |
160 | }, |
161 | { |
162 | .init_state = false, |
163 | .key = &base_inv_old_true_key, |
164 | .test_key = &base_inv_old_true_key_static_key_true, |
165 | }, |
166 | { |
167 | .init_state = false, |
168 | .key = &base_old_false_key, |
169 | .test_key = &base_old_false_key_static_key_false, |
170 | }, |
171 | { |
172 | .init_state = true, |
173 | .key = &base_inv_old_false_key, |
174 | .test_key = &base_inv_old_false_key_static_key_false, |
175 | }, |
176 | /* external keys - new keys */ |
177 | { |
178 | .init_state = true, |
179 | .key = &base_true_key.key, |
180 | .test_key = &base_true_key_static_branch_likely, |
181 | }, |
182 | { |
183 | .init_state = true, |
184 | .key = &base_true_key.key, |
185 | .test_key = &base_true_key_static_branch_unlikely, |
186 | }, |
187 | { |
188 | .init_state = false, |
189 | .key = &base_inv_true_key.key, |
190 | .test_key = &base_inv_true_key_static_branch_likely, |
191 | }, |
192 | { |
193 | .init_state = false, |
194 | .key = &base_inv_true_key.key, |
195 | .test_key = &base_inv_true_key_static_branch_unlikely, |
196 | }, |
197 | { |
198 | .init_state = false, |
199 | .key = &base_false_key.key, |
200 | .test_key = &base_false_key_static_branch_likely, |
201 | }, |
202 | { |
203 | .init_state = false, |
204 | .key = &base_false_key.key, |
205 | .test_key = &base_false_key_static_branch_unlikely, |
206 | }, |
207 | { |
208 | .init_state = true, |
209 | .key = &base_inv_false_key.key, |
210 | .test_key = &base_inv_false_key_static_branch_likely, |
211 | }, |
212 | { |
213 | .init_state = true, |
214 | .key = &base_inv_false_key.key, |
215 | .test_key = &base_inv_false_key_static_branch_unlikely, |
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 <jbaron@akamai.com>"); |
247 | MODULE_LICENSE("GPL"); |
248 |