xref: /linux/lib/test_static_keys.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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  
invert_key(struct static_key * key)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  
invert_keys(struct test_key * keys,int size)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  
verify_keys(struct test_key * keys,int size,bool invert)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  
test_key_func(old_true_key,static_key_true)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  
test_static_key_exit(void)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