Merge tag 'uml-for-linus-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / kernel / cpu.c
index f6811c857102329c4f543f496a31e647b886ebb3..6de7c6bb74eeea98c217374cb5bed57c7b38a452 100644 (file)
@@ -1487,8 +1487,22 @@ out:
        return ret;
 }
 
+struct cpu_down_work {
+       unsigned int            cpu;
+       enum cpuhp_state        target;
+};
+
+static long __cpu_down_maps_locked(void *arg)
+{
+       struct cpu_down_work *work = arg;
+
+       return _cpu_down(work->cpu, 0, work->target);
+}
+
 static int cpu_down_maps_locked(unsigned int cpu, enum cpuhp_state target)
 {
+       struct cpu_down_work work = { .cpu = cpu, .target = target, };
+
        /*
         * If the platform does not support hotplug, report it explicitly to
         * differentiate it from a transient offlining failure.
@@ -1497,7 +1511,15 @@ static int cpu_down_maps_locked(unsigned int cpu, enum cpuhp_state target)
                return -EOPNOTSUPP;
        if (cpu_hotplug_disabled)
                return -EBUSY;
-       return _cpu_down(cpu, 0, target);
+
+       /*
+        * Ensure that the control task does not run on the to be offlined
+        * CPU to prevent a deadlock against cfs_b->period_timer.
+        */
+       cpu = cpumask_any_but(cpu_online_mask, cpu);
+       if (cpu >= nr_cpu_ids)
+               return -EBUSY;
+       return work_on_cpu(cpu, __cpu_down_maps_locked, &work);
 }
 
 static int cpu_down(unsigned int cpu, enum cpuhp_state target)