|
@@ -236,13 +236,24 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1,
|
|
|
struct cpu_stopper *stopper2 = per_cpu_ptr(&cpu_stopper, cpu2);
|
|
|
DEFINE_WAKE_Q(wakeq);
|
|
|
int err;
|
|
|
+
|
|
|
retry:
|
|
|
+ /*
|
|
|
+ * The waking up of stopper threads has to happen in the same
|
|
|
+ * scheduling context as the queueing. Otherwise, there is a
|
|
|
+ * possibility of one of the above stoppers being woken up by another
|
|
|
+ * CPU, and preempting us. This will cause us to not wake up the other
|
|
|
+ * stopper forever.
|
|
|
+ */
|
|
|
+ preempt_disable();
|
|
|
raw_spin_lock_irq(&stopper1->lock);
|
|
|
raw_spin_lock_nested(&stopper2->lock, SINGLE_DEPTH_NESTING);
|
|
|
|
|
|
- err = -ENOENT;
|
|
|
- if (!stopper1->enabled || !stopper2->enabled)
|
|
|
+ if (!stopper1->enabled || !stopper2->enabled) {
|
|
|
+ err = -ENOENT;
|
|
|
goto unlock;
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Ensure that if we race with __stop_cpus() the stoppers won't get
|
|
|
* queued up in reverse order leading to system deadlock.
|
|
@@ -253,36 +264,30 @@ retry:
|
|
|
* It can be falsely true but it is safe to spin until it is cleared,
|
|
|
* queue_stop_cpus_work() does everything under preempt_disable().
|
|
|
*/
|
|
|
- err = -EDEADLK;
|
|
|
- if (unlikely(stop_cpus_in_progress))
|
|
|
- goto unlock;
|
|
|
+ if (unlikely(stop_cpus_in_progress)) {
|
|
|
+ err = -EDEADLK;
|
|
|
+ goto unlock;
|
|
|
+ }
|
|
|
|
|
|
err = 0;
|
|
|
__cpu_stop_queue_work(stopper1, work1, &wakeq);
|
|
|
__cpu_stop_queue_work(stopper2, work2, &wakeq);
|
|
|
- /*
|
|
|
- * The waking up of stopper threads has to happen
|
|
|
- * in the same scheduling context as the queueing.
|
|
|
- * Otherwise, there is a possibility of one of the
|
|
|
- * above stoppers being woken up by another CPU,
|
|
|
- * and preempting us. This will cause us to n ot
|
|
|
- * wake up the other stopper forever.
|
|
|
- */
|
|
|
- preempt_disable();
|
|
|
+
|
|
|
unlock:
|
|
|
raw_spin_unlock(&stopper2->lock);
|
|
|
raw_spin_unlock_irq(&stopper1->lock);
|
|
|
|
|
|
if (unlikely(err == -EDEADLK)) {
|
|
|
+ preempt_enable();
|
|
|
+
|
|
|
while (stop_cpus_in_progress)
|
|
|
cpu_relax();
|
|
|
+
|
|
|
goto retry;
|
|
|
}
|
|
|
|
|
|
- if (!err) {
|
|
|
- wake_up_q(&wakeq);
|
|
|
- preempt_enable();
|
|
|
- }
|
|
|
+ wake_up_q(&wakeq);
|
|
|
+ preempt_enable();
|
|
|
|
|
|
return err;
|
|
|
}
|