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 */
15struct static_key old_true_key = STATIC_KEY_INIT_TRUE;
16struct static_key old_false_key = STATIC_KEY_INIT_FALSE;
17
18/* new api */
19DEFINE_STATIC_KEY_TRUE(true_key);
20DEFINE_STATIC_KEY_FALSE(false_key);
21
22/* external */
23extern struct static_key base_old_true_key;
24extern struct static_key base_inv_old_true_key;
25extern struct static_key base_old_false_key;
26extern struct static_key base_inv_old_false_key;
27
28/* new api */
29extern struct static_key_true base_true_key;
30extern struct static_key_true base_inv_true_key;
31extern struct static_key_false base_false_key;
32extern struct static_key_false base_inv_false_key;
33
34
35struct 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) \
42static bool key ## _ ## branch(void) \
43{ \
44 return branch(&key); \
45}
46
47static 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
55static 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
68static 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
90test_key_func(old_true_key, static_key_true)
91test_key_func(old_false_key, static_key_false)
92test_key_func(true_key, static_branch_likely)
93test_key_func(true_key, static_branch_unlikely)
94test_key_func(false_key, static_branch_likely)
95test_key_func(false_key, static_branch_unlikely)
96test_key_func(base_old_true_key, static_key_true)
97test_key_func(base_inv_old_true_key, static_key_true)
98test_key_func(base_old_false_key, static_key_false)
99test_key_func(base_inv_old_false_key, static_key_false)
100test_key_func(base_true_key, static_branch_likely)
101test_key_func(base_true_key, static_branch_unlikely)
102test_key_func(base_inv_true_key, static_branch_likely)
103test_key_func(base_inv_true_key, static_branch_unlikely)
104test_key_func(base_false_key, static_branch_likely)
105test_key_func(base_false_key, static_branch_unlikely)
106test_key_func(base_inv_false_key, static_branch_likely)
107test_key_func(base_inv_false_key, static_branch_unlikely)
108
109static 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;
227out:
228 return ret;
229}
230
231static void __exit test_static_key_exit(void)
232{
233}
234
235module_init(test_static_key_init);
236module_exit(test_static_key_exit);
237
238MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>");
239MODULE_LICENSE("GPL");
240

source code of linux/lib/test_static_keys.c