Because synchronize_srcu_atomic() cannot sleep, if a pair of them run concurrently pinned to the same CPU, it is possible that one will spin uselessly waiting for the other while at the same time preventing that other from running. This commit therefore disables preemption to prevent this failure mode.
Signed-off-by: Paul E. McKenney <[email protected]> --- kernel/rcu/srcutree.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c index 570d068d1840..61c2375ba2ec 100644 --- a/kernel/rcu/srcutree.c +++ b/kernel/rcu/srcutree.c @@ -2123,11 +2123,14 @@ void synchronize_srcu_atomic(struct srcu_struct *ssp) // Perhaps others will do our work for us. srcu_state = get_state_synchronize_srcu(ssp); + preempt_disable(); while (atomic_read(&sup->srcu_atomic_gp_flag) || atomic_xchg(&sup->srcu_atomic_gp_flag, 1)) { + preempt_enable(); if (poll_state_synchronize_srcu(ssp, srcu_state)) return; cpu_relax(); + preempt_disable(); } // One last check for others doing our work for us under the lock. @@ -2135,6 +2138,7 @@ void synchronize_srcu_atomic(struct srcu_struct *ssp) if (poll_state_synchronize_srcu(ssp, srcu_state)) { raw_spin_unlock_irq_rcu_node(sup); atomic_set(&sup->srcu_atomic_gp_flag, 0); + preempt_enable(); return; } @@ -2152,6 +2156,7 @@ void synchronize_srcu_atomic(struct srcu_struct *ssp) } ASSERT_EXCLUSIVE_WRITER(sup->srcu_atomic_gp_flag); atomic_set_release(&sup->srcu_atomic_gp_flag, 0); + preempt_enable(); non_block_end(); } EXPORT_SYMBOL_GPL(synchronize_srcu_atomic); -- 2.40.1

