1 | // SPDX-License-Identifier: GPL-2.0-only |
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> |
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 | |
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(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 | /* internal keys - old keys */ |
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 | /* internal keys - new keys */ |
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 | /* external keys - old keys */ |
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 | /* external keys - new keys */ |
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(keys: static_key_tests, size, invert: false); |
214 | if (ret) |
215 | goto out; |
216 | |
217 | invert_keys(keys: static_key_tests, size); |
218 | ret = verify_keys(keys: static_key_tests, size, invert: true); |
219 | if (ret) |
220 | goto out; |
221 | |
222 | invert_keys(keys: static_key_tests, size); |
223 | ret = verify_keys(keys: static_key_tests, size, invert: 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" ); |
240 | |