summaryrefslogtreecommitdiff
path: root/drivers/hv/vmbus_drv.c
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2017-05-01 02:21:18 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-18 17:55:28 +0300
commit54a66265d6754b37fb4baf1d970ec88a6225a988 (patch)
tree308f05e5a3e1c693fc8c5952ec2ecc942baab42e /drivers/hv/vmbus_drv.c
parent1e052a16eb2caf6727b594cad0744ccdfddf4254 (diff)
downloadlinux-54a66265d6754b37fb4baf1d970ec88a6225a988.tar.xz
Drivers: hv: vmbus: Fix rescind handling
Fix the rescind handling. This patch addresses the following rescind scenario that is currently not handled correctly: If a rescind were to be received while the offer is still being peocessed, we will be blocked indefinitely since the rescind message is handled on the same work element as the offer message. Fix this issue. I would like to thank Dexuan Cui <decui@microsoft.com> and Long Li <longli@microsoft.com> for working with me on this patch. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv/vmbus_drv.c')
-rw-r--r--drivers/hv/vmbus_drv.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 0087b49095eb..59bb3efa6e10 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -798,8 +798,10 @@ static void vmbus_device_release(struct device *device)
struct hv_device *hv_dev = device_to_hv_device(device);
struct vmbus_channel *channel = hv_dev->channel;
+ mutex_lock(&vmbus_connection.channel_mutex);
hv_process_channel_removal(channel,
channel->offermsg.child_relid);
+ mutex_unlock(&vmbus_connection.channel_mutex);
kfree(hv_dev);
}
@@ -877,7 +879,32 @@ void vmbus_on_msg_dpc(unsigned long data)
INIT_WORK(&ctx->work, vmbus_onmessage_work);
memcpy(&ctx->msg, msg, sizeof(*msg));
- queue_work(vmbus_connection.work_queue, &ctx->work);
+ /*
+ * The host can generate a rescind message while we
+ * may still be handling the original offer. We deal with
+ * this condition by ensuring the processing is done on the
+ * same CPU.
+ */
+ switch (hdr->msgtype) {
+ case CHANNELMSG_RESCIND_CHANNELOFFER:
+ /*
+ * If we are handling the rescind message;
+ * schedule the work on the global work queue.
+ */
+ schedule_work_on(vmbus_connection.connect_cpu,
+ &ctx->work);
+ break;
+
+ case CHANNELMSG_OFFERCHANNEL:
+ atomic_inc(&vmbus_connection.offer_in_progress);
+ queue_work_on(vmbus_connection.connect_cpu,
+ vmbus_connection.work_queue,
+ &ctx->work);
+ break;
+
+ default:
+ queue_work(vmbus_connection.work_queue, &ctx->work);
+ }
} else
entry->message_handler(hdr);