The following commit has been merged into the core/rcu branch of tip:

Commit-ID:     bfba7ed084f8ab0269a5a1d2f51b07865456c334
Gitweb:        
https://git.kernel.org/tip/bfba7ed084f8ab0269a5a1d2f51b07865456c334
Author:        Uladzislau Rezki (Sony) <ure...@gmail.com>
AuthorDate:    Wed, 09 Dec 2020 21:27:32 +01:00
Committer:     Paul E. McKenney <paul...@kernel.org>
CommitterDate: Mon, 04 Jan 2021 15:54:49 -08:00

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) <ure...@gmail.com>
[ paulmck: Handle CONFIG_PROVE_RCU=n and identify test cases' callbacks. ]
Signed-off-by: Paul E. McKenney <paul...@kernel.org>
---
 kernel/rcu/tasks.h | 79 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 79 insertions(+)

diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
index 73bbe79..74767d3 100644
--- a/kernel/rcu/tasks.h
+++ b/kernel/rcu/tasks.h
@@ -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 */

Reply via email to