xref: /linux/lib/test_static_keys.c (revision 4b132aacb0768ac1e652cf517097ea6f237214b9)
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(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(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_DESCRIPTION("Kernel module for testing static keys");
240 MODULE_LICENSE("GPL");
241