aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcu
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/rcu')
-rw-r--r--kernel/rcu/rcu.h2
-rw-r--r--kernel/rcu/tiny.c4
-rw-r--r--kernel/rcu/tree.c2
-rw-r--r--kernel/rcu/update.c84
4 files changed, 91 insertions, 1 deletions
diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h
index ff1a6de62f17..07bb02eda844 100644
--- a/kernel/rcu/rcu.h
+++ b/kernel/rcu/rcu.h
@@ -135,4 +135,6 @@ int rcu_jiffies_till_stall_check(void);
135 */ 135 */
136#define TPS(x) tracepoint_string(x) 136#define TPS(x) tracepoint_string(x)
137 137
138void rcu_early_boot_tests(void);
139
138#endif /* __LINUX_RCU_H */ 140#endif /* __LINUX_RCU_H */
diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
index c0623fc47125..d3d44c589122 100644
--- a/kernel/rcu/tiny.c
+++ b/kernel/rcu/tiny.c
@@ -380,7 +380,9 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
380} 380}
381EXPORT_SYMBOL_GPL(call_rcu_bh); 381EXPORT_SYMBOL_GPL(call_rcu_bh);
382 382
383void rcu_init(void) 383void __init rcu_init(void)
384{ 384{
385 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); 385 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
386
387 rcu_early_boot_tests();
386} 388}
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 9815447d22e0..77b48f03c077 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -3766,6 +3766,8 @@ void __init rcu_init(void)
3766 pm_notifier(rcu_pm_notify, 0); 3766 pm_notifier(rcu_pm_notify, 0);
3767 for_each_online_cpu(cpu) 3767 for_each_online_cpu(cpu)
3768 rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu); 3768 rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
3769
3770 rcu_early_boot_tests();
3769} 3771}
3770 3772
3771#include "tree_plugin.h" 3773#include "tree_plugin.h"
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index 3ef8ba58694e..99d47e6a280f 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -690,3 +690,87 @@ static void rcu_spawn_tasks_kthread(void)
690} 690}
691 691
692#endif /* #ifdef CONFIG_TASKS_RCU */ 692#endif /* #ifdef CONFIG_TASKS_RCU */
693
694#ifdef CONFIG_PROVE_RCU
695
696/*
697 * Early boot self test parameters, one for each flavor
698 */
699static bool rcu_self_test;
700static bool rcu_self_test_bh;
701static bool rcu_self_test_sched;
702
703module_param(rcu_self_test, bool, 0444);
704module_param(rcu_self_test_bh, bool, 0444);
705module_param(rcu_self_test_sched, bool, 0444);
706
707static int rcu_self_test_counter;
708
709static void test_callback(struct rcu_head *r)
710{
711 rcu_self_test_counter++;
712 pr_info("RCU test callback executed %d\n", rcu_self_test_counter);
713}
714
715static void early_boot_test_call_rcu(void)
716{
717 static struct rcu_head head;
718
719 call_rcu(&head, test_callback);
720}
721
722static void early_boot_test_call_rcu_bh(void)
723{
724 static struct rcu_head head;
725
726 call_rcu_bh(&head, test_callback);
727}
728
729static void early_boot_test_call_rcu_sched(void)
730{
731 static struct rcu_head head;
732
733 call_rcu_sched(&head, test_callback);
734}
735
736void rcu_early_boot_tests(void)
737{
738 pr_info("Running RCU self tests\n");
739
740 if (rcu_self_test)
741 early_boot_test_call_rcu();
742 if (rcu_self_test_bh)
743 early_boot_test_call_rcu_bh();
744 if (rcu_self_test_sched)
745 early_boot_test_call_rcu_sched();
746}
747
748static int rcu_verify_early_boot_tests(void)
749{
750 int ret = 0;
751 int early_boot_test_counter = 0;
752
753 if (rcu_self_test) {
754 early_boot_test_counter++;
755 rcu_barrier();
756 }
757 if (rcu_self_test_bh) {
758 early_boot_test_counter++;
759 rcu_barrier_bh();
760 }
761 if (rcu_self_test_sched) {
762 early_boot_test_counter++;
763 rcu_barrier_sched();
764 }
765
766 if (rcu_self_test_counter != early_boot_test_counter) {
767 WARN_ON(1);
768 ret = -1;
769 }
770
771 return ret;
772}
773late_initcall(rcu_verify_early_boot_tests);
774#else
775void rcu_early_boot_tests(void) {}
776#endif /* CONFIG_PROVE_RCU */