241 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Kernel module for testing static keys.4 *5 * Copyright 2015 Akamai Technologies Inc. All Rights Reserved6 *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 else52 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(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(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;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_DESCRIPTION("Kernel module for testing static keys");240MODULE_LICENSE("GPL");241