hc
2023-11-06 e3e12f52b214121840b44c91de5b3e5af5d3eb84
kernel/kernel/cpu.c
....@@ -876,6 +876,15 @@
876876 int err, cpu = smp_processor_id();
877877 int ret;
878878
879
+#ifdef CONFIG_PREEMPT_RT_BASE
880
+ /*
881
+ * If any tasks disabled migration before we got here,
882
+ * go back and sleep again.
883
+ */
884
+ if (cpu_nr_pinned(cpu))
885
+ return -EAGAIN;
886
+#endif
887
+
879888 /* Ensure this CPU doesn't handle any more interrupts. */
880889 err = __cpu_disable();
881890 if (err < 0)
....@@ -903,6 +912,10 @@
903912 return 0;
904913 }
905914
915
+#ifdef CONFIG_PREEMPT_RT_BASE
916
+struct task_struct *takedown_cpu_task;
917
+#endif
918
+
906919 static int takedown_cpu(unsigned int cpu)
907920 {
908921 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
....@@ -917,11 +930,39 @@
917930 */
918931 irq_lock_sparse();
919932
933
+#ifdef CONFIG_PREEMPT_RT_BASE
934
+ WARN_ON_ONCE(takedown_cpu_task);
935
+ takedown_cpu_task = current;
936
+
937
+again:
938
+ /*
939
+ * If a task pins this CPU after we pass this check, take_cpu_down
940
+ * will return -EAGAIN.
941
+ */
942
+ for (;;) {
943
+ int nr_pinned;
944
+
945
+ set_current_state(TASK_UNINTERRUPTIBLE);
946
+ nr_pinned = cpu_nr_pinned(cpu);
947
+ if (nr_pinned == 0)
948
+ break;
949
+ schedule();
950
+ }
951
+ set_current_state(TASK_RUNNING);
952
+#endif
953
+
920954 /*
921955 * So now all preempt/rcu users must observe !cpu_active().
922956 */
923957 err = stop_machine_cpuslocked(take_cpu_down, NULL, cpumask_of(cpu));
958
+#ifdef CONFIG_PREEMPT_RT_BASE
959
+ if (err == -EAGAIN)
960
+ goto again;
961
+#endif
924962 if (err) {
963
+#ifdef CONFIG_PREEMPT_RT_BASE
964
+ takedown_cpu_task = NULL;
965
+#endif
925966 /* CPU refused to die */
926967 irq_unlock_sparse();
927968 /* Unpark the hotplug thread so we can rollback there */
....@@ -940,6 +981,9 @@
940981 wait_for_ap_thread(st, false);
941982 BUG_ON(st->state != CPUHP_AP_IDLE_DEAD);
942983
984
+#ifdef CONFIG_PREEMPT_RT_BASE
985
+ takedown_cpu_task = NULL;
986
+#endif
943987 /* Interrupts are moved away from the dying cpu, reenable alloc/free */
944988 irq_unlock_sparse();
945989