aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitaly Kuznetsov <vkuznets@redhat.com>2016-04-30 22:21:33 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-05-01 12:23:14 -0400
commit4dbfc2e68004c60edab7e8fd26784383dd3ee9bc (patch)
tree7fa8bef839b4f58926c7508e7411272194909854
parentd449d69d216854a8cab049fe035ffefbf383a2e1 (diff)
Drivers: hv: kvp: fix IP Failover
Hyper-V VMs can be replicated to another hosts and there is a feature to set different IP for replicas, it is called 'Failover TCP/IP'. When such guest starts Hyper-V host sends it KVP_OP_SET_IP_INFO message as soon as we finish negotiation procedure. The problem is that it can happen (and it actually happens) before userspace daemon connects and we reply with HV_E_FAIL to the message. As there are no repetitions we fail to set the requested IP. Solve the issue by postponing our reply to the negotiation message till userspace daemon is connected. We can't wait too long as there is a host-side timeout (cca. 75 seconds) and if we fail to reply in this time frame the whole KVP service will become inactive. The solution is not ideal - if it takes userspace daemon more than 60 seconds to connect IP Failover will still fail but I don't see a solution with our current separation between kernel and userspace parts. Other two modules (VSS and FCOPY) don't require such delay, leave them untouched. 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>
-rw-r--r--drivers/hv/hv_kvp.c31
-rw-r--r--drivers/hv/hyperv_vmbus.h5
2 files changed, 36 insertions, 0 deletions
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 9b9b370fe22a..cb1a9160aab1 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -78,9 +78,11 @@ static void kvp_send_key(struct work_struct *dummy);
78 78
79static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error); 79static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
80static void kvp_timeout_func(struct work_struct *dummy); 80static void kvp_timeout_func(struct work_struct *dummy);
81static void kvp_host_handshake_func(struct work_struct *dummy);
81static void kvp_register(int); 82static void kvp_register(int);
82 83
83static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func); 84static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func);
85static DECLARE_DELAYED_WORK(kvp_host_handshake_work, kvp_host_handshake_func);
84static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); 86static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
85 87
86static const char kvp_devname[] = "vmbus/hv_kvp"; 88static const char kvp_devname[] = "vmbus/hv_kvp";
@@ -130,6 +132,11 @@ static void kvp_timeout_func(struct work_struct *dummy)
130 hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper); 132 hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
131} 133}
132 134
135static void kvp_host_handshake_func(struct work_struct *dummy)
136{
137 hv_poll_channel(kvp_transaction.recv_channel, hv_kvp_onchannelcallback);
138}
139
133static int kvp_handle_handshake(struct hv_kvp_msg *msg) 140static int kvp_handle_handshake(struct hv_kvp_msg *msg)
134{ 141{
135 switch (msg->kvp_hdr.operation) { 142 switch (msg->kvp_hdr.operation) {
@@ -154,6 +161,12 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
154 pr_debug("KVP: userspace daemon ver. %d registered\n", 161 pr_debug("KVP: userspace daemon ver. %d registered\n",
155 KVP_OP_REGISTER); 162 KVP_OP_REGISTER);
156 kvp_register(dm_reg_value); 163 kvp_register(dm_reg_value);
164
165 /*
166 * If we're still negotiating with the host cancel the timeout
167 * work to not poll the channel twice.
168 */
169 cancel_delayed_work_sync(&kvp_host_handshake_work);
157 hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper); 170 hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
158 171
159 return 0; 172 return 0;
@@ -594,7 +607,22 @@ void hv_kvp_onchannelcallback(void *context)
594 struct icmsg_negotiate *negop = NULL; 607 struct icmsg_negotiate *negop = NULL;
595 int util_fw_version; 608 int util_fw_version;
596 int kvp_srv_version; 609 int kvp_srv_version;
610 static enum {NEGO_NOT_STARTED,
611 NEGO_IN_PROGRESS,
612 NEGO_FINISHED} host_negotiatied = NEGO_NOT_STARTED;
597 613
614 if (host_negotiatied == NEGO_NOT_STARTED &&
615 kvp_transaction.state < HVUTIL_READY) {
616 /*
617 * If userspace daemon is not connected and host is asking
618 * us to negotiate we need to delay to not lose messages.
619 * This is important for Failover IP setting.
620 */
621 host_negotiatied = NEGO_IN_PROGRESS;
622 schedule_delayed_work(&kvp_host_handshake_work,
623 HV_UTIL_NEGO_TIMEOUT * HZ);
624 return;
625 }
598 if (kvp_transaction.state > HVUTIL_READY) 626 if (kvp_transaction.state > HVUTIL_READY)
599 return; 627 return;
600 628
@@ -672,6 +700,8 @@ void hv_kvp_onchannelcallback(void *context)
672 vmbus_sendpacket(channel, recv_buffer, 700 vmbus_sendpacket(channel, recv_buffer,
673 recvlen, requestid, 701 recvlen, requestid,
674 VM_PKT_DATA_INBAND, 0); 702 VM_PKT_DATA_INBAND, 0);
703
704 host_negotiatied = NEGO_FINISHED;
675 } 705 }
676 706
677} 707}
@@ -708,6 +738,7 @@ hv_kvp_init(struct hv_util_service *srv)
708void hv_kvp_deinit(void) 738void hv_kvp_deinit(void)
709{ 739{
710 kvp_transaction.state = HVUTIL_DEVICE_DYING; 740 kvp_transaction.state = HVUTIL_DEVICE_DYING;
741 cancel_delayed_work_sync(&kvp_host_handshake_work);
711 cancel_delayed_work_sync(&kvp_timeout_work); 742 cancel_delayed_work_sync(&kvp_timeout_work);
712 cancel_work_sync(&kvp_sendkey_work); 743 cancel_work_sync(&kvp_sendkey_work);
713 hvutil_transport_destroy(hvt); 744 hvutil_transport_destroy(hvt);
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index e5c586fab0e5..e5203e4d6782 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -36,6 +36,11 @@
36#define HV_UTIL_TIMEOUT 30 36#define HV_UTIL_TIMEOUT 30
37 37
38/* 38/*
39 * Timeout for guest-host handshake for services.
40 */
41#define HV_UTIL_NEGO_TIMEOUT 60
42
43/*
39 * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent 44 * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
40 * is set by CPUID(HVCPUID_VERSION_FEATURES). 45 * is set by CPUID(HVCPUID_VERSION_FEATURES).
41 */ 46 */