diff options
Diffstat (limited to 'drivers/hv')
-rw-r--r-- | drivers/hv/hv.c | 31 | ||||
-rw-r--r-- | drivers/hv/vmbus_drv.c | 9 |
2 files changed, 35 insertions, 5 deletions
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 8dbbed4efa45..714e1ebc834c 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -587,10 +587,41 @@ int hv_synic_cleanup(unsigned int cpu) union hv_synic_simp simp; union hv_synic_siefp siefp; union hv_synic_scontrol sctrl; + struct vmbus_channel *channel, *sc; + bool channel_found = false; + unsigned long flags; if (!hv_context.synic_initialized) return -EFAULT; + /* + * 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 + * fail, this will effectively prevent CPU offlining. There is no way + * we can re-bind channels to different CPUs for now. + */ + mutex_lock(&vmbus_connection.channel_mutex); + list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { + if (channel->target_cpu == cpu) { + channel_found = true; + break; + } + spin_lock_irqsave(&channel->lock, flags); + list_for_each_entry(sc, &channel->sc_list, sc_list) { + if (sc->target_cpu == cpu) { + channel_found = true; + break; + } + } + spin_unlock_irqrestore(&channel->lock, flags); + if (channel_found) + break; + } + mutex_unlock(&vmbus_connection.channel_mutex); + + if (channel_found && vmbus_connection.conn_state == CONNECTED) + return -EBUSY; + /* Turn off clockevent device */ if (ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE) { clockevents_unbind_device(hv_context.clk_evt[cpu], cpu); diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index a16d519b7e37..565bdd16134a 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1008,9 +1008,6 @@ static int vmbus_bus_init(void) if (ret) goto err_connect; - if (vmbus_proto_version > VERSION_WIN7) - cpu_hotplug_disable(); - /* * Only register if the crash MSRs are available */ @@ -1486,6 +1483,9 @@ static void hv_kexec_handler(void) { hv_synic_clockevents_cleanup(); vmbus_initiate_unload(false); + vmbus_connection.conn_state = DISCONNECTED; + /* Make sure conn_state is set as hv_synic_cleanup checks for it */ + mb(); cpuhp_remove_state(hyperv_cpuhp_online); hv_cleanup(false); }; @@ -1498,6 +1498,7 @@ static void hv_crash_handler(struct pt_regs *regs) * doing the cleanup for current CPU only. This should be sufficient * for kdump. */ + vmbus_connection.conn_state = DISCONNECTED; hv_synic_cleanup(smp_processor_id()); hv_cleanup(true); }; @@ -1566,8 +1567,6 @@ static void __exit vmbus_exit(void) cpuhp_remove_state(hyperv_cpuhp_online); hv_synic_free(); acpi_bus_unregister_driver(&vmbus_acpi_driver); - if (vmbus_proto_version > VERSION_WIN7) - cpu_hotplug_enable(); } |