Commit fcf0e25a authored by Ankur Arora's avatar Ankur Arora Committed by Boqun Feng
Browse files

rcu: handle unstable rdp in rcu_read_unlock_strict()



rcu_read_unlock_strict() can be called with preemption enabled
which can make for an unstable rdp and a racy norm value.

Fix this by dropping the preempt-count in __rcu_read_unlock()
after the call to rcu_read_unlock_strict(), adjusting the
preempt-count check appropriately.

Suggested-by: default avatarFrederic Weisbecker <frederic@kernel.org>
Signed-off-by: default avatarAnkur Arora <ankur.a.arora@oracle.com>
Reviewed-by: default avatarFrederic Weisbecker <frederic@kernel.org>
Signed-off-by: default avatarPaul E. McKenney <paulmck@kernel.org>
Signed-off-by: default avatarBoqun Feng <boqun.feng@gmail.com>
parent 2c00e119
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -95,9 +95,9 @@ static inline void __rcu_read_lock(void)

static inline void __rcu_read_unlock(void)
{
	preempt_enable();
	if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD))
		rcu_read_unlock_strict();
	preempt_enable();
}

static inline int rcu_preempt_depth(void)
+10 −1
Original line number Diff line number Diff line
@@ -833,8 +833,17 @@ void rcu_read_unlock_strict(void)
{
	struct rcu_data *rdp;

	if (irqs_disabled() || preempt_count() || !rcu_state.gp_kthread)
	if (irqs_disabled() || in_atomic_preempt_off() || !rcu_state.gp_kthread)
		return;

	/*
	 * rcu_report_qs_rdp() can only be invoked with a stable rdp and
	 * from the local CPU.
	 *
	 * The in_atomic_preempt_off() check ensures that we come here holding
	 * the last preempt_count (which will get dropped once we return to
	 * __rcu_read_unlock().
	 */
	rdp = this_cpu_ptr(&rcu_data);
	rdp->cpu_no_qs.b.norm = false;
	rcu_report_qs_rdp(rdp);