aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hv
diff options
context:
space:
mode:
authorVitaly Kuznetsov <vkuznets@redhat.com>2016-01-28 01:29:35 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-02-08 00:34:12 -0500
commit415719160de3fae3bb9cbc617664649919cd00d0 (patch)
treebf877b7cbe41b2e137b52ab584310e3c1605597b /drivers/hv
parent79fd8e706637a5c7c41f9498fe0fbfb437abfdc8 (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.c44
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
593static 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/*