Skip to content

Commit 8e9c01c

Browse files
Frederic Weisbeckerpaulmckrcu
authored andcommitted
srcu: Initialize SRCU after timers
Once srcu_init() is called, the SRCU core will make use of delayed workqueues, which rely on timers. However init_timers() is called several steps after rcu_init(). This means that a call_srcu() after rcu_init() but before init_timers() would find itself within a dangerously uninitialized timer core. This commit therefore creates a separate call to srcu_init() after init_timer() completes, which ensures that we stay in early SRCU mode until timers are safe(r). Signed-off-by: Frederic Weisbecker <frederic@kernel.org> Cc: Uladzislau Rezki <urezki@gmail.com> Cc: Boqun Feng <boqun.feng@gmail.com> Cc: Lai Jiangshan <jiangshanlai@gmail.com> Cc: Neeraj Upadhyay <neeraju@codeaurora.org> Cc: Josh Triplett <josh@joshtriplett.org> Cc: Joel Fernandes <joel@joelfernandes.org> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
1 parent 7bf0a61 commit 8e9c01c

File tree

6 files changed

+13
-8
lines changed

6 files changed

+13
-8
lines changed

include/linux/srcu.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ unsigned long get_state_synchronize_srcu(struct srcu_struct *ssp);
6464
unsigned long start_poll_synchronize_srcu(struct srcu_struct *ssp);
6565
bool poll_state_synchronize_srcu(struct srcu_struct *ssp, unsigned long cookie);
6666

67+
#ifdef CONFIG_SRCU
68+
void srcu_init(void);
69+
#else /* #ifdef CONFIG_SRCU */
70+
static inline void srcu_init(void) { }
71+
#endif /* #else #ifdef CONFIG_SRCU */
72+
6773
#ifdef CONFIG_DEBUG_LOCK_ALLOC
6874

6975
/**

init/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <linux/profile.h>
4343
#include <linux/kfence.h>
4444
#include <linux/rcupdate.h>
45+
#include <linux/srcu.h>
4546
#include <linux/moduleparam.h>
4647
#include <linux/kallsyms.h>
4748
#include <linux/writeback.h>
@@ -979,6 +980,7 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
979980
tick_init();
980981
rcu_init_nohz();
981982
init_timers();
983+
srcu_init();
982984
hrtimers_init();
983985
softirq_init();
984986
timekeeping_init();

kernel/rcu/rcu.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -422,12 +422,6 @@ do { \
422422

423423
#endif /* #if defined(CONFIG_SRCU) || !defined(CONFIG_TINY_RCU) */
424424

425-
#ifdef CONFIG_SRCU
426-
void srcu_init(void);
427-
#else /* #ifdef CONFIG_SRCU */
428-
static inline void srcu_init(void) { }
429-
#endif /* #else #ifdef CONFIG_SRCU */
430-
431425
#ifdef CONFIG_TINY_RCU
432426
/* Tiny RCU doesn't expedite, as its purpose in life is instead to be tiny. */
433427
static inline bool rcu_gp_is_normal(void) { return true; }

kernel/rcu/srcutree.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,6 +1384,11 @@ void __init srcu_init(void)
13841384
{
13851385
struct srcu_struct *ssp;
13861386

1387+
/*
1388+
* Once that is set, call_srcu() can follow the normal path and
1389+
* queue delayed work. This must follow RCU workqueues creation
1390+
* and timers initialization.
1391+
*/
13871392
srcu_init_done = true;
13881393
while (!list_empty(&srcu_boot_list)) {
13891394
ssp = list_first_entry(&srcu_boot_list, struct srcu_struct,

kernel/rcu/tiny.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,5 +221,4 @@ void __init rcu_init(void)
221221
{
222222
open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
223223
rcu_early_boot_tests();
224-
srcu_init();
225224
}

kernel/rcu/tree.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4735,7 +4735,6 @@ void __init rcu_init(void)
47354735
WARN_ON(!rcu_gp_wq);
47364736
rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0);
47374737
WARN_ON(!rcu_par_gp_wq);
4738-
srcu_init();
47394738

47404739
/* Fill in default value for rcutree.qovld boot parameter. */
47414740
/* -After- the rcu_node ->lock fields are initialized! */

0 commit comments

Comments
 (0)