All of lore.kernel.org
 help / color / mirror / Atom feed
* [Bug] Race condition between CPU hotplug off flow and __sched_setscheduler()
@ 2022-05-19 12:53 ` Jing-Ting Wu
  0 siblings, 0 replies; 30+ messages in thread
From: Jing-Ting Wu @ 2022-05-19 12:53 UTC (permalink / raw)
  To: Peter Zijlstra, Daniel Bristot de Oliveira, Valentin Schneider, tglx
  Cc: wsd_upstream, linux-kernel, linux-arm-kernel, linux-mediatek,
	Jonathan.JMChen, chris.redpath, Dietmar Eggemann,
	Vincent Donnefort, Ingo Molnar, Juri Lelli, Vincent Guittot,
	Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
	Christian Brauner

Hi all


There is a race condition between CPU hotplug off flow and
__sched_setscheduler(), which will cause hang-up in CPU hotplug off
flow.

Syndrome:
During hotplug off flow in CPU_A, it blocks on
CPUHP_AP_SCHED_WAIT_EMPTY state when enters rcuwait_wait_event().
In that moment, CPU_A stays in idle and cannot wake up stopper
thread(cpuhp/A) to continue CPU_A hotplug off flow.

Root cause:
Balance_push() callback has been stolen by CPU_B in executing
__sched_setscheduler() func., which should be executed in idle task of
CPU_A to wake up stopper thread (cpuhp/A) through calling
rcuwait_wake_up(&rq->hotplug_wait).

Racing flow as below:
CPU_A is going to hotplug off and set rq->balance_callback =
&balance_push_callback, then CPU_A should use balance_push() to push
the task out and release rq_lock.
But if CPU_B do __sched_setscheduler() before CPU_A switch to
swapper/A, CPU_B use splice_balance_callbacks() to steal rq-
>balance_callback and set the CPU_A rq->balance_callback = NULL.
Due to rq->balance_callback is NULL,
so swapper/A could not do balance_push() at CPU_A,
Due to rq(rq_A) != this_rq(rq_B),
so swapper/A could not do rcuwait_wake_up() at CPU_B.


Racing flow:
-----------------------------------------------------------------------
CPU_A (Hotplug down)                          
-----------------------------------------------------------------------
State: CPUHP_AP_ACTIVE
sched_cpu_deactivate()
-> balance_push_set(cpu, true)
   -> rq_A->balance_callback = &balance_push_callback
      => CPU_A set rq_A balance_callback here.
                                
State: CPUHP_AP_SCHED_WAIT_EMPTY
sched_cpu_wait_empty()
-> balance_hotplug_wait()
   -> rcuwait_wait_event(&rq->hotplug_wait)
      => CPU_A do while loop to push task out from CPU_A,
         until swapper/A wake up cpuhp/A.
      -> schedule()
         -> rq_lock(rq, &rf)
            -> context_switch() 
              -> finish_lock_switch()
                 -> __balance_callbacks(rq_A)
                    -> do_balance_callbacks(rq,
                                      splice_balance_callbacks(rq))
                       -> balance_push(rq_A)
                 -> raw_spin_rq_unlock_irq(rq_A)
                    => CPU_A release rq_A lock.

CPU_A release rq_A lock, CPU_B can get rq_A lock.

-----------------------------------------------------------------------
CPU_B (do __sched_setscheduler(), set rq_A->balance_callback = NULL)
-----------------------------------------------------------------------
__sched_setscheduler(p) => task_rq(p) is rq_A
-> task_rq_lock(rq_A)
  -> splice_balance_callbacks(rq_A)
     -> if (head)
           rq_A->balance_callback = NULL
           => CPU_B steal rq_A->balance_callback.
     -> task_rq_unlock(rq_A)


CPU_B release rq_A lock, CPU_A can get rq_A lock and switch to
swapper/A.

-----------------------------------------------------------------------
CPU_A (Hotplug down)                           
-----------------------------------------------------------------------
switch to swapper/A:
schedule()
-> rq_lock(rq, &rf)
   -> context_switch()                                     
      -> finish_lock_switch()
         -> __balance_callbacks(rq_A)
            -> do_balance_callbacks(rq, NULL) 
               => Because rq_A->balance_callback = NULL,
                  swapper/A could not do rcuwait_wake_up().
         -> raw_spin_rq_unlock_irq(rq_A)   

-----------------------------------------------------------------------
CPU_B (do __sched_setscheduler(), set rq_A->balance_callback = NULL) 
-----------------------------------------------------------------------
balance_callbacks(rq_A, head)
-> balance_push(rq_A)
   -> rq->balance_callback = &balance_push_callback;
     -> if (rq != this_rq())
           return;
           => Because rq = rq_A, this_rq = rq_B,
              swapper/A could not do rcuwait_wake_up().

-----------------------------------------------------------------------
CPU_A (Hotplug down)                           
-----------------------------------------------------------------------
rcuwait_wait_event(&rq->hotplug_wait)
=> swapper/A could not do rcuwait_wake_up(),
   it cannot wake up stopper thread(cpuhp/A),
   so system could not exit the while loop at rcuwait_wait_event.




Do you have any suggestion or solution for this issue?
Thank you.



Best regards,
Jing-Ting Wu


^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2022-06-13  8:29 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-19 12:53 [Bug] Race condition between CPU hotplug off flow and __sched_setscheduler() Jing-Ting Wu
2022-05-19 12:53 ` Jing-Ting Wu
2022-05-19 12:53 ` Jing-Ting Wu
2022-05-19 13:14 ` Peter Zijlstra
2022-05-19 13:14   ` Peter Zijlstra
2022-05-19 13:14   ` Peter Zijlstra
2022-05-19 13:19   ` Peter Zijlstra
2022-05-19 13:19     ` Peter Zijlstra
2022-05-19 13:19     ` Peter Zijlstra
2022-05-19 13:47 ` Peter Zijlstra
2022-05-19 13:47   ` Peter Zijlstra
2022-05-19 13:47   ` Peter Zijlstra
2022-05-23  7:12   ` [SPAM]Re: " Jing-Ting Wu
2022-05-23  7:12     ` Jing-Ting Wu
2022-05-26  5:57     ` Jing-Ting Wu
2022-05-26  5:57       ` Jing-Ting Wu
2022-06-02 16:15       ` Jing-Ting Wu
2022-06-02 16:15         ` Jing-Ting Wu
2022-06-07 20:40         ` Peter Zijlstra
2022-06-07 20:40           ` Peter Zijlstra
2022-06-07 21:39           ` [PATCH] sched: Fix balance_push() vs __sched_setscheduler() Peter Zijlstra
2022-06-07 21:39             ` Peter Zijlstra
2022-06-07 21:39             ` Peter Zijlstra
2022-06-08 14:16             ` Jing-Ting Wu
2022-06-08 14:16               ` Jing-Ting Wu
2022-06-08 14:16               ` Jing-Ting Wu
2022-06-08 14:48               ` Peter Zijlstra
2022-06-08 14:48                 ` Peter Zijlstra
2022-06-08 14:48                 ` Peter Zijlstra
2022-06-13  8:29   ` [tip: sched/urgent] " tip-bot2 for Peter Zijlstra

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.