int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
 {
        int ret = 0;
-       unsigned int cur_cpu;
        struct vmbus_channel_initiate_contact *msg;
        unsigned long flags;
 
 
        msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
        msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
-       /*
-        * We want all channel messages to be delivered on CPU 0.
-        * This has been the behavior pre-win8. This is not
-        * perf issue and having all channel messages delivered on CPU 0
-        * would be ok.
-        * For post win8 hosts, we support receiving channel messagges on
-        * all the CPUs. This is needed for kexec to work correctly where
-        * the CPU attempting to connect may not be CPU 0.
-        */
-       if (version >= VERSION_WIN8_1) {
-               cur_cpu = get_cpu();
-               msg->target_vcpu = hv_cpu_number_to_vp_number(cur_cpu);
-               vmbus_connection.connect_cpu = cur_cpu;
-               put_cpu();
-       } else {
-               msg->target_vcpu = 0;
-               vmbus_connection.connect_cpu = 0;
-       }
+       msg->target_vcpu = hv_cpu_number_to_vp_number(VMBUS_CONNECT_CPU);
 
        /*
         * Add to list before we send the request since we may
 
        bool channel_found = false;
        unsigned long flags;
 
+       /*
+        * Hyper-V does not provide a way to change the connect CPU once
+        * it is set; we must prevent the connect CPU from going offline.
+        */
+       if (cpu == VMBUS_CONNECT_CPU)
+               return -EBUSY;
+
        /*
         * Search for channels which are bound to the CPU we're about to
         * cleanup. In case we find one and vmbus is still connected we need to
 
 
 #define MAX_SIZE_CHANNEL_MESSAGE       HV_MESSAGE_PAYLOAD_BYTE_COUNT
 
-struct vmbus_connection {
-       /*
-        * CPU on which the initial host contact was made.
-        */
-       int connect_cpu;
+/*
+ * The CPU that Hyper-V will interrupt for VMBUS messages, such as
+ * CHANNELMSG_OFFERCHANNEL and CHANNELMSG_RESCIND_CHANNELOFFER.
+ */
+#define VMBUS_CONNECT_CPU      0
 
+struct vmbus_connection {
        u32 msg_conn_id;
 
        atomic_t offer_in_progress;
 
                        /*
                         * If we are handling the rescind message;
                         * schedule the work on the global work queue.
+                        *
+                        * The OFFER message and the RESCIND message should
+                        * not be handled by the same serialized work queue,
+                        * because the OFFER handler may call vmbus_open(),
+                        * which tries to open the channel by sending an
+                        * OPEN_CHANNEL message to the host and waits for
+                        * the host's response; however, if the host has
+                        * rescinded the channel before it receives the
+                        * OPEN_CHANNEL message, the host just silently
+                        * ignores the OPEN_CHANNEL message; as a result,
+                        * the guest's OFFER handler hangs for ever, if we
+                        * handle the RESCIND message in the same serialized
+                        * work queue: the RESCIND handler can not start to
+                        * run before the OFFER handler finishes.
                         */
-                       schedule_work_on(vmbus_connection.connect_cpu,
+                       schedule_work_on(VMBUS_CONNECT_CPU,
                                         &ctx->work);
                        break;
 
                case CHANNELMSG_OFFERCHANNEL:
                        atomic_inc(&vmbus_connection.offer_in_progress);
-                       queue_work_on(vmbus_connection.connect_cpu,
+                       queue_work_on(VMBUS_CONNECT_CPU,
                                      vmbus_connection.work_queue,
                                      &ctx->work);
                        break;
 
        INIT_WORK(&ctx->work, vmbus_onmessage_work);
 
-       queue_work_on(vmbus_connection.connect_cpu,
+       queue_work_on(VMBUS_CONNECT_CPU,
                      vmbus_connection.work_queue,
                      &ctx->work);
 }