Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/Hyper-V: Unload vmbus channel in hv panic callback

When kdump is not configured, a Hyper-V VM might still respond to
network traffic after a kernel panic when kernel parameter panic=0.
The panic CPU goes into an infinite loop with interrupts enabled,
and the VMbus driver interrupt handler still works because the
VMbus connection is unloaded only in the kdump path. The network
responses make the other end of the connection think the VM is
still functional even though it has panic'ed, which could affect any
failover actions that should be taken.

Fix this by unloading the VMbus connection during the panic process.
vmbus_initiate_unload() could then be called twice (e.g., by
hyperv_panic_event() and hv_crash_handler(), so reset the connection
state in vmbus_initiate_unload() to ensure the unload is done only
once.

Fixes: 81b18bce48af ("Drivers: HV: Send one page worth of kmsg dump over Hyper-V during panic")
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
Link: https://lore.kernel.org/r/20200406155331.2105-2-Tianyu.Lan@microsoft.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Tianyu Lan and committed by
Wei Liu
74347a99 97d9f1c4

+16 -8
+3
drivers/hv/channel_mgmt.c
··· 839 839 { 840 840 struct vmbus_channel_message_header hdr; 841 841 842 + if (xchg(&vmbus_connection.conn_state, DISCONNECTED) == DISCONNECTED) 843 + return; 844 + 842 845 /* Pre-Win2012R2 hosts don't support reconnect */ 843 846 if (vmbus_proto_version < VERSION_WIN8_1) 844 847 return;
+13 -8
drivers/hv/vmbus_drv.c
··· 53 53 { 54 54 struct pt_regs *regs; 55 55 56 - regs = current_pt_regs(); 56 + vmbus_initiate_unload(true); 57 57 58 - hyperv_report_panic(regs, val); 58 + if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { 59 + regs = current_pt_regs(); 60 + hyperv_report_panic(regs, val); 61 + } 59 62 return NOTIFY_DONE; 60 63 } 61 64 ··· 1394 1391 } 1395 1392 1396 1393 register_die_notifier(&hyperv_die_block); 1397 - atomic_notifier_chain_register(&panic_notifier_list, 1398 - &hyperv_panic_block); 1399 1394 } 1395 + 1396 + /* 1397 + * Always register the panic notifier because we need to unload 1398 + * the VMbus channel connection to prevent any VMbus 1399 + * activity after the VM panics. 1400 + */ 1401 + atomic_notifier_chain_register(&panic_notifier_list, 1402 + &hyperv_panic_block); 1400 1403 1401 1404 vmbus_request_offers(); 1402 1405 ··· 2213 2204 2214 2205 vmbus_initiate_unload(false); 2215 2206 2216 - vmbus_connection.conn_state = DISCONNECTED; 2217 - 2218 2207 /* Reset the event for the next resume. */ 2219 2208 reinit_completion(&vmbus_connection.ready_for_resume_event); 2220 2209 ··· 2296 2289 { 2297 2290 hv_stimer_global_cleanup(); 2298 2291 vmbus_initiate_unload(false); 2299 - vmbus_connection.conn_state = DISCONNECTED; 2300 2292 /* Make sure conn_state is set as hv_synic_cleanup checks for it */ 2301 2293 mb(); 2302 2294 cpuhp_remove_state(hyperv_cpuhp_online); ··· 2312 2306 * doing the cleanup for current CPU only. This should be sufficient 2313 2307 * for kdump. 2314 2308 */ 2315 - vmbus_connection.conn_state = DISCONNECTED; 2316 2309 cpu = smp_processor_id(); 2317 2310 hv_stimer_cleanup(cpu); 2318 2311 hv_synic_disable_regs(cpu);