Commit 31d8aaa8 authored by Paul E. McKenney's avatar Paul E. McKenney

rcu: Keep synchronize_rcu() from enabling irqs in early boot

Making polled RCU grace periods account for expedited grace periods
required acquiring the leaf rcu_node structure's lock during early boot,
but after rcu_init() was called.  This lock is irq-disabled, but the
code incorrectly assumes that irqs are always disabled when invoking
synchronize_rcu().  The exception is early boot before the scheduler has
started, which means that upon return from synchronize_rcu(), irqs will
be incorrectly enabled.

This commit fixes this bug by using irqsave/irqrestore locking primitives.

Fixes: bf95b2bc ("rcu: Switch polled grace-period APIs to ->gp_seq_polled")
Reported-by: default avatarSteven Rostedt <rostedt@goodmis.org>
Signed-off-by: default avatarPaul E. McKenney <paulmck@kernel.org>
parent 9abf2313
...@@ -1403,30 +1403,32 @@ static void rcu_poll_gp_seq_end(unsigned long *snap) ...@@ -1403,30 +1403,32 @@ static void rcu_poll_gp_seq_end(unsigned long *snap)
// where caller does not hold the root rcu_node structure's lock. // where caller does not hold the root rcu_node structure's lock.
static void rcu_poll_gp_seq_start_unlocked(unsigned long *snap) static void rcu_poll_gp_seq_start_unlocked(unsigned long *snap)
{ {
unsigned long flags;
struct rcu_node *rnp = rcu_get_root(); struct rcu_node *rnp = rcu_get_root();
if (rcu_init_invoked()) { if (rcu_init_invoked()) {
lockdep_assert_irqs_enabled(); lockdep_assert_irqs_enabled();
raw_spin_lock_irq_rcu_node(rnp); raw_spin_lock_irqsave_rcu_node(rnp, flags);
} }
rcu_poll_gp_seq_start(snap); rcu_poll_gp_seq_start(snap);
if (rcu_init_invoked()) if (rcu_init_invoked())
raw_spin_unlock_irq_rcu_node(rnp); raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
} }
// Make the polled API aware of the end of a grace period, but where // Make the polled API aware of the end of a grace period, but where
// caller does not hold the root rcu_node structure's lock. // caller does not hold the root rcu_node structure's lock.
static void rcu_poll_gp_seq_end_unlocked(unsigned long *snap) static void rcu_poll_gp_seq_end_unlocked(unsigned long *snap)
{ {
unsigned long flags;
struct rcu_node *rnp = rcu_get_root(); struct rcu_node *rnp = rcu_get_root();
if (rcu_init_invoked()) { if (rcu_init_invoked()) {
lockdep_assert_irqs_enabled(); lockdep_assert_irqs_enabled();
raw_spin_lock_irq_rcu_node(rnp); raw_spin_lock_irqsave_rcu_node(rnp, flags);
} }
rcu_poll_gp_seq_end(snap); rcu_poll_gp_seq_end(snap);
if (rcu_init_invoked()) if (rcu_init_invoked())
raw_spin_unlock_irq_rcu_node(rnp); raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment