summaryrefslogtreecommitdiff
path: root/drivers/hv/channel_mgmt.c
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2016-12-22 16:54:00 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-12 06:41:49 +0100
commit728fe696fd3ee551c24e02e7826dd9bdb89f1d47 (patch)
tree827a29cec12f66fbd9c6a36024e41a71e7ad81be /drivers/hv/channel_mgmt.c
parente44eab51e74c59a0b01c1fce2159c82b3c8a31b0 (diff)
Drivers: hv: vmbus: Fix a rescind handling bug
commit ccb61f8a99e6c29df4fb96a65dad4fad740d5be9 upstream. The host can rescind a channel that has been offered to the guest and once the channel is rescinded, the host does not respond to any requests on that channel. Deal with the case where the guest may be blocked waiting for a response from the host. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv/channel_mgmt.c')
-rw-r--r--drivers/hv/channel_mgmt.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index f3a8b52acb51..cb9531541a12 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -147,6 +147,29 @@ static const struct {
{ HV_RDV_GUID },
};
+/*
+ * The rescinded channel may be blocked waiting for a response from the host;
+ * take care of that.
+ */
+static void vmbus_rescind_cleanup(struct vmbus_channel *channel)
+{
+ struct vmbus_channel_msginfo *msginfo;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+
+ list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
+ msglistentry) {
+
+ if (msginfo->waiting_channel == channel) {
+ complete(&msginfo->waitevent);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+}
+
static bool is_unsupported_vmbus_devs(const uuid_le *guid)
{
int i;
@@ -825,6 +848,8 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
channel->rescind = true;
spin_unlock_irqrestore(&channel->lock, flags);
+ vmbus_rescind_cleanup(channel);
+
if (channel->device_obj) {
if (channel->chn_rescind_callback) {
channel->chn_rescind_callback(channel);