aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hv
diff options
context:
space:
mode:
authorVitaly Kuznetsov <vkuznets@redhat.com>2016-06-03 20:09:22 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-08-31 07:05:40 -0400
commita9f61ca793becabdefab03b77568d6c6f8c1bc79 (patch)
tree422f0e2eb47880341e6ebe69a1afa918458c4dd4 /drivers/hv
parent069b188f43d9a44422eb35a8f95533d2c44ad315 (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.c8
-rw-r--r--drivers/hv/hyperv_vmbus.h2
-rw-r--r--drivers/hv/vmbus_drv.c8
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 */
281void hv_cleanup(void) 281void 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
496extern int hv_init(void); 496extern int hv_init(void);
497 497
498extern void hv_cleanup(void); 498extern void hv_cleanup(bool crash);
499 499
500extern int hv_post_message(union hv_connection_id connection_id, 500extern 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
876err_cleanup: 876err_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
1332static void hv_crash_handler(struct pt_regs *regs) 1332static 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
1344static int __init hv_acpi_init(void) 1344static 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);