summaryrefslogtreecommitdiff
path: root/drivers/hv/vmbus_drv.c
diff options
context:
space:
mode:
authorVitaly Kuznetsov <vkuznets@redhat.com>2015-08-01 16:08:07 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-08-04 22:25:29 -0700
commit2517281d63a2b09d94aedfb522943617048f337e (patch)
tree41a7a6adfa03b6cde5c4afc611202a5d21cfe873 /drivers/hv/vmbus_drv.c
parent2b94ed245861a7d378dcde6eef7fa7717e06e349 (diff)
Drivers: hv: vmbus: add special kexec handler
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>
Diffstat (limited to 'drivers/hv/vmbus_drv.c')
-rw-r--r--drivers/hv/vmbus_drv.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 00d5158b4ac7..31748a21d8f9 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -1060,6 +1060,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;
@@ -1092,6 +1103,8 @@ static int __init hv_acpi_init(void)
if (ret)
goto cleanup;
+ hv_setup_kexec_handler(hv_kexec_handler);
+
return 0;
cleanup:
@@ -1104,6 +1117,7 @@ static void __exit vmbus_exit(void)
{
int cpu;
+ hv_remove_kexec_handler();
vmbus_connection.conn_state = DISCONNECTED;
hv_synic_clockevents_cleanup();
vmbus_disconnect();