linux/lib/test_static_keys.c
<<
>>
Prefs
   1/*
   2 * Kernel module for testing static keys.
   3 *
   4 * Copyright 2015 Akamai Technologies Inc. All Rights Reserved
   5 *
   6 * Authors:
   7 *      Jason Baron       <jbaron@akamai.com>
   8 *
   9 * This software is licensed under the terms of the GNU General Public
  10 * License version 2, as published by the Free Software Foundation, and
  11 * may be copied, distributed, and modified under those terms.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 */
  18
  19#include <linux/module.h>
  20#include <linux/jump_label.h>
  21
  22/* old keys */
  23struct static_key old_true_key  = STATIC_KEY_INIT_TRUE;
  24struct static_key old_false_key = STATIC_KEY_INIT_FALSE;
  25
  26/* new api */
  27DEFINE_STATIC_KEY_TRUE(true_key);
  28DEFINE_STATIC_KEY_FALSE(false_key);
  29
  30/* external */
  31extern struct static_key base_old_true_key;
  32extern struct static_key base_inv_old_true_key;
  33extern struct static_key base_old_false_key;
  34extern struct static_key base_inv_old_false_key;
  35
  36/* new api */
  37extern struct static_key_true base_true_key;
  38extern struct static_key_true base_inv_true_key;
  39extern struct static_key_false base_false_key;
  40extern struct static_key_false base_inv_false_key;
  41
  42
  43struct test_key {
  44        bool                    init_state;
  45        struct static_key       *key;
  46        bool                    (*test_key)(void);
  47};
  48
  49#define test_key_func(key, branch)      \
  50static bool key ## _ ## branch(void)    \
  51{                                       \
  52        return branch(&key);            \
  53}
  54
  55static void invert_key(struct static_key *key)
  56{
  57        if (static_key_enabled(key))
  58                static_key_disable(key);
  59        else
  60                static_key_enable(key);
  61}
  62
  63static void invert_keys(struct test_key *keys, int size)
  64{
  65        struct static_key *previous = NULL;
  66        int i;
  67
  68        for (i = 0; i < size; i++) {
  69                if (previous != keys[i].key) {
  70                        invert_key(keys[i].key);
  71                        previous = keys[i].key;
  72                }
  73        }
  74}
  75
  76static int verify_keys(struct test_key *keys, int size, bool invert)
  77{
  78        int i;
  79        bool ret, init;
  80
  81        for (i = 0; i < size; i++) {
  82                ret = static_key_enabled(keys[i].key);
  83                init = keys[i].init_state;
  84                if (ret != (invert ? !init : init))
  85                        return -EINVAL;
  86                ret = keys[i].test_key();
  87                if (static_key_enabled(keys[i].key)) {
  88                        if (!ret)
  89                                return -EINVAL;
  90                } else {
  91                        if (ret)
  92                                return -EINVAL;
  93                }
  94        }
  95        return 0;
  96}
  97
  98test_key_func(old_true_key, static_key_true)
  99test_key_func(old_false_key, static_key_false)
 100test_key_func(true_key, static_branch_likely)
 101test_key_func(true_key, static_branch_unlikely)
 102test_key_func(false_key, static_branch_likely)
 103test_key_func(false_key, static_branch_unlikely)
 104test_key_func(base_old_true_key, static_key_true)
 105test_key_func(base_inv_old_true_key, static_key_true)
 106test_key_func(base_old_false_key, static_key_false)
 107test_key_func(base_inv_old_false_key, static_key_false)
 108test_key_func(base_true_key, static_branch_likely)
 109test_key_func(base_true_key, static_branch_unlikely)
 110test_key_func(base_inv_true_key, static_branch_likely)
 111test_key_func(base_inv_true_key, static_branch_unlikely)
 112test_key_func(base_false_key, static_branch_likely)
 113test_key_func(base_false_key, static_branch_unlikely)
 114test_key_func(base_inv_false_key, static_branch_likely)
 115test_key_func(base_inv_false_key, static_branch_unlikely)
 116
 117static int __init test_static_key_init(void)
 118{
 119        int ret;
 120        int size;
 121
 122        struct test_key static_key_tests[] = {
 123                /* internal keys - old keys */
 124                {
 125                        .init_state     = true,
 126                        .key            = &old_true_key,
 127                        .test_key       = &old_true_key_static_key_true,
 128                },
 129                {
 130                        .init_state     = false,
 131                        .key            = &old_false_key,
 132                        .test_key       = &old_false_key_static_key_false,
 133                },
 134                /* internal keys - new keys */
 135                {
 136                        .init_state     = true,
 137                        .key            = &true_key.key,
 138                        .test_key       = &true_key_static_branch_likely,
 139                },
 140                {
 141                        .init_state     = true,
 142                        .key            = &true_key.key,
 143                        .test_key       = &true_key_static_branch_unlikely,
 144                },
 145                {
 146                        .init_state     = false,
 147                        .key            = &false_key.key,
 148                        .test_key       = &false_key_static_branch_likely,
 149                },
 150                {
 151                        .init_state     = false,
 152                        .key            = &false_key.key,
 153                        .test_key       = &false_key_static_branch_unlikely,
 154                },
 155                /* external keys - old keys */
 156                {
 157                        .init_state     = true,
 158                        .key            = &base_old_true_key,
 159                        .test_key       = &base_old_true_key_static_key_true,
 160                },
 161                {
 162                        .init_state     = false,
 163                        .key            = &base_inv_old_true_key,
 164                        .test_key       = &base_inv_old_true_key_static_key_true,
 165                },
 166                {
 167                        .init_state     = false,
 168                        .key            = &base_old_false_key,
 169                        .test_key       = &base_old_false_key_static_key_false,
 170                },
 171                {
 172                        .init_state     = true,
 173                        .key            = &base_inv_old_false_key,
 174                        .test_key       = &base_inv_old_false_key_static_key_false,
 175                },
 176                /* external keys - new keys */
 177                {
 178                        .init_state     = true,
 179                        .key            = &base_true_key.key,
 180                        .test_key       = &base_true_key_static_branch_likely,
 181                },
 182                {
 183                        .init_state     = true,
 184                        .key            = &base_true_key.key,
 185                        .test_key       = &base_true_key_static_branch_unlikely,
 186                },
 187                {
 188                        .init_state     = false,
 189                        .key            = &base_inv_true_key.key,
 190                        .test_key       = &base_inv_true_key_static_branch_likely,
 191                },
 192                {
 193                        .init_state     = false,
 194                        .key            = &base_inv_true_key.key,
 195                        .test_key       = &base_inv_true_key_static_branch_unlikely,
 196                },
 197                {
 198                        .init_state     = false,
 199                        .key            = &base_false_key.key,
 200                        .test_key       = &base_false_key_static_branch_likely,
 201                },
 202                {
 203                        .init_state     = false,
 204                        .key            = &base_false_key.key,
 205                        .test_key       = &base_false_key_static_branch_unlikely,
 206                },
 207                {
 208                        .init_state     = true,
 209                        .key            = &base_inv_false_key.key,
 210                        .test_key       = &base_inv_false_key_static_branch_likely,
 211                },
 212                {
 213                        .init_state     = true,
 214                        .key            = &base_inv_false_key.key,
 215                        .test_key       = &base_inv_false_key_static_branch_unlikely,
 216                },
 217        };
 218
 219        size = ARRAY_SIZE(static_key_tests);
 220
 221        ret = verify_keys(static_key_tests, size, false);
 222        if (ret)
 223                goto out;
 224
 225        invert_keys(static_key_tests, size);
 226        ret = verify_keys(static_key_tests, size, true);
 227        if (ret)
 228                goto out;
 229
 230        invert_keys(static_key_tests, size);
 231        ret = verify_keys(static_key_tests, size, false);
 232        if (ret)
 233                goto out;
 234        return 0;
 235out:
 236        return ret;
 237}
 238
 239static void __exit test_static_key_exit(void)
 240{
 241}
 242
 243module_init(test_static_key_init);
 244module_exit(test_static_key_exit);
 245
 246MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>");
 247MODULE_LICENSE("GPL");
 248