xics_kvm: cache already enabled vCPU ids

Since commit a45863bda9 ("xics_kvm: Don't enable KVM_CAP_IRQ_XICS if
already enabled"), we were able to re-hotplug a vCPU that had been hot-
unplugged ealier, thanks to a boolean flag in ICPState that we set when
enabling KVM_CAP_IRQ_XICS.

This could work because the lifecycle of all ICPState objects was the
same as the machine. Commit 5bc8d26de2 ("spapr: allocate the ICPState
object from under sPAPRCPUCore") broke this assumption and now we always
pass a freshly allocated ICPState object (ie, with the flag unset) to
icp_kvm_cpu_setup().

This cause re-hotplug to fail with:

Unable to connect CPU8 to kernel XICS: Device or resource busy

Let's fix this by caching all the vCPU ids for which KVM_CAP_IRQ_XICS was
enabled. This also drops the now useless boolean flag from ICPState.

Reported-by: Laurent Vivier <lvivier@redhat.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
Tested-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Greg Kurz 2017-05-17 16:38:20 +02:00 committed by David Gibson
parent 06ec79e865
commit de86eccc0c
2 changed files with 20 additions and 8 deletions

View File

@ -42,6 +42,14 @@
static int kernel_xics_fd = -1;
typedef struct KVMEnabledICP {
unsigned long vcpu_id;
QLIST_ENTRY(KVMEnabledICP) node;
} KVMEnabledICP;
static QLIST_HEAD(, KVMEnabledICP)
kvm_enabled_icps = QLIST_HEAD_INITIALIZER(&kvm_enabled_icps);
/*
* ICP-KVM
*/
@ -121,6 +129,8 @@ static void icp_kvm_reset(void *dev)
static void icp_kvm_cpu_setup(ICPState *icp, PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
KVMEnabledICP *enabled_icp;
unsigned long vcpu_id = kvm_arch_vcpu_id(cs);
int ret;
if (kernel_xics_fd == -1) {
@ -132,18 +142,21 @@ static void icp_kvm_cpu_setup(ICPState *icp, PowerPCCPU *cpu)
* which was hot-removed earlier we don't have to renable
* KVM_CAP_IRQ_XICS capability again.
*/
if (icp->cap_irq_xics_enabled) {
return;
QLIST_FOREACH(enabled_icp, &kvm_enabled_icps, node) {
if (enabled_icp->vcpu_id == vcpu_id) {
return;
}
}
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd,
kvm_arch_vcpu_id(cs));
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd, vcpu_id);
if (ret < 0) {
error_report("Unable to connect CPU%ld to kernel XICS: %s",
kvm_arch_vcpu_id(cs), strerror(errno));
error_report("Unable to connect CPU%ld to kernel XICS: %s", vcpu_id,
strerror(errno));
exit(1);
}
icp->cap_irq_xics_enabled = true;
enabled_icp = g_malloc(sizeof(*enabled_icp));
enabled_icp->vcpu_id = vcpu_id;
QLIST_INSERT_HEAD(&kvm_enabled_icps, enabled_icp, node);
}
static void icp_kvm_realize(DeviceState *dev, Error **errp)

View File

@ -81,7 +81,6 @@ struct ICPState {
uint8_t pending_priority;
uint8_t mfrr;
qemu_irq output;
bool cap_irq_xics_enabled;
XICSFabric *xics;
};