2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-01-29 17:40:25 +03:00
/*
* Resizable , Scalable , Concurrent Hash Table
*
2015-05-01 01:37:41 +03:00
* Copyright ( c ) 2014 - 2015 Thomas Graf < tgraf @ suug . ch >
2015-01-29 17:40:25 +03:00
* Copyright ( c ) 2008 - 2014 Patrick McHardy < kaber @ trash . net >
*/
/**************************************************************************
* Self Test
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/init.h>
# include <linux/jhash.h>
# include <linux/kernel.h>
2015-08-15 01:37:15 +03:00
# include <linux/kthread.h>
2015-01-29 17:40:25 +03:00
# include <linux/module.h>
# include <linux/rcupdate.h>
# include <linux/rhashtable.h>
# include <linux/slab.h>
2015-07-17 11:52:48 +03:00
# include <linux/sched.h>
2017-09-20 02:12:14 +03:00
# include <linux/random.h>
2015-08-15 01:37:15 +03:00
# include <linux/vmalloc.h>
2018-12-16 22:48:21 +03:00
# include <linux/wait.h>
2015-01-29 17:40:25 +03:00
2015-05-01 01:37:41 +03:00
# define MAX_ENTRIES 1000000
2015-05-01 01:37:45 +03:00
# define TEST_INSERT_FAIL INT_MAX
2015-05-01 01:37:41 +03:00
2017-09-20 02:12:12 +03:00
static int parm_entries = 50000 ;
module_param ( parm_entries , int , 0 ) ;
MODULE_PARM_DESC ( parm_entries , " Number of entries to add (default: 50000) " ) ;
2015-05-01 01:37:41 +03:00
static int runs = 4 ;
module_param ( runs , int , 0 ) ;
MODULE_PARM_DESC ( runs , " Number of test runs per variant (default: 4) " ) ;
2015-11-20 20:17:19 +03:00
static int max_size = 0 ;
2015-05-01 01:37:41 +03:00
module_param ( max_size , int , 0 ) ;
2016-08-04 13:37:17 +03:00
MODULE_PARM_DESC ( max_size , " Maximum table size (default: calculated) " ) ;
2015-05-01 01:37:41 +03:00
static bool shrinking = false ;
module_param ( shrinking , bool , 0 ) ;
MODULE_PARM_DESC ( shrinking , " Enable automatic shrinking (default: off) " ) ;
static int size = 8 ;
module_param ( size , int , 0 ) ;
MODULE_PARM_DESC ( size , " Initial size hint of table (default: 8) " ) ;
2015-01-29 17:40:25 +03:00
2015-08-15 01:37:15 +03:00
static int tcount = 10 ;
module_param ( tcount , int , 0 ) ;
MODULE_PARM_DESC ( tcount , " Number of threads to spawn (default: 10) " ) ;
2015-11-20 20:17:20 +03:00
static bool enomem_retry = false ;
module_param ( enomem_retry , bool , 0 ) ;
MODULE_PARM_DESC ( enomem_retry , " Retry insert even if -ENOMEM was returned (default: off) " ) ;
2017-07-21 17:51:31 +03:00
struct test_obj_val {
int id ;
int tid ;
} ;
2015-01-29 17:40:25 +03:00
struct test_obj {
2017-07-21 17:51:31 +03:00
struct test_obj_val value ;
2015-01-29 17:40:25 +03:00
struct rhash_head node ;
} ;
2017-09-20 02:12:14 +03:00
struct test_obj_rhl {
struct test_obj_val value ;
struct rhlist_head list_node ;
} ;
2015-08-15 01:37:15 +03:00
struct thread_data {
2017-09-20 02:12:12 +03:00
unsigned int entries ;
2015-08-15 01:37:15 +03:00
int id ;
struct task_struct * task ;
struct test_obj * objs ;
} ;
2018-03-04 18:29:49 +03:00
static u32 my_hashfn ( const void * data , u32 len , u32 seed )
{
const struct test_obj_rhl * obj = data ;
2018-06-18 05:52:50 +03:00
return ( obj - > value . id % 10 ) ;
2018-03-04 18:29:49 +03:00
}
static int my_cmpfn ( struct rhashtable_compare_arg * arg , const void * obj )
{
const struct test_obj_rhl * test_obj = obj ;
const struct test_obj_val * val = arg - > key ;
return test_obj - > value . id - val - > id ;
}
2015-05-01 01:37:41 +03:00
static struct rhashtable_params test_rht_params = {
2015-03-20 13:57:04 +03:00
. head_offset = offsetof ( struct test_obj , node ) ,
. key_offset = offsetof ( struct test_obj , value ) ,
2017-07-21 17:51:31 +03:00
. key_len = sizeof ( struct test_obj_val ) ,
2015-03-20 13:57:04 +03:00
. hashfn = jhash ,
} ;
2018-03-04 18:29:49 +03:00
static struct rhashtable_params test_rht_params_dup = {
. head_offset = offsetof ( struct test_obj_rhl , list_node ) ,
. key_offset = offsetof ( struct test_obj_rhl , value ) ,
. key_len = sizeof ( struct test_obj_val ) ,
. hashfn = jhash ,
. obj_hashfn = my_hashfn ,
. obj_cmpfn = my_cmpfn ,
. nelem_hint = 128 ,
. automatic_shrinking = false ,
} ;
2018-12-16 22:48:21 +03:00
static atomic_t startup_count ;
static DECLARE_WAIT_QUEUE_HEAD ( startup_wait ) ;
2015-08-15 01:37:15 +03:00
2017-09-20 02:12:11 +03:00
static int insert_retry ( struct rhashtable * ht , struct test_obj * obj ,
2015-11-20 20:17:18 +03:00
const struct rhashtable_params params )
{
2015-11-20 20:17:20 +03:00
int err , retries = - 1 , enomem_retries = 0 ;
2015-11-20 20:17:18 +03:00
do {
retries + + ;
cond_resched ( ) ;
2017-09-20 02:12:11 +03:00
err = rhashtable_insert_fast ( ht , & obj - > node , params ) ;
2015-11-20 20:17:20 +03:00
if ( err = = - ENOMEM & & enomem_retry ) {
enomem_retries + + ;
err = - EBUSY ;
}
2015-11-20 20:17:18 +03:00
} while ( err = = - EBUSY ) ;
2015-11-20 20:17:20 +03:00
if ( enomem_retries )
pr_info ( " %u insertions retried after -ENOMEM \n " ,
enomem_retries ) ;
2015-11-20 20:17:18 +03:00
return err ? : retries ;
}
2017-09-20 02:12:12 +03:00
static int __init test_rht_lookup ( struct rhashtable * ht , struct test_obj * array ,
unsigned int entries )
2015-01-29 17:40:25 +03:00
{
unsigned int i ;
2017-09-20 02:12:12 +03:00
for ( i = 0 ; i < entries ; i + + ) {
2015-01-29 17:40:25 +03:00
struct test_obj * obj ;
bool expected = ! ( i % 2 ) ;
2017-07-21 17:51:31 +03:00
struct test_obj_val key = {
. id = i ,
} ;
2015-01-29 17:40:25 +03:00
2017-07-21 17:51:31 +03:00
if ( array [ i / 2 ] . value . id = = TEST_INSERT_FAIL )
2015-05-01 01:37:45 +03:00
expected = false ;
2015-03-20 13:57:04 +03:00
obj = rhashtable_lookup_fast ( ht , & key , test_rht_params ) ;
2015-01-29 17:40:25 +03:00
if ( expected & & ! obj ) {
2017-07-21 17:51:31 +03:00
pr_warn ( " Test failed: Could not find key %u \n " , key . id ) ;
2015-01-29 17:40:25 +03:00
return - ENOENT ;
} else if ( ! expected & & obj ) {
pr_warn ( " Test failed: Unexpected entry found for key %u \n " ,
2017-07-21 17:51:31 +03:00
key . id ) ;
2015-01-29 17:40:25 +03:00
return - EEXIST ;
} else if ( expected & & obj ) {
2017-07-21 17:51:31 +03:00
if ( obj - > value . id ! = i ) {
2015-05-01 01:37:42 +03:00
pr_warn ( " Test failed: Lookup value mismatch %u!=%u \n " ,
2017-07-21 17:51:31 +03:00
obj - > value . id , i ) ;
2015-01-29 17:40:25 +03:00
return - EINVAL ;
}
}
2015-07-17 11:52:48 +03:00
cond_resched_rcu ( ) ;
2015-01-29 17:40:25 +03:00
}
return 0 ;
}
2017-09-20 02:12:12 +03:00
static void test_bucket_stats ( struct rhashtable * ht , unsigned int entries )
2015-01-29 17:40:25 +03:00
{
2019-02-14 17:03:27 +03:00
unsigned int total = 0 , chain_len = 0 ;
2015-05-01 01:37:44 +03:00
struct rhashtable_iter hti ;
2015-01-29 17:40:25 +03:00
struct rhash_head * pos ;
2019-02-14 17:03:27 +03:00
rhashtable_walk_enter ( ht , & hti ) ;
2017-12-04 21:31:41 +03:00
rhashtable_walk_start ( & hti ) ;
2015-01-29 17:40:25 +03:00
2015-05-01 01:37:44 +03:00
while ( ( pos = rhashtable_walk_next ( & hti ) ) ) {
if ( PTR_ERR ( pos ) = = - EAGAIN ) {
pr_info ( " Info: encountered resize \n " ) ;
chain_len + + ;
continue ;
} else if ( IS_ERR ( pos ) ) {
pr_warn ( " Test failed: rhashtable_walk_next() error: %ld \n " ,
PTR_ERR ( pos ) ) ;
break ;
2015-01-29 17:40:25 +03:00
}
2015-05-01 01:37:44 +03:00
total + + ;
2015-01-29 17:40:25 +03:00
}
2015-05-01 01:37:44 +03:00
rhashtable_walk_stop ( & hti ) ;
rhashtable_walk_exit ( & hti ) ;
pr_info ( " Traversal complete: counted=%u, nelems=%u, entries=%d, table-jumps=%u \n " ,
total , atomic_read ( & ht - > nelems ) , entries , chain_len ) ;
2015-01-29 17:40:25 +03:00
2015-05-01 01:37:41 +03:00
if ( total ! = atomic_read ( & ht - > nelems ) | | total ! = entries )
2015-01-29 17:40:25 +03:00
pr_warn ( " Test failed: Total count mismatch ^^^ " ) ;
}
2017-09-20 02:12:12 +03:00
static s64 __init test_rhashtable ( struct rhashtable * ht , struct test_obj * array ,
unsigned int entries )
2015-01-29 17:40:25 +03:00
{
struct test_obj * obj ;
int err ;
2015-11-20 20:17:18 +03:00
unsigned int i , insert_retries = 0 ;
2015-05-01 01:37:41 +03:00
s64 start , end ;
2015-01-29 17:40:25 +03:00
/*
* Insertion Test :
2015-05-01 01:37:41 +03:00
* Insert entries into table with all keys even numbers
2015-01-29 17:40:25 +03:00
*/
2015-05-01 01:37:41 +03:00
pr_info ( " Adding %d keys \n " , entries ) ;
start = ktime_get_ns ( ) ;
for ( i = 0 ; i < entries ; i + + ) {
2015-05-01 01:37:43 +03:00
struct test_obj * obj = & array [ i ] ;
2015-01-29 17:40:25 +03:00
2017-07-21 17:51:31 +03:00
obj - > value . id = i * 2 ;
2017-09-20 02:12:11 +03:00
err = insert_retry ( ht , obj , test_rht_params ) ;
2015-11-20 20:17:18 +03:00
if ( err > 0 )
insert_retries + = err ;
else if ( err )
2015-05-01 01:37:43 +03:00
return err ;
2015-01-29 17:40:25 +03:00
}
2015-11-20 20:17:18 +03:00
if ( insert_retries )
pr_info ( " %u insertions retried due to memory pressure \n " ,
insert_retries ) ;
2015-05-01 01:37:45 +03:00
2017-09-20 02:12:12 +03:00
test_bucket_stats ( ht , entries ) ;
2015-01-29 17:40:25 +03:00
rcu_read_lock ( ) ;
2017-09-20 02:12:12 +03:00
test_rht_lookup ( ht , array , entries ) ;
2015-01-29 17:40:25 +03:00
rcu_read_unlock ( ) ;
2017-09-20 02:12:12 +03:00
test_bucket_stats ( ht , entries ) ;
2015-01-29 17:40:25 +03:00
2015-05-01 01:37:41 +03:00
pr_info ( " Deleting %d keys \n " , entries ) ;
for ( i = 0 ; i < entries ; i + + ) {
2017-07-25 14:36:21 +03:00
struct test_obj_val key = {
. id = i * 2 ,
} ;
2015-01-29 17:40:25 +03:00
2017-07-21 17:51:31 +03:00
if ( array [ i ] . value . id ! = TEST_INSERT_FAIL ) {
2015-05-01 01:37:45 +03:00
obj = rhashtable_lookup_fast ( ht , & key , test_rht_params ) ;
BUG_ON ( ! obj ) ;
2015-01-29 17:40:25 +03:00
2015-05-01 01:37:45 +03:00
rhashtable_remove_fast ( ht , & obj - > node , test_rht_params ) ;
}
2015-07-17 11:52:48 +03:00
cond_resched ( ) ;
2015-01-29 17:40:25 +03:00
}
2015-05-01 01:37:41 +03:00
end = ktime_get_ns ( ) ;
pr_info ( " Duration of test: %lld ns \n " , end - start ) ;
return end - start ;
2015-01-29 17:40:25 +03:00
}
rhashtable: don't allocate ht structure on stack in test_rht_init
With object runtime debugging enabled, the rhashtable test suite
will rightfully throw a warning "ODEBUG: object is on stack, but
not annotated" from rhashtable_init().
This is because run_work is (correctly) being initialized via
INIT_WORK(), and not annotated by INIT_WORK_ONSTACK(). Meaning,
rhashtable_init() is okay as is, we just need to move ht e.g.,
into global scope.
It never triggered anything, since test_rhashtable is rather a
controlled environment and effectively runs to completion, so
that stack memory is not vanishing underneath us, we shouldn't
confuse any testers with it though.
Fixes: 7e1e77636e36 ("lib: Resizable, Scalable, Concurrent Hash Table")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-02-20 23:14:21 +03:00
static struct rhashtable ht ;
2017-09-21 18:36:08 +03:00
static struct rhltable rhlt ;
2017-09-20 02:12:14 +03:00
static int __init test_rhltable ( unsigned int entries )
{
struct test_obj_rhl * rhl_test_objects ;
unsigned long * obj_in_table ;
unsigned int i , j , k ;
int ret , err ;
if ( entries = = 0 )
entries = 1 ;
treewide: Use array_size() in vzalloc()
The vzalloc() function has no 2-factor argument form, so multiplication
factors need to be wrapped in array_size(). This patch replaces cases of:
vzalloc(a * b)
with:
vzalloc(array_size(a, b))
as well as handling cases of:
vzalloc(a * b * c)
with:
vzalloc(array3_size(a, b, c))
This does, however, attempt to ignore constant size factors like:
vzalloc(4 * 1024)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
vzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
vzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
vzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
vzalloc(
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
vzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
vzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
vzalloc(C1 * C2 * C3, ...)
|
vzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression E1, E2;
constant C1, C2;
@@
(
vzalloc(C1 * C2, ...)
|
vzalloc(
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:27:37 +03:00
rhl_test_objects = vzalloc ( array_size ( entries ,
sizeof ( * rhl_test_objects ) ) ) ;
2017-09-20 02:12:14 +03:00
if ( ! rhl_test_objects )
return - ENOMEM ;
ret = - ENOMEM ;
treewide: Use array_size() in vzalloc()
The vzalloc() function has no 2-factor argument form, so multiplication
factors need to be wrapped in array_size(). This patch replaces cases of:
vzalloc(a * b)
with:
vzalloc(array_size(a, b))
as well as handling cases of:
vzalloc(a * b * c)
with:
vzalloc(array3_size(a, b, c))
This does, however, attempt to ignore constant size factors like:
vzalloc(4 * 1024)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
vzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
vzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
vzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
vzalloc(
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
vzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
vzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
vzalloc(C1 * C2 * C3, ...)
|
vzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression E1, E2;
constant C1, C2;
@@
(
vzalloc(C1 * C2, ...)
|
vzalloc(
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:27:37 +03:00
obj_in_table = vzalloc ( array_size ( sizeof ( unsigned long ) ,
BITS_TO_LONGS ( entries ) ) ) ;
2017-09-20 02:12:14 +03:00
if ( ! obj_in_table )
goto out_free ;
err = rhltable_init ( & rhlt , & test_rht_params ) ;
if ( WARN_ON ( err ) )
goto out_free ;
k = prandom_u32 ( ) ;
ret = 0 ;
for ( i = 0 ; i < entries ; i + + ) {
rhl_test_objects [ i ] . value . id = k ;
err = rhltable_insert ( & rhlt , & rhl_test_objects [ i ] . list_node ,
test_rht_params ) ;
if ( WARN ( err , " error %d on element %d \n " , err , i ) )
break ;
if ( err = = 0 )
set_bit ( i , obj_in_table ) ;
}
if ( err )
ret = err ;
pr_info ( " test %d add/delete pairs into rhlist \n " , entries ) ;
for ( i = 0 ; i < entries ; i + + ) {
struct rhlist_head * h , * pos ;
struct test_obj_rhl * obj ;
struct test_obj_val key = {
. id = k ,
} ;
bool found ;
rcu_read_lock ( ) ;
h = rhltable_lookup ( & rhlt , & key , test_rht_params ) ;
if ( WARN ( ! h , " key not found during iteration %d of %d " , i , entries ) ) {
rcu_read_unlock ( ) ;
break ;
}
if ( i ) {
j = i - 1 ;
rhl_for_each_entry_rcu ( obj , pos , h , list_node ) {
if ( WARN ( pos = = & rhl_test_objects [ j ] . list_node , " old element found, should be gone " ) )
break ;
}
}
cond_resched_rcu ( ) ;
found = false ;
rhl_for_each_entry_rcu ( obj , pos , h , list_node ) {
if ( pos = = & rhl_test_objects [ i ] . list_node ) {
found = true ;
break ;
}
}
rcu_read_unlock ( ) ;
if ( WARN ( ! found , " element %d not found " , i ) )
break ;
err = rhltable_remove ( & rhlt , & rhl_test_objects [ i ] . list_node , test_rht_params ) ;
WARN ( err , " rhltable_remove: err %d for iteration %d \n " , err , i ) ;
if ( err = = 0 )
clear_bit ( i , obj_in_table ) ;
}
if ( ret = = 0 & & err )
ret = err ;
for ( i = 0 ; i < entries ; i + + ) {
WARN ( test_bit ( i , obj_in_table ) , " elem %d allegedly still present " , i ) ;
err = rhltable_insert ( & rhlt , & rhl_test_objects [ i ] . list_node ,
test_rht_params ) ;
if ( WARN ( err , " error %d on element %d \n " , err , i ) )
break ;
if ( err = = 0 )
set_bit ( i , obj_in_table ) ;
}
pr_info ( " test %d random rhlist add/delete operations \n " , entries ) ;
for ( j = 0 ; j < entries ; j + + ) {
u32 i = prandom_u32_max ( entries ) ;
u32 prand = prandom_u32 ( ) ;
cond_resched ( ) ;
if ( prand = = 0 )
prand = prandom_u32 ( ) ;
if ( prand & 1 ) {
prand > > = 1 ;
continue ;
}
err = rhltable_remove ( & rhlt , & rhl_test_objects [ i ] . list_node , test_rht_params ) ;
if ( test_bit ( i , obj_in_table ) ) {
clear_bit ( i , obj_in_table ) ;
if ( WARN ( err , " cannot remove element at slot %d " , i ) )
continue ;
} else {
2019-02-18 01:52:09 +03:00
if ( WARN ( err ! = - ENOENT , " removed non-existent element %d, error %d not %d " ,
2017-09-20 02:12:14 +03:00
i , err , - ENOENT ) )
continue ;
}
if ( prand & 1 ) {
prand > > = 1 ;
continue ;
}
err = rhltable_insert ( & rhlt , & rhl_test_objects [ i ] . list_node , test_rht_params ) ;
if ( err = = 0 ) {
if ( WARN ( test_and_set_bit ( i , obj_in_table ) , " succeeded to insert same object %d " , i ) )
continue ;
} else {
if ( WARN ( ! test_bit ( i , obj_in_table ) , " failed to insert object %d " , i ) )
continue ;
}
if ( prand & 1 ) {
prand > > = 1 ;
continue ;
}
i = prandom_u32_max ( entries ) ;
if ( test_bit ( i , obj_in_table ) ) {
err = rhltable_remove ( & rhlt , & rhl_test_objects [ i ] . list_node , test_rht_params ) ;
WARN ( err , " cannot remove element at slot %d " , i ) ;
if ( err = = 0 )
clear_bit ( i , obj_in_table ) ;
} else {
err = rhltable_insert ( & rhlt , & rhl_test_objects [ i ] . list_node , test_rht_params ) ;
WARN ( err , " failed to insert object %d " , i ) ;
if ( err = = 0 )
set_bit ( i , obj_in_table ) ;
}
}
for ( i = 0 ; i < entries ; i + + ) {
cond_resched ( ) ;
err = rhltable_remove ( & rhlt , & rhl_test_objects [ i ] . list_node , test_rht_params ) ;
if ( test_bit ( i , obj_in_table ) ) {
if ( WARN ( err , " cannot remove element at slot %d " , i ) )
continue ;
} else {
2019-02-18 01:52:09 +03:00
if ( WARN ( err ! = - ENOENT , " removed non-existent element, error %d not %d " ,
2017-09-20 02:12:14 +03:00
err , - ENOENT ) )
2020-09-19 00:51:26 +03:00
continue ;
2017-09-20 02:12:14 +03:00
}
}
rhltable_destroy ( & rhlt ) ;
out_free :
vfree ( rhl_test_objects ) ;
vfree ( obj_in_table ) ;
return ret ;
}
rhashtable: don't allocate ht structure on stack in test_rht_init
With object runtime debugging enabled, the rhashtable test suite
will rightfully throw a warning "ODEBUG: object is on stack, but
not annotated" from rhashtable_init().
This is because run_work is (correctly) being initialized via
INIT_WORK(), and not annotated by INIT_WORK_ONSTACK(). Meaning,
rhashtable_init() is okay as is, we just need to move ht e.g.,
into global scope.
It never triggered anything, since test_rhashtable is rather a
controlled environment and effectively runs to completion, so
that stack memory is not vanishing underneath us, we shouldn't
confuse any testers with it though.
Fixes: 7e1e77636e36 ("lib: Resizable, Scalable, Concurrent Hash Table")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-02-20 23:14:21 +03:00
2017-09-20 02:12:13 +03:00
static int __init test_rhashtable_max ( struct test_obj * array ,
unsigned int entries )
{
unsigned int i , insert_retries = 0 ;
int err ;
test_rht_params . max_size = roundup_pow_of_two ( entries / 8 ) ;
err = rhashtable_init ( & ht , & test_rht_params ) ;
if ( err )
return err ;
for ( i = 0 ; i < ht . max_elems ; i + + ) {
struct test_obj * obj = & array [ i ] ;
obj - > value . id = i * 2 ;
err = insert_retry ( & ht , obj , test_rht_params ) ;
if ( err > 0 )
insert_retries + = err ;
else if ( err )
return err ;
}
err = insert_retry ( & ht , & array [ ht . max_elems ] , test_rht_params ) ;
if ( err = = - E2BIG ) {
err = 0 ;
} else {
pr_info ( " insert element %u should have failed with %d, got %d \n " ,
ht . max_elems , - E2BIG , err ) ;
if ( err = = 0 )
err = - 1 ;
}
rhashtable_destroy ( & ht ) ;
return err ;
}
2018-03-04 18:29:49 +03:00
static unsigned int __init print_ht ( struct rhltable * rhlt )
{
struct rhashtable * ht ;
const struct bucket_table * tbl ;
char buff [ 512 ] = " " ;
2021-03-23 16:03:32 +03:00
int offset = 0 ;
2018-03-04 18:29:49 +03:00
unsigned int i , cnt = 0 ;
ht = & rhlt - > ht ;
2018-06-18 05:52:50 +03:00
/* Take the mutex to avoid RCU warning */
mutex_lock ( & ht - > mutex ) ;
2018-03-04 18:29:49 +03:00
tbl = rht_dereference ( ht - > tbl , ht ) ;
for ( i = 0 ; i < tbl - > size ; i + + ) {
struct rhash_head * pos , * next ;
struct test_obj_rhl * p ;
2019-04-12 04:52:08 +03:00
pos = rht_ptr_exclusive ( tbl - > buckets + i ) ;
2018-03-04 18:29:49 +03:00
next = ! rht_is_a_nulls ( pos ) ? rht_dereference ( pos - > next , ht ) : NULL ;
if ( ! rht_is_a_nulls ( pos ) ) {
2021-03-23 16:03:32 +03:00
offset + = sprintf ( buff + offset , " \n bucket[%d] -> " , i ) ;
2018-03-04 18:29:49 +03:00
}
while ( ! rht_is_a_nulls ( pos ) ) {
struct rhlist_head * list = container_of ( pos , struct rhlist_head , rhead ) ;
2021-03-23 16:03:32 +03:00
offset + = sprintf ( buff + offset , " [[ " ) ;
2018-03-04 18:29:49 +03:00
do {
pos = & list - > rhead ;
list = rht_dereference ( list - > next , ht ) ;
p = rht_obj ( ht , pos ) ;
2021-03-23 16:03:32 +03:00
offset + = sprintf ( buff + offset , " val %d (tid=%d)%s " , p - > value . id , p - > value . tid ,
2018-03-04 18:29:49 +03:00
list ? " , " : " " ) ;
cnt + + ;
} while ( list ) ;
pos = next ,
next = ! rht_is_a_nulls ( pos ) ?
rht_dereference ( pos - > next , ht ) : NULL ;
2021-03-23 16:03:32 +03:00
offset + = sprintf ( buff + offset , " ]]%s " , ! rht_is_a_nulls ( pos ) ? " -> " : " " ) ;
2018-03-04 18:29:49 +03:00
}
}
printk ( KERN_ERR " \n ---- ht: ----%s \n ------------- \n " , buff ) ;
2018-06-18 05:52:50 +03:00
mutex_unlock ( & ht - > mutex ) ;
2018-03-04 18:29:49 +03:00
return cnt ;
}
static int __init test_insert_dup ( struct test_obj_rhl * rhl_test_objects ,
int cnt , bool slow )
{
2019-01-30 21:42:30 +03:00
struct rhltable * rhlt ;
2018-03-04 18:29:49 +03:00
unsigned int i , ret ;
const char * key ;
int err = 0 ;
2019-01-30 21:42:30 +03:00
rhlt = kmalloc ( sizeof ( * rhlt ) , GFP_KERNEL ) ;
if ( WARN_ON ( ! rhlt ) )
return - EINVAL ;
err = rhltable_init ( rhlt , & test_rht_params_dup ) ;
if ( WARN_ON ( err ) ) {
kfree ( rhlt ) ;
2018-03-04 18:29:49 +03:00
return err ;
2019-01-30 21:42:30 +03:00
}
2018-03-04 18:29:49 +03:00
for ( i = 0 ; i < cnt ; i + + ) {
rhl_test_objects [ i ] . value . tid = i ;
2019-01-30 21:42:30 +03:00
key = rht_obj ( & rhlt - > ht , & rhl_test_objects [ i ] . list_node . rhead ) ;
2018-03-04 18:29:49 +03:00
key + = test_rht_params_dup . key_offset ;
if ( slow ) {
2019-01-30 21:42:30 +03:00
err = PTR_ERR ( rhashtable_insert_slow ( & rhlt - > ht , key ,
2018-03-04 18:29:49 +03:00
& rhl_test_objects [ i ] . list_node . rhead ) ) ;
if ( err = = - EAGAIN )
err = 0 ;
} else
2019-01-30 21:42:30 +03:00
err = rhltable_insert ( rhlt ,
2018-03-04 18:29:49 +03:00
& rhl_test_objects [ i ] . list_node ,
test_rht_params_dup ) ;
if ( WARN ( err , " error %d on element %d/%d (%s) \n " , err , i , cnt , slow ? " slow " : " fast " ) )
goto skip_print ;
}
2019-01-30 21:42:30 +03:00
ret = print_ht ( rhlt ) ;
2018-03-04 18:29:49 +03:00
WARN ( ret ! = cnt , " missing rhltable elements (%d != %d, %s) \n " , ret , cnt , slow ? " slow " : " fast " ) ;
skip_print :
2019-01-30 21:42:30 +03:00
rhltable_destroy ( rhlt ) ;
kfree ( rhlt ) ;
2018-03-04 18:29:49 +03:00
return 0 ;
}
static int __init test_insert_duplicates_run ( void )
{
struct test_obj_rhl rhl_test_objects [ 3 ] = { } ;
pr_info ( " test inserting duplicates \n " ) ;
/* two different values that map to same bucket */
rhl_test_objects [ 0 ] . value . id = 1 ;
rhl_test_objects [ 1 ] . value . id = 21 ;
/* and another duplicate with same as [0] value
* which will be second on the bucket list */
rhl_test_objects [ 2 ] . value . id = rhl_test_objects [ 0 ] . value . id ;
test_insert_dup ( rhl_test_objects , 2 , false ) ;
test_insert_dup ( rhl_test_objects , 3 , false ) ;
test_insert_dup ( rhl_test_objects , 2 , true ) ;
test_insert_dup ( rhl_test_objects , 3 , true ) ;
return 0 ;
}
2015-08-15 01:37:15 +03:00
static int thread_lookup_test ( struct thread_data * tdata )
{
2017-09-20 02:12:12 +03:00
unsigned int entries = tdata - > entries ;
2015-08-15 01:37:15 +03:00
int i , err = 0 ;
for ( i = 0 ; i < entries ; i + + ) {
struct test_obj * obj ;
2017-07-21 17:51:31 +03:00
struct test_obj_val key = {
. id = i ,
. tid = tdata - > id ,
} ;
2015-08-15 01:37:15 +03:00
obj = rhashtable_lookup_fast ( & ht , & key , test_rht_params ) ;
2017-07-21 17:51:31 +03:00
if ( obj & & ( tdata - > objs [ i ] . value . id = = TEST_INSERT_FAIL ) ) {
pr_err ( " found unexpected object %d-%d \n " , key . tid , key . id ) ;
2015-08-15 01:37:15 +03:00
err + + ;
2017-07-21 17:51:31 +03:00
} else if ( ! obj & & ( tdata - > objs [ i ] . value . id ! = TEST_INSERT_FAIL ) ) {
pr_err ( " object %d-%d not found! \n " , key . tid , key . id ) ;
2015-08-15 01:37:15 +03:00
err + + ;
2017-07-21 17:51:31 +03:00
} else if ( obj & & memcmp ( & obj - > value , & key , sizeof ( key ) ) ) {
pr_err ( " wrong object returned (got %d-%d, expected %d-%d) \n " ,
obj - > value . tid , obj - > value . id , key . tid , key . id ) ;
2015-08-15 01:37:15 +03:00
err + + ;
}
2015-11-20 20:17:17 +03:00
cond_resched ( ) ;
2015-08-15 01:37:15 +03:00
}
return err ;
}
static int threadfunc ( void * data )
{
2015-11-20 20:17:18 +03:00
int i , step , err = 0 , insert_retries = 0 ;
2015-08-15 01:37:15 +03:00
struct thread_data * tdata = data ;
2018-12-16 22:48:21 +03:00
if ( atomic_dec_and_test ( & startup_count ) )
wake_up ( & startup_wait ) ;
if ( wait_event_interruptible ( startup_wait , atomic_read ( & startup_count ) = = - 1 ) ) {
pr_err ( " thread[%d]: interrupted \n " , tdata - > id ) ;
goto out ;
}
2015-08-15 01:37:15 +03:00
2017-09-20 02:12:12 +03:00
for ( i = 0 ; i < tdata - > entries ; i + + ) {
2017-07-21 17:51:31 +03:00
tdata - > objs [ i ] . value . id = i ;
tdata - > objs [ i ] . value . tid = tdata - > id ;
2017-09-20 02:12:11 +03:00
err = insert_retry ( & ht , & tdata - > objs [ i ] , test_rht_params ) ;
2015-11-20 20:17:18 +03:00
if ( err > 0 ) {
insert_retries + = err ;
2015-08-15 01:37:15 +03:00
} else if ( err ) {
pr_err ( " thread[%d]: rhashtable_insert_fast failed \n " ,
tdata - > id ) ;
goto out ;
}
}
2015-11-20 20:17:18 +03:00
if ( insert_retries )
pr_info ( " thread[%d]: %u insertions retried due to memory pressure \n " ,
tdata - > id , insert_retries ) ;
2015-08-15 01:37:15 +03:00
err = thread_lookup_test ( tdata ) ;
if ( err ) {
pr_err ( " thread[%d]: rhashtable_lookup_test failed \n " ,
tdata - > id ) ;
goto out ;
}
for ( step = 10 ; step > 0 ; step - - ) {
2017-09-20 02:12:12 +03:00
for ( i = 0 ; i < tdata - > entries ; i + = step ) {
2017-07-21 17:51:31 +03:00
if ( tdata - > objs [ i ] . value . id = = TEST_INSERT_FAIL )
2015-08-15 01:37:15 +03:00
continue ;
err = rhashtable_remove_fast ( & ht , & tdata - > objs [ i ] . node ,
test_rht_params ) ;
if ( err ) {
pr_err ( " thread[%d]: rhashtable_remove_fast failed \n " ,
tdata - > id ) ;
goto out ;
}
2017-07-21 17:51:31 +03:00
tdata - > objs [ i ] . value . id = TEST_INSERT_FAIL ;
2015-11-20 20:17:17 +03:00
cond_resched ( ) ;
2015-08-15 01:37:15 +03:00
}
err = thread_lookup_test ( tdata ) ;
if ( err ) {
pr_err ( " thread[%d]: rhashtable_lookup_test (2) failed \n " ,
tdata - > id ) ;
goto out ;
}
}
out :
while ( ! kthread_should_stop ( ) ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule ( ) ;
}
return err ;
}
2015-01-29 17:40:25 +03:00
static int __init test_rht_init ( void )
{
2017-09-20 02:12:12 +03:00
unsigned int entries ;
2015-08-15 01:37:15 +03:00
int i , err , started_threads = 0 , failed_threads = 0 ;
2015-05-01 01:37:41 +03:00
u64 total_time = 0 ;
2015-08-15 01:37:15 +03:00
struct thread_data * tdata ;
struct test_obj * objs ;
2015-01-29 17:40:25 +03:00
2017-09-20 02:12:12 +03:00
if ( parm_entries < 0 )
parm_entries = 1 ;
entries = min ( parm_entries , MAX_ENTRIES ) ;
2015-01-29 17:40:25 +03:00
2015-05-01 01:37:41 +03:00
test_rht_params . automatic_shrinking = shrinking ;
2015-11-20 20:17:19 +03:00
test_rht_params . max_size = max_size ? : roundup_pow_of_two ( entries ) ;
2015-05-01 01:37:41 +03:00
test_rht_params . nelem_hint = size ;
2015-01-29 17:40:25 +03:00
treewide: Use array_size() in vzalloc()
The vzalloc() function has no 2-factor argument form, so multiplication
factors need to be wrapped in array_size(). This patch replaces cases of:
vzalloc(a * b)
with:
vzalloc(array_size(a, b))
as well as handling cases of:
vzalloc(a * b * c)
with:
vzalloc(array3_size(a, b, c))
This does, however, attempt to ignore constant size factors like:
vzalloc(4 * 1024)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
vzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
vzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
vzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
vzalloc(
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
vzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
vzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
vzalloc(C1 * C2 * C3, ...)
|
vzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression E1, E2;
constant C1, C2;
@@
(
vzalloc(C1 * C2, ...)
|
vzalloc(
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:27:37 +03:00
objs = vzalloc ( array_size ( sizeof ( struct test_obj ) ,
test_rht_params . max_size + 1 ) ) ;
2017-09-20 02:12:11 +03:00
if ( ! objs )
return - ENOMEM ;
2015-05-01 01:37:41 +03:00
pr_info ( " Running rhashtable test nelem=%d, max_size=%d, shrinking=%d \n " ,
size , max_size , shrinking ) ;
2015-01-29 17:40:25 +03:00
2015-05-01 01:37:41 +03:00
for ( i = 0 ; i < runs ; i + + ) {
s64 time ;
2015-01-29 17:40:25 +03:00
2015-05-01 01:37:41 +03:00
pr_info ( " Test %02d: \n " , i ) ;
2017-09-20 02:12:11 +03:00
memset ( objs , 0 , test_rht_params . max_size * sizeof ( struct test_obj ) ) ;
2015-05-01 01:37:41 +03:00
err = rhashtable_init ( & ht , & test_rht_params ) ;
if ( err < 0 ) {
pr_warn ( " Test failed: Unable to initialize hashtable: %d \n " ,
err ) ;
continue ;
}
2017-09-20 02:12:12 +03:00
time = test_rhashtable ( & ht , objs , entries ) ;
2015-05-01 01:37:41 +03:00
rhashtable_destroy ( & ht ) ;
if ( time < 0 ) {
2017-09-20 02:12:11 +03:00
vfree ( objs ) ;
2015-05-01 01:37:41 +03:00
pr_warn ( " Test failed: return code %lld \n " , time ) ;
return - EINVAL ;
}
total_time + = time ;
}
2017-09-20 02:12:13 +03:00
pr_info ( " test if its possible to exceed max_size %d: %s \n " ,
test_rht_params . max_size , test_rhashtable_max ( objs , entries ) = = 0 ?
" no, ok " : " YES, failed " ) ;
2017-09-20 02:12:11 +03:00
vfree ( objs ) ;
2017-09-20 02:12:13 +03:00
2015-05-05 03:27:02 +03:00
do_div ( total_time , runs ) ;
pr_info ( " Average test time: %llu \n " , total_time ) ;
2015-05-01 01:37:41 +03:00
2018-03-04 18:29:49 +03:00
test_insert_duplicates_run ( ) ;
2015-08-15 01:37:15 +03:00
if ( ! tcount )
return 0 ;
pr_info ( " Testing concurrent rhashtable access from %d threads \n " ,
tcount ) ;
2018-12-16 22:48:21 +03:00
atomic_set ( & startup_count , tcount ) ;
treewide: Use array_size() in vzalloc()
The vzalloc() function has no 2-factor argument form, so multiplication
factors need to be wrapped in array_size(). This patch replaces cases of:
vzalloc(a * b)
with:
vzalloc(array_size(a, b))
as well as handling cases of:
vzalloc(a * b * c)
with:
vzalloc(array3_size(a, b, c))
This does, however, attempt to ignore constant size factors like:
vzalloc(4 * 1024)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
vzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
vzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
vzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
vzalloc(
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
vzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
vzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
vzalloc(C1 * C2 * C3, ...)
|
vzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression E1, E2;
constant C1, C2;
@@
(
vzalloc(C1 * C2, ...)
|
vzalloc(
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:27:37 +03:00
tdata = vzalloc ( array_size ( tcount , sizeof ( struct thread_data ) ) ) ;
2015-08-15 01:37:15 +03:00
if ( ! tdata )
return - ENOMEM ;
treewide: Use array_size() in vzalloc()
The vzalloc() function has no 2-factor argument form, so multiplication
factors need to be wrapped in array_size(). This patch replaces cases of:
vzalloc(a * b)
with:
vzalloc(array_size(a, b))
as well as handling cases of:
vzalloc(a * b * c)
with:
vzalloc(array3_size(a, b, c))
This does, however, attempt to ignore constant size factors like:
vzalloc(4 * 1024)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
vzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
vzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
vzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
vzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
vzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
vzalloc(
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
vzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
vzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
vzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
vzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
vzalloc(C1 * C2 * C3, ...)
|
vzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression E1, E2;
constant C1, C2;
@@
(
vzalloc(C1 * C2, ...)
|
vzalloc(
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:27:37 +03:00
objs = vzalloc ( array3_size ( sizeof ( struct test_obj ) , tcount , entries ) ) ;
2015-08-15 01:37:15 +03:00
if ( ! objs ) {
vfree ( tdata ) ;
return - ENOMEM ;
}
2015-11-20 20:17:19 +03:00
test_rht_params . max_size = max_size ? :
roundup_pow_of_two ( tcount * entries ) ;
2015-08-15 01:37:15 +03:00
err = rhashtable_init ( & ht , & test_rht_params ) ;
if ( err < 0 ) {
pr_warn ( " Test failed: Unable to initialize hashtable: %d \n " ,
err ) ;
vfree ( tdata ) ;
vfree ( objs ) ;
return - EINVAL ;
}
for ( i = 0 ; i < tcount ; i + + ) {
tdata [ i ] . id = i ;
2017-09-20 02:12:12 +03:00
tdata [ i ] . entries = entries ;
2015-08-15 01:37:15 +03:00
tdata [ i ] . objs = objs + i * entries ;
tdata [ i ] . task = kthread_run ( threadfunc , & tdata [ i ] ,
" rhashtable_thrad[%d] " , i ) ;
2018-12-16 22:48:21 +03:00
if ( IS_ERR ( tdata [ i ] . task ) ) {
2015-08-15 01:37:15 +03:00
pr_err ( " kthread_run failed for thread %d \n " , i ) ;
2018-12-16 22:48:21 +03:00
atomic_dec ( & startup_count ) ;
} else {
2015-08-15 01:37:15 +03:00
started_threads + + ;
2018-12-16 22:48:21 +03:00
}
2015-08-15 01:37:15 +03:00
}
2018-12-16 22:48:21 +03:00
if ( wait_event_interruptible ( startup_wait , atomic_read ( & startup_count ) = = 0 ) )
pr_err ( " wait_event interruptible failed \n " ) ;
/* count is 0 now, set it to -1 and wake up all threads together */
atomic_dec ( & startup_count ) ;
wake_up_all ( & startup_wait ) ;
2015-08-15 01:37:15 +03:00
for ( i = 0 ; i < tcount ; i + + ) {
if ( IS_ERR ( tdata [ i ] . task ) )
continue ;
if ( ( err = kthread_stop ( tdata [ i ] . task ) ) ) {
pr_warn ( " Test failed: thread %d returned: %d \n " ,
i , err ) ;
failed_threads + + ;
}
}
rhashtable_destroy ( & ht ) ;
vfree ( tdata ) ;
vfree ( objs ) ;
2017-09-20 02:12:14 +03:00
/*
* rhltable_remove is very expensive , default values can cause test
* to run for 2 minutes or more , use a smaller number instead .
*/
err = test_rhltable ( entries / 16 ) ;
pr_info ( " Started %d threads, %d failed, rhltable test returns %d \n " ,
started_threads , failed_threads , err ) ;
2015-05-01 01:37:41 +03:00
return 0 ;
2015-01-29 17:40:25 +03:00
}
2015-02-20 02:53:39 +03:00
static void __exit test_rht_exit ( void )
{
}
2015-01-29 17:40:25 +03:00
module_init ( test_rht_init ) ;
2015-02-20 02:53:39 +03:00
module_exit ( test_rht_exit ) ;
2015-01-29 17:40:25 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;