diff options
| author | Vitaly Kuznetsov <vkuznets@redhat.com> | 2016-06-03 20:09:22 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-08-31 07:05:40 -0400 |
| commit | a9f61ca793becabdefab03b77568d6c6f8c1bc79 (patch) | |
| tree | 422f0e2eb47880341e6ebe69a1afa918458c4dd4 /drivers/hv | |
| parent | 069b188f43d9a44422eb35a8f95533d2c44ad315 (diff) | |
Drivers: hv: avoid vfree() on crash
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>
Diffstat (limited to 'drivers/hv')
| -rw-r--r-- | drivers/hv/hv.c | 8 | ||||
| -rw-r--r-- | drivers/hv/hyperv_vmbus.h | 2 | ||||
| -rw-r--r-- | 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 a1c086ba3b9a..60dbd6cb4640 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c | |||
| @@ -278,7 +278,7 @@ cleanup: | |||
| 278 | * | 278 | * |
| 279 | * This routine is called normally during driver unloading or exiting. | 279 | * This routine is called normally during driver unloading or exiting. |
| 280 | */ | 280 | */ |
| 281 | void hv_cleanup(void) | 281 | void hv_cleanup(bool crash) |
| 282 | { | 282 | { |
| 283 | union hv_x64_msr_hypercall_contents hypercall_msr; | 283 | union hv_x64_msr_hypercall_contents hypercall_msr; |
| 284 | 284 | ||
| @@ -288,7 +288,8 @@ void hv_cleanup(void) | |||
| 288 | if (hv_context.hypercall_page) { | 288 | if (hv_context.hypercall_page) { |
| 289 | hypercall_msr.as_uint64 = 0; | 289 | hypercall_msr.as_uint64 = 0; |
| 290 | wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); | 290 | wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); |
| 291 | vfree(hv_context.hypercall_page); | 291 | if (!crash) |
| 292 | vfree(hv_context.hypercall_page); | ||
| 292 | hv_context.hypercall_page = NULL; | 293 | hv_context.hypercall_page = NULL; |
| 293 | } | 294 | } |
| 294 | 295 | ||
| @@ -308,7 +309,8 @@ void hv_cleanup(void) | |||
| 308 | 309 | ||
| 309 | hypercall_msr.as_uint64 = 0; | 310 | hypercall_msr.as_uint64 = 0; |
| 310 | wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64); | 311 | wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64); |
| 311 | vfree(hv_context.tsc_page); | 312 | if (!crash) |
| 313 | vfree(hv_context.tsc_page); | ||
| 312 | hv_context.tsc_page = NULL; | 314 | hv_context.tsc_page = NULL; |
| 313 | } | 315 | } |
| 314 | #endif | 316 | #endif |
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 718b5c72f0c8..dfa9fac100d8 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h | |||
| @@ -495,7 +495,7 @@ struct hv_ring_buffer_debug_info { | |||
| 495 | 495 | ||
| 496 | extern int hv_init(void); | 496 | extern int hv_init(void); |
| 497 | 497 | ||
| 498 | extern void hv_cleanup(void); | 498 | extern void hv_cleanup(bool crash); |
| 499 | 499 | ||
| 500 | extern int hv_post_message(union hv_connection_id connection_id, | 500 | extern int hv_post_message(union hv_connection_id connection_id, |
| 501 | enum hv_message_type message_type, | 501 | enum hv_message_type message_type, |
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index e82f7e1c217c..fedf6298ec0b 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c | |||
| @@ -874,7 +874,7 @@ err_alloc: | |||
| 874 | bus_unregister(&hv_bus); | 874 | bus_unregister(&hv_bus); |
| 875 | 875 | ||
| 876 | err_cleanup: | 876 | err_cleanup: |
| 877 | hv_cleanup(); | 877 | hv_cleanup(false); |
| 878 | 878 | ||
| 879 | return ret; | 879 | return ret; |
| 880 | } | 880 | } |
| @@ -1326,7 +1326,7 @@ static void hv_kexec_handler(void) | |||
| 1326 | vmbus_initiate_unload(false); | 1326 | vmbus_initiate_unload(false); |
| 1327 | for_each_online_cpu(cpu) | 1327 | for_each_online_cpu(cpu) |
| 1328 | smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); | 1328 | smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); |
| 1329 | hv_cleanup(); | 1329 | hv_cleanup(false); |
| 1330 | }; | 1330 | }; |
| 1331 | 1331 | ||
| 1332 | static void hv_crash_handler(struct pt_regs *regs) | 1332 | static void hv_crash_handler(struct pt_regs *regs) |
| @@ -1338,7 +1338,7 @@ static void hv_crash_handler(struct pt_regs *regs) | |||
| 1338 | * for kdump. | 1338 | * for kdump. |
| 1339 | */ | 1339 | */ |
| 1340 | hv_synic_cleanup(NULL); | 1340 | hv_synic_cleanup(NULL); |
| 1341 | hv_cleanup(); | 1341 | hv_cleanup(true); |
| 1342 | }; | 1342 | }; |
| 1343 | 1343 | ||
| 1344 | static int __init hv_acpi_init(void) | 1344 | static int __init hv_acpi_init(void) |
| @@ -1398,7 +1398,7 @@ static void __exit vmbus_exit(void) | |||
| 1398 | &hyperv_panic_block); | 1398 | &hyperv_panic_block); |
| 1399 | } | 1399 | } |
| 1400 | bus_unregister(&hv_bus); | 1400 | bus_unregister(&hv_bus); |
| 1401 | hv_cleanup(); | 1401 | hv_cleanup(false); |
| 1402 | for_each_online_cpu(cpu) { | 1402 | for_each_online_cpu(cpu) { |
| 1403 | tasklet_kill(hv_context.event_dpc[cpu]); | 1403 | tasklet_kill(hv_context.event_dpc[cpu]); |
| 1404 | smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); | 1404 | smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); |
