aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDexuan Cui <decui@microsoft.com>2015-03-27 12:10:08 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-04-03 10:18:01 -0400
commit652594c7dfd9bf6392e3a727bc69d89a2562d953 (patch)
tree6f40c87328a8d8e2880d8a4a6feb3f3fdb1c6caf
parent01081f5ab9916603555f236b11f76bb00e4e01e9 (diff)
hv: run non-blocking message handlers in the dispatch tasklet
A work item in vmbus_connection.work_queue can sleep, waiting for a new host message (usually it is some kind of "completion" message). Currently the new message will be handled in the same workqueue, but since work items in the workqueue is serialized, we actually have no chance to handle the new message if the current work item is sleeping -- as as result, the current work item will hang forever. K. Y. has posted the below fix to resolve the issue: Drivers: hv: vmbus: Perform device register in the per-channel work element Actually we can simplify the fix by directly running non-blocking message handlers in the dispatch tasklet (inspired by K. Y.). This patch is the fundamental change. The following 2 patches will simplify the message offering and rescind-offering handling a lot. Signed-off-by: Dexuan Cui <decui@microsoft.com> Cc: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/hv/channel_mgmt.c41
-rw-r--r--drivers/hv/hyperv_vmbus.h17
-rw-r--r--drivers/hv/vmbus_drv.c21
3 files changed, 53 insertions, 26 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index bb39705a89d9..287f07b1bef6 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -33,11 +33,6 @@
33 33
34#include "hyperv_vmbus.h" 34#include "hyperv_vmbus.h"
35 35
36struct vmbus_channel_message_table_entry {
37 enum vmbus_channel_message_type message_type;
38 void (*message_handler)(struct vmbus_channel_message_header *msg);
39};
40
41struct vmbus_rescind_work { 36struct vmbus_rescind_work {
42 struct work_struct work; 37 struct work_struct work;
43 struct vmbus_channel *channel; 38 struct vmbus_channel *channel;
@@ -827,25 +822,25 @@ static void vmbus_onversion_response(
827} 822}
828 823
829/* Channel message dispatch table */ 824/* Channel message dispatch table */
830static struct vmbus_channel_message_table_entry 825struct vmbus_channel_message_table_entry
831 channel_message_table[CHANNELMSG_COUNT] = { 826 channel_message_table[CHANNELMSG_COUNT] = {
832 {CHANNELMSG_INVALID, NULL}, 827 {CHANNELMSG_INVALID, 0, NULL},
833 {CHANNELMSG_OFFERCHANNEL, vmbus_onoffer}, 828 {CHANNELMSG_OFFERCHANNEL, 0, vmbus_onoffer},
834 {CHANNELMSG_RESCIND_CHANNELOFFER, vmbus_onoffer_rescind}, 829 {CHANNELMSG_RESCIND_CHANNELOFFER, 0, vmbus_onoffer_rescind},
835 {CHANNELMSG_REQUESTOFFERS, NULL}, 830 {CHANNELMSG_REQUESTOFFERS, 0, NULL},
836 {CHANNELMSG_ALLOFFERS_DELIVERED, vmbus_onoffers_delivered}, 831 {CHANNELMSG_ALLOFFERS_DELIVERED, 1, vmbus_onoffers_delivered},
837 {CHANNELMSG_OPENCHANNEL, NULL}, 832 {CHANNELMSG_OPENCHANNEL, 0, NULL},
838 {CHANNELMSG_OPENCHANNEL_RESULT, vmbus_onopen_result}, 833 {CHANNELMSG_OPENCHANNEL_RESULT, 1, vmbus_onopen_result},
839 {CHANNELMSG_CLOSECHANNEL, NULL}, 834 {CHANNELMSG_CLOSECHANNEL, 0, NULL},
840 {CHANNELMSG_GPADL_HEADER, NULL}, 835 {CHANNELMSG_GPADL_HEADER, 0, NULL},
841 {CHANNELMSG_GPADL_BODY, NULL}, 836 {CHANNELMSG_GPADL_BODY, 0, NULL},
842 {CHANNELMSG_GPADL_CREATED, vmbus_ongpadl_created}, 837 {CHANNELMSG_GPADL_CREATED, 1, vmbus_ongpadl_created},
843 {CHANNELMSG_GPADL_TEARDOWN, NULL}, 838 {CHANNELMSG_GPADL_TEARDOWN, 0, NULL},
844 {CHANNELMSG_GPADL_TORNDOWN, vmbus_ongpadl_torndown}, 839 {CHANNELMSG_GPADL_TORNDOWN, 1, vmbus_ongpadl_torndown},
845 {CHANNELMSG_RELID_RELEASED, NULL}, 840 {CHANNELMSG_RELID_RELEASED, 0, NULL},
846 {CHANNELMSG_INITIATE_CONTACT, NULL}, 841 {CHANNELMSG_INITIATE_CONTACT, 0, NULL},
847 {CHANNELMSG_VERSION_RESPONSE, vmbus_onversion_response}, 842 {CHANNELMSG_VERSION_RESPONSE, 1, vmbus_onversion_response},
848 {CHANNELMSG_UNLOAD, NULL}, 843 {CHANNELMSG_UNLOAD, 0, NULL},
849}; 844};
850 845
851/* 846/*
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index c8e27e0fdc99..f40a5a935ab6 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -685,6 +685,23 @@ struct vmbus_msginfo {
685 685
686extern struct vmbus_connection vmbus_connection; 686extern struct vmbus_connection vmbus_connection;
687 687
688enum vmbus_message_handler_type {
689 /* The related handler can sleep. */
690 VMHT_BLOCKING = 0,
691
692 /* The related handler must NOT sleep. */
693 VMHT_NON_BLOCKING = 1,
694};
695
696struct vmbus_channel_message_table_entry {
697 enum vmbus_channel_message_type message_type;
698 enum vmbus_message_handler_type handler_type;
699 void (*message_handler)(struct vmbus_channel_message_header *msg);
700};
701
702extern struct vmbus_channel_message_table_entry
703 channel_message_table[CHANNELMSG_COUNT];
704
688/* General vmbus interface */ 705/* General vmbus interface */
689 706
690struct hv_device *vmbus_device_create(const uuid_le *type, 707struct hv_device *vmbus_device_create(const uuid_le *type,
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 8313e25378cb..c85235e9f245 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -657,21 +657,36 @@ static void vmbus_on_msg_dpc(unsigned long data)
657 void *page_addr = hv_context.synic_message_page[cpu]; 657 void *page_addr = hv_context.synic_message_page[cpu];
658 struct hv_message *msg = (struct hv_message *)page_addr + 658 struct hv_message *msg = (struct hv_message *)page_addr +
659 VMBUS_MESSAGE_SINT; 659 VMBUS_MESSAGE_SINT;
660 struct vmbus_channel_message_header *hdr;
661 struct vmbus_channel_message_table_entry *entry;
660 struct onmessage_work_context *ctx; 662 struct onmessage_work_context *ctx;
661 663
662 while (1) { 664 while (1) {
663 if (msg->header.message_type == HVMSG_NONE) { 665 if (msg->header.message_type == HVMSG_NONE)
664 /* no msg */ 666 /* no msg */
665 break; 667 break;
666 } else { 668
669 hdr = (struct vmbus_channel_message_header *)msg->u.payload;
670
671 if (hdr->msgtype >= CHANNELMSG_COUNT) {
672 WARN_ONCE(1, "unknown msgtype=%d\n", hdr->msgtype);
673 goto msg_handled;
674 }
675
676 entry = &channel_message_table[hdr->msgtype];
677 if (entry->handler_type == VMHT_BLOCKING) {
667 ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC); 678 ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
668 if (ctx == NULL) 679 if (ctx == NULL)
669 continue; 680 continue;
681
670 INIT_WORK(&ctx->work, vmbus_onmessage_work); 682 INIT_WORK(&ctx->work, vmbus_onmessage_work);
671 memcpy(&ctx->msg, msg, sizeof(*msg)); 683 memcpy(&ctx->msg, msg, sizeof(*msg));
684
672 queue_work(vmbus_connection.work_queue, &ctx->work); 685 queue_work(vmbus_connection.work_queue, &ctx->work);
673 } 686 } else
687 entry->message_handler(hdr);
674 688
689msg_handled:
675 msg->header.message_type = HVMSG_NONE; 690 msg->header.message_type = HVMSG_NONE;
676 691
677 /* 692 /*