diff options
author | Vitaly Kuznetsov <vkuznets@redhat.com> | 2016-01-28 01:29:35 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-02-08 00:34:12 -0500 |
commit | 415719160de3fae3bb9cbc617664649919cd00d0 (patch) | |
tree | bf877b7cbe41b2e137b52ab584310e3c1605597b /drivers/hv | |
parent | 79fd8e706637a5c7c41f9498fe0fbfb437abfdc8 (diff) |
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 <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/channel_mgmt.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index af1d82eb8ecf..d6c611457601 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/completion.h> | 30 | #include <linux/completion.h> |
31 | #include <linux/delay.h> | ||
31 | #include <linux/hyperv.h> | 32 | #include <linux/hyperv.h> |
32 | 33 | ||
33 | #include "hyperv_vmbus.h" | 34 | #include "hyperv_vmbus.h" |
@@ -589,6 +590,40 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) | |||
589 | channel->target_vp = hv_context.vp_index[cur_cpu]; | 590 | channel->target_vp = hv_context.vp_index[cur_cpu]; |
590 | } | 591 | } |
591 | 592 | ||
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 | |||
592 | /* | 627 | /* |
593 | * vmbus_unload_response - Handler for the unload response. | 628 | * vmbus_unload_response - Handler for the unload response. |
594 | */ | 629 | */ |
@@ -614,7 +649,14 @@ void vmbus_initiate_unload(void) | |||
614 | hdr.msgtype = CHANNELMSG_UNLOAD; | 649 | hdr.msgtype = CHANNELMSG_UNLOAD; |
615 | vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header)); | 650 | vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header)); |
616 | 651 | ||
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(); | ||
618 | } | 660 | } |
619 | 661 | ||
620 | /* | 662 | /* |