Skip to content

Commit 4157191

Browse files
vittyvkgregkh
authored andcommitted
Drivers: hv: vmbus: avoid scheduling in interrupt context in vmbus_initiate_unload()
We have to call vmbus_initiate_unload() on crash to make kdump work but the crash can also be happening in interrupt (e.g. Sysrq + c results in such) where we can't schedule or the following will happen: [ 314.905786] bad: scheduling from the idle thread! Just skipping the wait (and even adding some random wait here) won't help: to make host-side magic working we're supposed to receive CHANNELMSG_UNLOAD (and actually confirm the fact that we received it) but we can't use interrupt-base path (vmbus_isr()-> vmbus_on_msg_dpc()). Implement a simple busy wait ignoring all the other messages and use it if we're in an interrupt context. Signed-off-by: Vitaly Kuznetsov <[email protected]> Signed-off-by: K. Y. Srinivasan <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 79fd8e7 commit 4157191

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

drivers/hv/channel_mgmt.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <linux/list.h>
2929
#include <linux/module.h>
3030
#include <linux/completion.h>
31+
#include <linux/delay.h>
3132
#include <linux/hyperv.h>
3233

3334
#include "hyperv_vmbus.h"
@@ -589,6 +590,40 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
589590
channel->target_vp = hv_context.vp_index[cur_cpu];
590591
}
591592

593+
static void vmbus_wait_for_unload(void)
594+
{
595+
int cpu = smp_processor_id();
596+
void *page_addr = hv_context.synic_message_page[cpu];
597+
struct hv_message *msg = (struct hv_message *)page_addr +
598+
VMBUS_MESSAGE_SINT;
599+
struct vmbus_channel_message_header *hdr;
600+
bool unloaded = false;
601+
602+
while (1) {
603+
if (msg->header.message_type == HVMSG_NONE) {
604+
mdelay(10);
605+
continue;
606+
}
607+
608+
hdr = (struct vmbus_channel_message_header *)msg->u.payload;
609+
if (hdr->msgtype == CHANNELMSG_UNLOAD_RESPONSE)
610+
unloaded = true;
611+
612+
msg->header.message_type = HVMSG_NONE;
613+
/*
614+
* header.message_type needs to be written before we do
615+
* wrmsrl() below.
616+
*/
617+
mb();
618+
619+
if (msg->header.message_flags.msg_pending)
620+
wrmsrl(HV_X64_MSR_EOM, 0);
621+
622+
if (unloaded)
623+
break;
624+
}
625+
}
626+
592627
/*
593628
* vmbus_unload_response - Handler for the unload response.
594629
*/
@@ -614,7 +649,14 @@ void vmbus_initiate_unload(void)
614649
hdr.msgtype = CHANNELMSG_UNLOAD;
615650
vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header));
616651

617-
wait_for_completion(&vmbus_connection.unload_event);
652+
/*
653+
* vmbus_initiate_unload() is also called on crash and the crash can be
654+
* happening in an interrupt context, where scheduling is impossible.
655+
*/
656+
if (!in_interrupt())
657+
wait_for_completion(&vmbus_connection.unload_event);
658+
else
659+
vmbus_wait_for_unload();
618660
}
619661

620662
/*

0 commit comments

Comments
 (0)