rcu-tasks: Add RCU-tasks self tests
This commit adds self tests for early-boot use of RCU-tasks grace periods. It tests all three variants (Rude, Tasks, and Tasks Trace) and covers both synchronous (e.g., synchronize_rcu_tasks()) and asynchronous (e.g., call_rcu_tasks()) grace-period APIs. Self-tests are run only in kernels built with CONFIG_PROVE_RCU=y. Signed-off-by: Uladzislau Rezki (Sony) <urezki@gmail.com> [ paulmck: Handle CONFIG_PROVE_RCU=n and identify test cases' callbacks. ] Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
This commit is contained in:
parent
7dffe01765
commit
bfba7ed084
|
@ -1231,6 +1231,82 @@ void show_rcu_tasks_gp_kthreads(void)
|
|||
}
|
||||
#endif /* #ifndef CONFIG_TINY_RCU */
|
||||
|
||||
#ifdef CONFIG_PROVE_RCU
|
||||
struct rcu_tasks_test_desc {
|
||||
struct rcu_head rh;
|
||||
const char *name;
|
||||
bool notrun;
|
||||
};
|
||||
|
||||
static struct rcu_tasks_test_desc tests[] = {
|
||||
{
|
||||
.name = "call_rcu_tasks()",
|
||||
/* If not defined, the test is skipped. */
|
||||
.notrun = !IS_ENABLED(CONFIG_TASKS_RCU),
|
||||
},
|
||||
{
|
||||
.name = "call_rcu_tasks_rude()",
|
||||
/* If not defined, the test is skipped. */
|
||||
.notrun = !IS_ENABLED(CONFIG_TASKS_RUDE_RCU),
|
||||
},
|
||||
{
|
||||
.name = "call_rcu_tasks_trace()",
|
||||
/* If not defined, the test is skipped. */
|
||||
.notrun = !IS_ENABLED(CONFIG_TASKS_TRACE_RCU)
|
||||
}
|
||||
};
|
||||
|
||||
static void test_rcu_tasks_callback(struct rcu_head *rhp)
|
||||
{
|
||||
struct rcu_tasks_test_desc *rttd =
|
||||
container_of(rhp, struct rcu_tasks_test_desc, rh);
|
||||
|
||||
pr_info("Callback from %s invoked.\n", rttd->name);
|
||||
|
||||
rttd->notrun = true;
|
||||
}
|
||||
|
||||
static void rcu_tasks_initiate_self_tests(void)
|
||||
{
|
||||
pr_info("Running RCU-tasks wait API self tests\n");
|
||||
#ifdef CONFIG_TASKS_RCU
|
||||
synchronize_rcu_tasks();
|
||||
call_rcu_tasks(&tests[0].rh, test_rcu_tasks_callback);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TASKS_RUDE_RCU
|
||||
synchronize_rcu_tasks_rude();
|
||||
call_rcu_tasks_rude(&tests[1].rh, test_rcu_tasks_callback);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TASKS_TRACE_RCU
|
||||
synchronize_rcu_tasks_trace();
|
||||
call_rcu_tasks_trace(&tests[2].rh, test_rcu_tasks_callback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int rcu_tasks_verify_self_tests(void)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
if (!tests[i].notrun) { // still hanging.
|
||||
pr_err("%s has been failed.\n", tests[i].name);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
WARN_ON(1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
late_initcall(rcu_tasks_verify_self_tests);
|
||||
#else /* #ifdef CONFIG_PROVE_RCU */
|
||||
static void rcu_tasks_initiate_self_tests(void) { }
|
||||
#endif /* #else #ifdef CONFIG_PROVE_RCU */
|
||||
|
||||
void __init rcu_init_tasks_generic(void)
|
||||
{
|
||||
#ifdef CONFIG_TASKS_RCU
|
||||
|
@ -1244,6 +1320,9 @@ void __init rcu_init_tasks_generic(void)
|
|||
#ifdef CONFIG_TASKS_TRACE_RCU
|
||||
rcu_spawn_tasks_trace_kthread();
|
||||
#endif
|
||||
|
||||
// Run the self-tests.
|
||||
rcu_tasks_initiate_self_tests();
|
||||
}
|
||||
|
||||
#else /* #ifdef CONFIG_TASKS_RCU_GENERIC */
|
||||
|
|
Loading…
Reference in New Issue