]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
Drivers: hv: vmbus: add special kexec handler
authorVitaly Kuznetsov <vkuznets@redhat.com>
Sat, 1 Aug 2015 23:08:07 +0000 (16:08 -0700)
committerChuck Anderson <chuck.anderson@oracle.com>
Fri, 26 Feb 2016 02:28:58 +0000 (18:28 -0800)
When general-purpose kexec (not kdump) is being performed in Hyper-V guest
the newly booted kernel fails with an MCE error coming from the host. It
is the same error which was fixed in the "Drivers: hv: vmbus: Implement
the protocol for tearing down vmbus state" commit - monitor pages remain
special and when they're being written to (as the new kernel doesn't know
these pages are special) bad things happen. We need to perform some
minimalistic cleanup before booting a new kernel on kexec. To do so we
need to register a special machine_ops.shutdown handler to be executed
before the native_machine_shutdown(). Registering a shutdown notification
handler via the register_reboot_notifier() call is not sufficient as it
happens to early for our purposes. machine_ops is not being exported to
modules (and I don't think we want to export it) so let's do this in
mshyperv.c

The minimalistic cleanup consists of cleaning up clockevents, synic MSRs,
guest os id MSR, and hypercall MSR.

Kdump doesn't require all this stuff as it lives in a separate memory
space.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 2517281d63a2b09d94aedfb522943617048f337e)

Orabug: 21886720
Signed-off-by: Jason Luo <zhangqing.luo@oracle.com>
arch/x86/include/asm/mshyperv.h
arch/x86/kernel/cpu/mshyperv.c
drivers/hv/vmbus_drv.c

index c163215abb9ad99ee1c9eac3210acfb0380614b6..d3db9108346bed4d8fb316c50aa415556366c24c 100644 (file)
@@ -20,4 +20,6 @@ void hyperv_vector_handler(struct pt_regs *regs);
 void hv_setup_vmbus_irq(void (*handler)(void));
 void hv_remove_vmbus_irq(void);
 
+void hv_setup_kexec_handler(void (*handler)(void));
+void hv_remove_kexec_handler(void);
 #endif
index 939155ffdecec60628a06b2937604dd2f2f98813..09911aa8a647b5e691d1fa40267f3bb11cb5a809 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/efi.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/kexec.h>
 #include <asm/processor.h>
 #include <asm/hypervisor.h>
 #include <asm/hyperv.h>
 #include <asm/i8259.h>
 #include <asm/apic.h>
 #include <asm/timer.h>
+#include <asm/reboot.h>
 
 struct ms_hyperv_info ms_hyperv;
 EXPORT_SYMBOL_GPL(ms_hyperv);
 
+static void (*hv_kexec_handler)(void);
+
 #if IS_ENABLED(CONFIG_HYPERV)
 static void (*vmbus_handler)(void);
 
@@ -69,8 +73,27 @@ void hv_remove_vmbus_irq(void)
 }
 EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq);
 EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq);
+
+void hv_setup_kexec_handler(void (*handler)(void))
+{
+       hv_kexec_handler = handler;
+}
+EXPORT_SYMBOL_GPL(hv_setup_kexec_handler);
+
+void hv_remove_kexec_handler(void)
+{
+       hv_kexec_handler = NULL;
+}
+EXPORT_SYMBOL_GPL(hv_remove_kexec_handler);
 #endif
 
+static void hv_machine_shutdown(void)
+{
+       if (kexec_in_progress && hv_kexec_handler)
+               hv_kexec_handler();
+       native_machine_shutdown();
+}
+
 static uint32_t  __init ms_hyperv_platform(void)
 {
        u32 eax;
@@ -143,6 +166,7 @@ static void __init ms_hyperv_init_platform(void)
        no_timer_check = 1;
 #endif
 
+       machine_ops.shutdown = hv_machine_shutdown;
 }
 
 const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
index f198bf9810a175b2d8f2dcc8c141e32fdd34a425..3ae58f8c8358e44f4dbfd5e140879a3ec669169a 100644 (file)
@@ -1050,6 +1050,17 @@ static struct acpi_driver vmbus_acpi_driver = {
        },
 };
 
+static void hv_kexec_handler(void)
+{
+       int cpu;
+
+       hv_synic_clockevents_cleanup();
+       vmbus_initiate_unload();
+       for_each_online_cpu(cpu)
+               smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
+       hv_cleanup();
+};
+
 static int __init hv_acpi_init(void)
 {
        int ret, t;
@@ -1082,6 +1093,8 @@ static int __init hv_acpi_init(void)
        if (ret)
                goto cleanup;
 
+       hv_setup_kexec_handler(hv_kexec_handler);
+
        return 0;
 
 cleanup:
@@ -1094,6 +1107,7 @@ static void __exit vmbus_exit(void)
 {
        int cpu;
 
+       hv_remove_kexec_handler();
        vmbus_connection.conn_state = DISCONNECTED;
        hv_synic_clockevents_cleanup();
        vmbus_disconnect();