Comment 44 for bug 1400319

Revision history for this message
Joshua R. Poulson (jrp) wrote :

A consideration:

From: Vitaly Kuznetsov <email address hidden>

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 <email address hidden>
Signed-off-by: K. Y. Srinivasan <email address hidden>
---
 drivers/hv/hv.c | 8 +++++---
 drivers/hv/hyperv_vmbus.h | 2 +-
 drivers/hv/vmbus_drv.c | 8 ++++----
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index a1c086b..60dbd6c 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -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
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 718b5c7..dfa9fac 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -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,
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 952f20f..d11690e 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -871,7 +871,7 @@ err_alloc:
        bus_unregister(&hv_bus);

 err_cleanup:
- hv_cleanup();
+ hv_cleanup(false);

        return ret;
 }
@@ -1323,7 +1323,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)
@@ -1335,7 +1335,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)
@@ -1395,7 +1395,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);

--
1.7.4.1