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

Drivers: hv: vmbus: Increase wait time for VMbus unload

When running in Azure, disks may be connected to a Linux VM with
read/write caching enabled. If a VM panics and issues a VMbus
UNLOAD request to Hyper-V, the response is delayed until all dirty
data in the disk cache is flushed. In extreme cases, this flushing
can take 10's of seconds, depending on the disk speed and the amount
of dirty data. If kdump is configured for the VM, the current 10 second
timeout in vmbus_wait_for_unload() may be exceeded, and the UNLOAD
complete message may arrive well after the kdump kernel is already
running, causing problems. Note that no problem occurs if kdump is
not enabled because Hyper-V waits for the cache flush before doing
a reboot through the BIOS/UEFI code.

Fix this problem by increasing the timeout in vmbus_wait_for_unload()
to 100 seconds. Also output periodic messages so that if anyone is
watching the serial console, they won't think the VM is completely
hung.

Fixes: 911e1987efc8 ("Drivers: hv: vmbus: Add timeout to vmbus_wait_for_unload")
Signed-off-by: Michael Kelley <mikelley@microsoft.com>
Reviewed-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Link: https://lore.kernel.org/r/1618894089-126662-1-git-send-email-mikelley@microsoft.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Michael Kelley and committed by
Wei Liu
77db0ec8 8c2d5e06

+26 -6
+26 -6
drivers/hv/channel_mgmt.c
··· 755 755 free_cpumask_var(available_mask); 756 756 } 757 757 758 + #define UNLOAD_DELAY_UNIT_MS 10 /* 10 milliseconds */ 759 + #define UNLOAD_WAIT_MS (100*1000) /* 100 seconds */ 760 + #define UNLOAD_WAIT_LOOPS (UNLOAD_WAIT_MS/UNLOAD_DELAY_UNIT_MS) 761 + #define UNLOAD_MSG_MS (5*1000) /* Every 5 seconds */ 762 + #define UNLOAD_MSG_LOOPS (UNLOAD_MSG_MS/UNLOAD_DELAY_UNIT_MS) 763 + 758 764 static void vmbus_wait_for_unload(void) 759 765 { 760 766 int cpu; ··· 778 772 * vmbus_connection.unload_event. If not, the last thing we can do is 779 773 * read message pages for all CPUs directly. 780 774 * 781 - * Wait no more than 10 seconds so that the panic path can't get 782 - * hung forever in case the response message isn't seen. 775 + * Wait up to 100 seconds since an Azure host must writeback any dirty 776 + * data in its disk cache before the VMbus UNLOAD request will 777 + * complete. This flushing has been empirically observed to take up 778 + * to 50 seconds in cases with a lot of dirty data, so allow additional 779 + * leeway and for inaccuracies in mdelay(). But eventually time out so 780 + * that the panic path can't get hung forever in case the response 781 + * message isn't seen. 783 782 */ 784 - for (i = 0; i < 1000; i++) { 783 + for (i = 1; i <= UNLOAD_WAIT_LOOPS; i++) { 785 784 if (completion_done(&vmbus_connection.unload_event)) 786 - break; 785 + goto completed; 787 786 788 787 for_each_online_cpu(cpu) { 789 788 struct hv_per_cpu_context *hv_cpu ··· 811 800 vmbus_signal_eom(msg, message_type); 812 801 } 813 802 814 - mdelay(10); 815 - } 803 + /* 804 + * Give a notice periodically so someone watching the 805 + * serial output won't think it is completely hung. 806 + */ 807 + if (!(i % UNLOAD_MSG_LOOPS)) 808 + pr_notice("Waiting for VMBus UNLOAD to complete\n"); 816 809 810 + mdelay(UNLOAD_DELAY_UNIT_MS); 811 + } 812 + pr_err("Continuing even though VMBus UNLOAD did not complete\n"); 813 + 814 + completed: 817 815 /* 818 816 * We're crashing and already got the UNLOAD_RESPONSE, cleanup all 819 817 * maybe-pending messages on all CPUs to be able to receive new