Drivers: hv: avoid vfree() on crash
authorVitaly Kuznetsov <vkuznets@redhat.com>
Sat, 4 Jun 2016 00:09:22 +0000 (17:09 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 31 Aug 2016 11:05:40 +0000 (13:05 +0200)
When we crash from NMI context (e.g. after NMI injection from host when
'sysctl -w kernel.unknown_nmi_panic=1' is set) we hit

    kernel BUG at mm/vmalloc.c:1530!

as vfree() is denied. While the issue could be solved with in_nmi() check
instead I opted for skipping vfree on all sorts of crashes to reduce the
amount of work which can cause consequent crashes. We don't really need to
free anything on crash.

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>
drivers/hv/hv.c
drivers/hv/hyperv_vmbus.h
drivers/hv/vmbus_drv.c

index a1c086ba3b9a0736c522d648092d04d4ac92a3c7..60dbd6cb4640cd6caeb36a8c07585660d812f3b9 100644 (file)
@@ -278,7 +278,7 @@ cleanup:
  *
  * This routine is called normally during driver unloading or exiting.
  */
-void hv_cleanup(void)
+void hv_cleanup(bool crash)
 {
        union hv_x64_msr_hypercall_contents hypercall_msr;
 
@@ -288,7 +288,8 @@ void hv_cleanup(void)
        if (hv_context.hypercall_page) {
                hypercall_msr.as_uint64 = 0;
                wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-               vfree(hv_context.hypercall_page);
+               if (!crash)
+                       vfree(hv_context.hypercall_page);
                hv_context.hypercall_page = NULL;
        }
 
@@ -308,7 +309,8 @@ void hv_cleanup(void)
 
                hypercall_msr.as_uint64 = 0;
                wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
-               vfree(hv_context.tsc_page);
+               if (!crash)
+                       vfree(hv_context.tsc_page);
                hv_context.tsc_page = NULL;
        }
 #endif
index 718b5c72f0c8bd86a8a1a6caba5b556e60c1b6f8..dfa9fac100d8dd505894475ffd76192e4eff9d50 100644 (file)
@@ -495,7 +495,7 @@ struct hv_ring_buffer_debug_info {
 
 extern int hv_init(void);
 
-extern void hv_cleanup(void);
+extern void hv_cleanup(bool crash);
 
 extern int hv_post_message(union hv_connection_id connection_id,
                         enum hv_message_type message_type,
index e82f7e1c217cbfcfb39ed9c0e87876c78f3a22b5..fedf6298ec0b060cbacee696888a0af9b5c6ce2f 100644 (file)
@@ -874,7 +874,7 @@ err_alloc:
        bus_unregister(&hv_bus);
 
 err_cleanup:
-       hv_cleanup();
+       hv_cleanup(false);
 
        return ret;
 }
@@ -1326,7 +1326,7 @@ static void hv_kexec_handler(void)
        vmbus_initiate_unload(false);
        for_each_online_cpu(cpu)
                smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
-       hv_cleanup();
+       hv_cleanup(false);
 };
 
 static void hv_crash_handler(struct pt_regs *regs)
@@ -1338,7 +1338,7 @@ static void hv_crash_handler(struct pt_regs *regs)
         * for kdump.
         */
        hv_synic_cleanup(NULL);
-       hv_cleanup();
+       hv_cleanup(true);
 };
 
 static int __init hv_acpi_init(void)
@@ -1398,7 +1398,7 @@ static void __exit vmbus_exit(void)
                                                 &hyperv_panic_block);
        }
        bus_unregister(&hv_bus);
-       hv_cleanup();
+       hv_cleanup(false);
        for_each_online_cpu(cpu) {
                tasklet_kill(hv_context.event_dpc[cpu]);
                smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);