2019-05-29 17:17:56 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-08-03 12:42:57 +03:00
/*
* Kernel module for testing static keys .
*
* Copyright 2015 Akamai Technologies Inc . All Rights Reserved
*
* Authors :
* Jason Baron < jbaron @ akamai . com >
*/
# include <linux/module.h>
# include <linux/jump_label.h>
/* old keys */
struct static_key old_true_key = STATIC_KEY_INIT_TRUE ;
struct static_key old_false_key = STATIC_KEY_INIT_FALSE ;
/* new api */
DEFINE_STATIC_KEY_TRUE ( true_key ) ;
DEFINE_STATIC_KEY_FALSE ( false_key ) ;
/* external */
extern struct static_key base_old_true_key ;
extern struct static_key base_inv_old_true_key ;
extern struct static_key base_old_false_key ;
extern struct static_key base_inv_old_false_key ;
/* new api */
extern struct static_key_true base_true_key ;
extern struct static_key_true base_inv_true_key ;
extern struct static_key_false base_false_key ;
extern struct static_key_false base_inv_false_key ;
struct test_key {
bool init_state ;
struct static_key * key ;
bool ( * test_key ) ( void ) ;
} ;
2016-02-08 17:36:52 +03:00
# define test_key_func(key, branch) \
static bool key # # _ # # branch ( void ) \
{ \
return branch ( & key ) ; \
}
2015-08-03 12:42:57 +03:00
static void invert_key ( struct static_key * key )
{
if ( static_key_enabled ( key ) )
static_key_disable ( key ) ;
else
static_key_enable ( key ) ;
}
static void invert_keys ( struct test_key * keys , int size )
{
struct static_key * previous = NULL ;
int i ;
for ( i = 0 ; i < size ; i + + ) {
if ( previous ! = keys [ i ] . key ) {
invert_key ( keys [ i ] . key ) ;
previous = keys [ i ] . key ;
}
}
}
2015-08-03 21:47:48 +03:00
static int verify_keys ( struct test_key * keys , int size , bool invert )
2015-08-03 12:42:57 +03:00
{
int i ;
bool ret , init ;
for ( i = 0 ; i < size ; i + + ) {
ret = static_key_enabled ( keys [ i ] . key ) ;
init = keys [ i ] . init_state ;
if ( ret ! = ( invert ? ! init : init ) )
return - EINVAL ;
ret = keys [ i ] . test_key ( ) ;
if ( static_key_enabled ( keys [ i ] . key ) ) {
if ( ! ret )
return - EINVAL ;
} else {
if ( ret )
return - EINVAL ;
}
}
return 0 ;
}
2016-02-08 17:36:52 +03:00
test_key_func ( old_true_key , static_key_true )
test_key_func ( old_false_key , static_key_false )
test_key_func ( true_key , static_branch_likely )
test_key_func ( true_key , static_branch_unlikely )
test_key_func ( false_key , static_branch_likely )
test_key_func ( false_key , static_branch_unlikely )
test_key_func ( base_old_true_key , static_key_true )
test_key_func ( base_inv_old_true_key , static_key_true )
test_key_func ( base_old_false_key , static_key_false )
test_key_func ( base_inv_old_false_key , static_key_false )
test_key_func ( base_true_key , static_branch_likely )
test_key_func ( base_true_key , static_branch_unlikely )
test_key_func ( base_inv_true_key , static_branch_likely )
test_key_func ( base_inv_true_key , static_branch_unlikely )
test_key_func ( base_false_key , static_branch_likely )
test_key_func ( base_false_key , static_branch_unlikely )
test_key_func ( base_inv_false_key , static_branch_likely )
test_key_func ( base_inv_false_key , static_branch_unlikely )
2015-08-03 12:42:57 +03:00
static int __init test_static_key_init ( void )
{
int ret ;
int size ;
struct test_key static_key_tests [ ] = {
/* internal keys - old keys */
{
. init_state = true ,
. key = & old_true_key ,
2016-02-08 17:36:52 +03:00
. test_key = & old_true_key_static_key_true ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = false ,
. key = & old_false_key ,
2016-02-08 17:36:52 +03:00
. test_key = & old_false_key_static_key_false ,
2015-08-03 12:42:57 +03:00
} ,
/* internal keys - new keys */
{
. init_state = true ,
. key = & true_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & true_key_static_branch_likely ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = true ,
. key = & true_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & true_key_static_branch_unlikely ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = false ,
. key = & false_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & false_key_static_branch_likely ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = false ,
. key = & false_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & false_key_static_branch_unlikely ,
2015-08-03 12:42:57 +03:00
} ,
/* external keys - old keys */
{
. init_state = true ,
. key = & base_old_true_key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_old_true_key_static_key_true ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = false ,
. key = & base_inv_old_true_key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_inv_old_true_key_static_key_true ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = false ,
. key = & base_old_false_key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_old_false_key_static_key_false ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = true ,
. key = & base_inv_old_false_key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_inv_old_false_key_static_key_false ,
2015-08-03 12:42:57 +03:00
} ,
/* external keys - new keys */
{
. init_state = true ,
. key = & base_true_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_true_key_static_branch_likely ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = true ,
. key = & base_true_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_true_key_static_branch_unlikely ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = false ,
. key = & base_inv_true_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_inv_true_key_static_branch_likely ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = false ,
. key = & base_inv_true_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_inv_true_key_static_branch_unlikely ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = false ,
. key = & base_false_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_false_key_static_branch_likely ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = false ,
. key = & base_false_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_false_key_static_branch_unlikely ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = true ,
. key = & base_inv_false_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_inv_false_key_static_branch_likely ,
2015-08-03 12:42:57 +03:00
} ,
{
. init_state = true ,
. key = & base_inv_false_key . key ,
2016-02-08 17:36:52 +03:00
. test_key = & base_inv_false_key_static_branch_unlikely ,
2015-08-03 12:42:57 +03:00
} ,
} ;
size = ARRAY_SIZE ( static_key_tests ) ;
ret = verify_keys ( static_key_tests , size , false ) ;
if ( ret )
goto out ;
invert_keys ( static_key_tests , size ) ;
ret = verify_keys ( static_key_tests , size , true ) ;
if ( ret )
goto out ;
invert_keys ( static_key_tests , size ) ;
ret = verify_keys ( static_key_tests , size , false ) ;
if ( ret )
goto out ;
return 0 ;
out :
return ret ;
}
static void __exit test_static_key_exit ( void )
{
}
module_init ( test_static_key_init ) ;
module_exit ( test_static_key_exit ) ;
MODULE_AUTHOR ( " Jason Baron <jbaron@akamai.com> " ) ;
2024-06-19 23:59:15 +03:00
MODULE_DESCRIPTION ( " Kernel module for testing static keys " ) ;
2015-08-03 12:42:57 +03:00
MODULE_LICENSE ( " GPL " ) ;