summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDexuan Cui <decui@microsoft.com>2019-09-05 19:01:20 -0400
committerSasha Levin <sashal@kernel.org>2019-09-06 14:52:44 -0400
commit1f48dcf180e5422b1a633b24680dd0f5c3f540f5 (patch)
tree20d79f9ecaf990857ec86829d38b89b8e39724f6
parentf53335e3289f9ac3a6a8faf6c2f819eee508bd39 (diff)
Drivers: hv: vmbus: Clean up hv_sock channels by force upon suspend
Fake RESCIND_CHANNEL messages to clean up hv_sock channels by force for hibernation. There is no better method to clean up the channels since some of the channels may still be referenced by the userspace apps when hibernation is triggered: in this case, with this patch, the "rescind" fields of the channels are set, and the apps will thoroughly destroy the channels after hibernation. Signed-off-by: Dexuan Cui <decui@microsoft.com> Reviewed-by: Michael Kelley <mikelley@microsoft.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--drivers/hv/vmbus_drv.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index ce9974bf683f..45b976ec6e79 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -24,6 +24,7 @@
24#include <linux/sched/task_stack.h> 24#include <linux/sched/task_stack.h>
25 25
26#include <asm/mshyperv.h> 26#include <asm/mshyperv.h>
27#include <linux/delay.h>
27#include <linux/notifier.h> 28#include <linux/notifier.h>
28#include <linux/ptrace.h> 29#include <linux/ptrace.h>
29#include <linux/screen_info.h> 30#include <linux/screen_info.h>
@@ -1069,6 +1070,41 @@ msg_handled:
1069 vmbus_signal_eom(msg, message_type); 1070 vmbus_signal_eom(msg, message_type);
1070} 1071}
1071 1072
1073/*
1074 * Fake RESCIND_CHANNEL messages to clean up hv_sock channels by force for
1075 * hibernation, because hv_sock connections can not persist across hibernation.
1076 */
1077static void vmbus_force_channel_rescinded(struct vmbus_channel *channel)
1078{
1079 struct onmessage_work_context *ctx;
1080 struct vmbus_channel_rescind_offer *rescind;
1081
1082 WARN_ON(!is_hvsock_channel(channel));
1083
1084 /*
1085 * sizeof(*ctx) is small and the allocation should really not fail,
1086 * otherwise the state of the hv_sock connections ends up in limbo.
1087 */
1088 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL | __GFP_NOFAIL);
1089
1090 /*
1091 * So far, these are not really used by Linux. Just set them to the
1092 * reasonable values conforming to the definitions of the fields.
1093 */
1094 ctx->msg.header.message_type = 1;
1095 ctx->msg.header.payload_size = sizeof(*rescind);
1096
1097 /* These values are actually used by Linux. */
1098 rescind = (struct vmbus_channel_rescind_offer *)ctx->msg.u.payload;
1099 rescind->header.msgtype = CHANNELMSG_RESCIND_CHANNELOFFER;
1100 rescind->child_relid = channel->offermsg.child_relid;
1101
1102 INIT_WORK(&ctx->work, vmbus_onmessage_work);
1103
1104 queue_work_on(vmbus_connection.connect_cpu,
1105 vmbus_connection.work_queue,
1106 &ctx->work);
1107}
1072 1108
1073/* 1109/*
1074 * Direct callback for channels using other deferred processing 1110 * Direct callback for channels using other deferred processing
@@ -2091,6 +2127,25 @@ acpi_walk_err:
2091 2127
2092static int vmbus_bus_suspend(struct device *dev) 2128static int vmbus_bus_suspend(struct device *dev)
2093{ 2129{
2130 struct vmbus_channel *channel;
2131
2132 while (atomic_read(&vmbus_connection.offer_in_progress) != 0) {
2133 /*
2134 * We wait here until the completion of any channel
2135 * offers that are currently in progress.
2136 */
2137 msleep(1);
2138 }
2139
2140 mutex_lock(&vmbus_connection.channel_mutex);
2141 list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
2142 if (!is_hvsock_channel(channel))
2143 continue;
2144
2145 vmbus_force_channel_rescinded(channel);
2146 }
2147 mutex_unlock(&vmbus_connection.channel_mutex);
2148
2094 vmbus_initiate_unload(false); 2149 vmbus_initiate_unload(false);
2095 2150
2096 vmbus_connection.conn_state = DISCONNECTED; 2151 vmbus_connection.conn_state = DISCONNECTED;