Merge tag '6.6-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6
[sfrench/cifs-2.6.git] / arch / x86 / kernel / reboot.c
index 3adbe97015c1344ce23b896356c89fe1dd7d0de8..830425e6d38e2f75fb9ea41f7dc042e175d98846 100644 (file)
@@ -22,7 +22,6 @@
 #include <asm/reboot_fixups.h>
 #include <asm/reboot.h>
 #include <asm/pci_x86.h>
-#include <asm/virtext.h>
 #include <asm/cpu.h>
 #include <asm/nmi.h>
 #include <asm/smp.h>
@@ -530,9 +529,54 @@ static inline void kb_wait(void)
 
 static inline void nmi_shootdown_cpus_on_restart(void);
 
+#if IS_ENABLED(CONFIG_KVM_INTEL) || IS_ENABLED(CONFIG_KVM_AMD)
+/* RCU-protected callback to disable virtualization prior to reboot. */
+static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback;
+
+void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback)
+{
+       if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback)))
+               return;
+
+       rcu_assign_pointer(cpu_emergency_virt_callback, callback);
+}
+EXPORT_SYMBOL_GPL(cpu_emergency_register_virt_callback);
+
+void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback)
+{
+       if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback) != callback))
+               return;
+
+       rcu_assign_pointer(cpu_emergency_virt_callback, NULL);
+       synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback);
+
+/*
+ * Disable virtualization, i.e. VMX or SVM, to ensure INIT is recognized during
+ * reboot.  VMX blocks INIT if the CPU is post-VMXON, and SVM blocks INIT if
+ * GIF=0, i.e. if the crash occurred between CLGI and STGI.
+ */
+void cpu_emergency_disable_virtualization(void)
+{
+       cpu_emergency_virt_cb *callback;
+
+       /*
+        * IRQs must be disabled as KVM enables virtualization in hardware via
+        * function call IPIs, i.e. IRQs need to be disabled to guarantee
+        * virtualization stays disabled.
+        */
+       lockdep_assert_irqs_disabled();
+
+       rcu_read_lock();
+       callback = rcu_dereference(cpu_emergency_virt_callback);
+       if (callback)
+               callback();
+       rcu_read_unlock();
+}
+
 static void emergency_reboot_disable_virtualization(void)
 {
-       /* Just make sure we won't change CPUs while doing this */
        local_irq_disable();
 
        /*
@@ -545,7 +589,7 @@ static void emergency_reboot_disable_virtualization(void)
         * Do the NMI shootdown even if virtualization is off on _this_ CPU, as
         * other CPUs may have virtualization enabled.
         */
-       if (cpu_has_vmx() || cpu_has_svm(NULL)) {
+       if (rcu_access_pointer(cpu_emergency_virt_callback)) {
                /* Safely force _this_ CPU out of VMX/SVM operation. */
                cpu_emergency_disable_virtualization();
 
@@ -553,7 +597,9 @@ static void emergency_reboot_disable_virtualization(void)
                nmi_shootdown_cpus_on_restart();
        }
 }
-
+#else
+static void emergency_reboot_disable_virtualization(void) { }
+#endif /* CONFIG_KVM_INTEL || CONFIG_KVM_AMD */
 
 void __attribute__((weak)) mach_reboot_fixups(void)
 {
@@ -787,21 +833,9 @@ void machine_crash_shutdown(struct pt_regs *regs)
 }
 #endif
 
-
 /* This is the CPU performing the emergency shutdown work. */
 int crashing_cpu = -1;
 
-/*
- * Disable virtualization, i.e. VMX or SVM, to ensure INIT is recognized during
- * reboot.  VMX blocks INIT if the CPU is post-VMXON, and SVM blocks INIT if
- * GIF=0, i.e. if the crash occurred between CLGI and STGI.
- */
-void cpu_emergency_disable_virtualization(void)
-{
-       cpu_emergency_vmxoff();
-       cpu_emergency_svm_disable();
-}
-
 #if defined(CONFIG_SMP)
 
 static nmi_shootdown_cb shootdown_callback;