]> Git Repo - linux.git/commitdiff
x86/Hyper-V: Unload vmbus channel in hv panic callback
authorTianyu Lan <[email protected]>
Mon, 6 Apr 2020 15:53:26 +0000 (08:53 -0700)
committerWei Liu <[email protected]>
Fri, 10 Apr 2020 14:29:00 +0000 (15:29 +0100)
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 <[email protected]>
Signed-off-by: Tianyu Lan <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Wei Liu <[email protected]>
drivers/hv/channel_mgmt.c
drivers/hv/vmbus_drv.c

index 0370364169c4ec2ebc09218395f41615b9f49cd5..501c43c5851dcc503edaff6c19cfc5b0d4df4a66 100644 (file)
@@ -839,6 +839,9 @@ void vmbus_initiate_unload(bool crash)
 {
        struct vmbus_channel_message_header hdr;
 
+       if (xchg(&vmbus_connection.conn_state, DISCONNECTED) == DISCONNECTED)
+               return;
+
        /* Pre-Win2012R2 hosts don't support reconnect */
        if (vmbus_proto_version < VERSION_WIN8_1)
                return;
index 029378c27421d1b30a168dbe25c1ba13c4c8de57..6478240d11ab46514282e6eb776dd4774f850891 100644 (file)
@@ -53,9 +53,12 @@ static int hyperv_panic_event(struct notifier_block *nb, unsigned long val,
 {
        struct pt_regs *regs;
 
-       regs = current_pt_regs();
+       vmbus_initiate_unload(true);
 
-       hyperv_report_panic(regs, val);
+       if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
+               regs = current_pt_regs();
+               hyperv_report_panic(regs, val);
+       }
        return NOTIFY_DONE;
 }
 
@@ -1391,10 +1394,16 @@ static int vmbus_bus_init(void)
                }
 
                register_die_notifier(&hyperv_die_block);
-               atomic_notifier_chain_register(&panic_notifier_list,
-                                              &hyperv_panic_block);
        }
 
+       /*
+        * Always register the panic notifier because we need to unload
+        * the VMbus channel connection to prevent any VMbus
+        * activity after the VM panics.
+        */
+       atomic_notifier_chain_register(&panic_notifier_list,
+                              &hyperv_panic_block);
+
        vmbus_request_offers();
 
        return 0;
@@ -2204,8 +2213,6 @@ static int vmbus_bus_suspend(struct device *dev)
 
        vmbus_initiate_unload(false);
 
-       vmbus_connection.conn_state = DISCONNECTED;
-
        /* Reset the event for the next resume. */
        reinit_completion(&vmbus_connection.ready_for_resume_event);
 
@@ -2289,7 +2296,6 @@ static void hv_kexec_handler(void)
 {
        hv_stimer_global_cleanup();
        vmbus_initiate_unload(false);
-       vmbus_connection.conn_state = DISCONNECTED;
        /* Make sure conn_state is set as hv_synic_cleanup checks for it */
        mb();
        cpuhp_remove_state(hyperv_cpuhp_online);
@@ -2306,7 +2312,6 @@ static void hv_crash_handler(struct pt_regs *regs)
         * doing the cleanup for current CPU only. This should be sufficient
         * for kdump.
         */
-       vmbus_connection.conn_state = DISCONNECTED;
        cpu = smp_processor_id();
        hv_stimer_cleanup(cpu);
        hv_synic_disable_regs(cpu);
This page took 0.06966 seconds and 4 git commands to generate.