In the rcu_nocb_toggle(), the schedule_hrtimeout() is called after the
state assignment with no condition check. the release-acquire pair from
raw_spin_unlock/lock(&cpu_base->lock), guarantee that task->__state is
visible to the hrtimer callback:
CPU0 CPU1
__set_current_state(TASK_INTERRUPTIBLE)
->WRITE_ONCE(task->__state, TASK_INTERRUPTIBLE)
schedule_hrtimeout
->hrtimer_sleeper_start_expires()
->raw_spin_lock_irqsave(&cpu_base->lock)
....
->raw_spin_unlock_irqrestore(&cpu_base->lock)
hard-irq:
raw_spin_lock_irqsave(&cpu_base->lock)
__hrtimer_run_queues
->__run_hrtimer
->raw_spin_unlock_irqrestore(&cpu_base->lock)
->fn(timer)
->hrtimer_wakeup
->wake_up_process
->try_to_wake_up
->READ
task->__state
This commit therefore use the __set_current_state() to replace the
set_current_state() in rcu_nocb_toggle().
Signed-off-by: Zqiang <[email protected]>
---
kernel/rcu/rcutorture.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index b1bab59efde5..a0e6901e0f90 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -2947,7 +2947,7 @@ static int rcu_nocb_toggle(void *arg)
atomic_long_inc(&n_nocb_deoffload);
}
toggle_delay = torture_random(&rand) % toggle_fuzz +
toggle_interval;
- set_current_state(TASK_INTERRUPTIBLE);
+ __set_current_state(TASK_INTERRUPTIBLE);
schedule_hrtimeout(&toggle_delay, HRTIMER_MODE_REL);
if (stutter_wait("rcu_nocb_toggle"))
sched_set_normal(current, oldnice);
--
2.17.1