aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPaul E. McKenney <paul.mckenney@linaro.org>2012-01-11 19:33:17 -0500
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2012-02-21 12:03:41 -0500
commit768dfffdffbfcc07d6927bdd642c714c0dd64c99 (patch)
tree3f559e37c0ff2ae59af963024c0d3595fa3d4b8e /kernel
parentafef20540f7cd1ea91bc1ac20be238389eee4003 (diff)
rcu: Prevent RCU callbacks from executing before scheduler initialized
This is a port of commit #b0d3041 from TREE_RCU to TREE_PREEMPT_RCU. Under some rare but real combinations of configuration parameters, RCU callbacks are posted during early boot that use kernel facilities that are not yet initialized. Therefore, when these callbacks are invoked, hard hangs and crashes ensue. This commit therefore prevents RCU callbacks from being invoked until after the scheduler is fully up and running, as in after multiple tasks have been spawned. It might well turn out that a better approach is to identify the specific RCU callbacks that are causing this problem, but that discussion will wait until such time as someone really needs an RCU callback to be invoked (as opposed to merely registered) during early boot. Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/rcutiny_plugin.h15
1 files changed, 12 insertions, 3 deletions
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h
index b58a3200f0ff..95df60ebe363 100644
--- a/kernel/rcutiny_plugin.h
+++ b/kernel/rcutiny_plugin.h
@@ -914,7 +914,8 @@ static void rcu_preempt_process_callbacks(void)
914static void invoke_rcu_callbacks(void) 914static void invoke_rcu_callbacks(void)
915{ 915{
916 have_rcu_kthread_work = 1; 916 have_rcu_kthread_work = 1;
917 wake_up(&rcu_kthread_wq); 917 if (rcu_kthread_task != NULL)
918 wake_up(&rcu_kthread_wq);
918} 919}
919 920
920#ifdef CONFIG_RCU_TRACE 921#ifdef CONFIG_RCU_TRACE
@@ -975,12 +976,16 @@ early_initcall(rcu_spawn_kthreads);
975 976
976#else /* #ifdef CONFIG_RCU_BOOST */ 977#else /* #ifdef CONFIG_RCU_BOOST */
977 978
979/* Hold off callback invocation until early_initcall() time. */
980static int rcu_scheduler_fully_active __read_mostly;
981
978/* 982/*
979 * Start up softirq processing of callbacks. 983 * Start up softirq processing of callbacks.
980 */ 984 */
981void invoke_rcu_callbacks(void) 985void invoke_rcu_callbacks(void)
982{ 986{
983 raise_softirq(RCU_SOFTIRQ); 987 if (rcu_scheduler_fully_active)
988 raise_softirq(RCU_SOFTIRQ);
984} 989}
985 990
986#ifdef CONFIG_RCU_TRACE 991#ifdef CONFIG_RCU_TRACE
@@ -995,10 +1000,14 @@ static bool rcu_is_callbacks_kthread(void)
995 1000
996#endif /* #ifdef CONFIG_RCU_TRACE */ 1001#endif /* #ifdef CONFIG_RCU_TRACE */
997 1002
998void rcu_init(void) 1003static int __init rcu_scheduler_really_started(void)
999{ 1004{
1005 rcu_scheduler_fully_active = 1;
1000 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); 1006 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
1007 raise_softirq(RCU_SOFTIRQ); /* Invoke any callbacks from early boot. */
1008 return 0;
1001} 1009}
1010early_initcall(rcu_scheduler_really_started);
1002 1011
1003#endif /* #else #ifdef CONFIG_RCU_BOOST */ 1012#endif /* #else #ifdef CONFIG_RCU_BOOST */
1004 1013