Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlaf Hering <ohering@suse.de>2013-07-19 16:39:26 +0200
committerOlaf Hering <ohering@suse.de>2013-07-19 16:39:31 +0200
commitaf855fc8527e21dd06eee74f1d3aae9927a9ee47 (patch)
tree7ad4048555f99c47c2c89f6a3225669274f3e7fe
parent123639ede052421bfe48b634f54913c16a4a6f5f (diff)
Drivers: hv: util: Fix a bug in version negotiation code for
util services (bnc#828714).
-rw-r--r--patches.suse/suse-hv-Drivers-hv-util-Fix-a-bug-in-version-negotiation-cod.patch304
-rw-r--r--series.conf1
2 files changed, 305 insertions, 0 deletions
diff --git a/patches.suse/suse-hv-Drivers-hv-util-Fix-a-bug-in-version-negotiation-cod.patch b/patches.suse/suse-hv-Drivers-hv-util-Fix-a-bug-in-version-negotiation-cod.patch
new file mode 100644
index 0000000000..0773b71469
--- /dev/null
+++ b/patches.suse/suse-hv-Drivers-hv-util-Fix-a-bug-in-version-negotiation-cod.patch
@@ -0,0 +1,304 @@
+From: "K. Y. Srinivasan" <kys@microsoft.com>
+Date: Tue, 2 Jul 2013 10:31:30 -0700
+Subject: Drivers: hv: util: Fix a bug in version negotiation code for util services
+Patch-mainline: submitted (lkml 2013-07-02)
+References: bnc#828714
+
+The current code picked the highest version advertised by the host. WS2012 R2
+has implemented a protocol version for KVP that is not compatible with prior
+protocol versions of KVP. Fix the bug in the current code by explicitly specifying
+the protocol version that the guest can support.
+
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
+Acked-by: <ohering@suse.de>
+---
+ drivers/hv/channel_mgmt.c | 75 +++++++++++++++++++++++++++++++++--------------
+ drivers/hv/hv_kvp.c | 24 ++++++++++++++-
+ drivers/hv/hv_snapshot.c | 18 ++++--------
+ drivers/hv/hv_util.c | 21 +++++++++++--
+ include/linux/hyperv.h | 10 ++++++-
+ 5 files changed, 109 insertions(+), 39 deletions(-)
+
+diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
+index 21ef689..a8fb7de 100644
+--- a/drivers/hv/channel_mgmt.c
++++ b/drivers/hv/channel_mgmt.c
+@@ -48,30 +48,39 @@ struct vmbus_channel_message_table_entry {
+ * @negop is of type &struct icmsg_negotiate.
+ * Set up and fill in default negotiate response message.
+ *
+- * The max_fw_version specifies the maximum framework version that
+- * we can support and max _srv_version specifies the maximum service
+- * version we can support. A special value MAX_SRV_VER can be
+- * specified to indicate that we can handle the maximum version
+- * exposed by the host.
++ * The fw_version specifies the framework version that
++ * we can support and srv_version specifies the service
++ * version we can support.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+-void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
++bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
+ struct icmsg_negotiate *negop, u8 *buf,
+- int max_fw_version, int max_srv_version)
++ int fw_version, int srv_version)
+ {
+- int icframe_vercnt;
+- int icmsg_vercnt;
++ int icframe_major, icframe_minor;
++ int icmsg_major, icmsg_minor;
++ int fw_major, fw_minor;
++ int srv_major, srv_minor;
+ int i;
++ bool found_match = false;
+
+ icmsghdrp->icmsgsize = 0x10;
++ fw_major = (fw_version >> 16);
++ fw_minor = (fw_version & 0xFFFF);
++
++ srv_major = (srv_version >> 16);
++ srv_minor = (srv_version & 0xFFFF);
+
+ negop = (struct icmsg_negotiate *)&buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+- icframe_vercnt = negop->icframe_vercnt;
+- icmsg_vercnt = negop->icmsg_vercnt;
++ icframe_major = negop->icframe_vercnt;
++ icframe_minor = 0;
++
++ icmsg_major = negop->icmsg_vercnt;
++ icmsg_minor = 0;
+
+ /*
+ * Select the framework version number we will
+@@ -79,26 +88,48 @@ void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
+ */
+
+ for (i = 0; i < negop->icframe_vercnt; i++) {
+- if (negop->icversion_data[i].major <= max_fw_version)
+- icframe_vercnt = negop->icversion_data[i].major;
++ if ((negop->icversion_data[i].major == fw_major) &&
++ (negop->icversion_data[i].minor == fw_minor)) {
++ icframe_major = negop->icversion_data[i].major;
++ icframe_minor = negop->icversion_data[i].minor;
++ found_match = true;
++ }
+ }
+
++ if (!found_match)
++ goto fw_error;
++
++ found_match = false;
++
+ for (i = negop->icframe_vercnt;
+ (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
+- if (negop->icversion_data[i].major <= max_srv_version)
+- icmsg_vercnt = negop->icversion_data[i].major;
++ if ((negop->icversion_data[i].major == srv_major) &&
++ (negop->icversion_data[i].minor == srv_minor)) {
++ icmsg_major = negop->icversion_data[i].major;
++ icmsg_minor = negop->icversion_data[i].minor;
++ found_match = true;
++ }
+ }
+
+ /*
+- * Respond with the maximum framework and service
++ * Respond with the framework and service
+ * version numbers we can support.
+ */
+- negop->icframe_vercnt = 1;
+- negop->icmsg_vercnt = 1;
+- negop->icversion_data[0].major = icframe_vercnt;
+- negop->icversion_data[0].minor = 0;
+- negop->icversion_data[1].major = icmsg_vercnt;
+- negop->icversion_data[1].minor = 0;
++
++fw_error:
++ if (!found_match) {
++ negop->icframe_vercnt = 0;
++ negop->icmsg_vercnt = 0;
++ } else {
++ negop->icframe_vercnt = 1;
++ negop->icmsg_vercnt = 1;
++ }
++
++ negop->icversion_data[0].major = icframe_major;
++ negop->icversion_data[0].minor = icframe_minor;
++ negop->icversion_data[1].major = icmsg_major;
++ negop->icversion_data[1].minor = icmsg_minor;
++ return found_match;
+ }
+
+ EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
+diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
+index ed50e9e..5312720 100644
+--- a/drivers/hv/hv_kvp.c
++++ b/drivers/hv/hv_kvp.c
+@@ -29,6 +29,16 @@
+ #include <linux/hyperv.h>
+
+
++/*
++ * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7)
++ */
++#define WIN7_SRV_MAJOR 3
++#define WIN7_SRV_MINOR 0
++#define WIN7_SRV_MAJOR_MINOR (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR)
++
++#define WIN8_SRV_MAJOR 4
++#define WIN8_SRV_MINOR 0
++#define WIN8_SRV_MAJOR_MINOR (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
+
+ /*
+ * Global state maintained for transaction that is being processed.
+@@ -593,8 +603,19 @@ void hv_kvp_onchannelcallback(void *context)
+ sizeof(struct vmbuspipe_hdr)];
+
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
++ /*
++ * We start with win8 version and if the host cannot
++ * support that we use the previous version.
++ */
++ if (vmbus_prep_negotiate_resp(icmsghdrp, negop,
++ recv_buffer, UTIL_FW_MAJOR_MINOR,
++ WIN8_SRV_MAJOR_MINOR))
++ goto done;
++
+ vmbus_prep_negotiate_resp(icmsghdrp, negop,
+- recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
++ recv_buffer, UTIL_FW_MAJOR_MINOR,
++ WIN7_SRV_MAJOR_MINOR);
++
+ } else {
+ kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr) +
+@@ -626,6 +647,7 @@ void hv_kvp_onchannelcallback(void *context)
+ return;
+
+ }
++done:
+
+ icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+ | ICMSGHDRFLAG_RESPONSE;
+diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
+index 8ad5653..e4572f3 100644
+--- a/drivers/hv/hv_snapshot.c
++++ b/drivers/hv/hv_snapshot.c
+@@ -24,6 +24,10 @@
+ #include <linux/workqueue.h>
+ #include <linux/hyperv.h>
+
++#define VSS_MAJOR 5
++#define VSS_MINOR 0
++#define VSS_MAJOR_MINOR (VSS_MAJOR << 16 | VSS_MINOR)
++
+
+
+ /*
+@@ -186,18 +190,8 @@ void hv_vss_onchannelcallback(void *context)
+
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ vmbus_prep_negotiate_resp(icmsghdrp, negop,
+- recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
+- /*
+- * We currently negotiate the highest number the
+- * host has presented. If this version is not
+- * atleast 5.0, reject.
+- */
+- negop = (struct icmsg_negotiate *)&recv_buffer[
+- sizeof(struct vmbuspipe_hdr) +
+- sizeof(struct icmsg_hdr)];
+-
+- if (negop->icversion_data[1].major < 5)
+- negop->icframe_vercnt = 0;
++ recv_buffer, UTIL_FW_MAJOR_MINOR,
++ VSS_MAJOR_MINOR);
+ } else {
+ vss_msg = (struct hv_vss_msg *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr) +
+diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
+index 2f561c5..c16164d 100644
+--- a/drivers/hv/hv_util.c
++++ b/drivers/hv/hv_util.c
+@@ -28,6 +28,18 @@
+ #include <linux/reboot.h>
+ #include <linux/hyperv.h>
+
++#define SHUTDOWN_MAJOR 3
++#define SHUTDOWN_MINOR 0
++#define SHUTDOWN_MAJOR_MINOR (SHUTDOWN_MAJOR << 16 | SHUTDOWN_MINOR)
++
++#define TIMESYNCH_MAJOR 3
++#define TIMESYNCH_MINOR 0
++#define TIMESYNCH_MAJOR_MINOR (TIMESYNCH_MAJOR << 16 | TIMESYNCH_MINOR)
++
++#define HEARTBEAT_MAJOR 3
++#define HEARTBEAT_MINOR 0
++#define HEARTBEAT_MAJOR_MINOR (HEARTBEAT_MAJOR << 16 | HEARTBEAT_MINOR)
++
+ static void shutdown_onchannelcallback(void *context);
+ static struct hv_util_service util_shutdown = {
+ .util_cb = shutdown_onchannelcallback,
+@@ -87,7 +99,8 @@ static void shutdown_onchannelcallback(void *context)
+
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ vmbus_prep_negotiate_resp(icmsghdrp, negop,
+- shut_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
++ shut_txf_buf, UTIL_FW_MAJOR_MINOR,
++ SHUTDOWN_MAJOR_MINOR);
+ } else {
+ shutdown_msg =
+ (struct shutdown_msg_data *)&shut_txf_buf[
+@@ -213,7 +226,8 @@ static void timesync_onchannelcallback(void *context)
+
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf,
+- MAX_SRV_VER, MAX_SRV_VER);
++ UTIL_FW_MAJOR_MINOR,
++ TIMESYNCH_MAJOR_MINOR);
+ } else {
+ timedatap = (struct ictimesync_data *)&time_txf_buf[
+ sizeof(struct vmbuspipe_hdr) +
+@@ -253,7 +267,8 @@ static void heartbeat_onchannelcallback(void *context)
+
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ vmbus_prep_negotiate_resp(icmsghdrp, NULL,
+- hbeat_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
++ hbeat_txf_buf, UTIL_FW_MAJOR_MINOR,
++ HEARTBEAT_MAJOR_MINOR);
+ } else {
+ heartbeat_msg =
+ (struct heartbeat_msg_data *)&hbeat_txf_buf[
+diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
+index c255984..2254f4b 100644
+--- a/include/linux/hyperv.h
++++ b/include/linux/hyperv.h
+@@ -27,6 +27,14 @@
+
+ #include <linux/types.h>
+
++/*
++ * Framework version for util services.
++ */
++
++#define UTIL_FW_MAJOR 3
++#define UTIL_FW_MINOR 0
++#define UTIL_FW_MAJOR_MINOR (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
++
+
+ /*
+ * Implementation of host controlled snapshot of the guest.
+@@ -1424,7 +1432,7 @@ struct hyperv_service_callback {
+ };
+
+ #define MAX_SRV_VER 0x7ffffff
+-extern void vmbus_prep_negotiate_resp(struct icmsg_hdr *,
++extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *,
+ struct icmsg_negotiate *, u8 *, int,
+ int);
+
diff --git a/series.conf b/series.conf
index 5c2369fd2c..2f2ae109b4 100644
--- a/series.conf
+++ b/series.conf
@@ -237,6 +237,7 @@
########################################################
# Suse specific stuff
########################################################
+ patches.suse/suse-hv-Drivers-hv-util-Fix-a-bug-in-version-negotiation-cod.patch
########################################################
# Networking, IPv6