Message ID | da6c5bd5f028263343480a72cd86df1b60acc3d8.1423823368.git.zhugh.fnst@cn.fujitsu.com |
---|---|
State | New |
Headers | show |
On Fri, Feb 13, 2015 at 4:10 PM, Zhu Guihua <zhugh.fnst@cn.fujitsu.com> wrote: > From: Gu Zheng <guz.fnst@cn.fujitsu.com> > > After ACPI get a signal to eject a vCPU, the vCPU must be > removed from CPU list,before the vCPU really removed, then > release the all related vCPU objects. > > In order to deal well with the kvm vcpus (which can not be removed without any > protection), we do not close KVM vcpu fd, just record and mark it as stopped > into a list, so that we can reuse it for the appending cpu hot-add request if > possible. It is also the approach that kvm guys suggested: > https://www.mail-archive.com/kvm@vger.kernel.org/msg102839.html > > Signed-off-by: Chen Fan <chen.fan.fnst@cn.fujitsu.com> > Signed-off-by: Gu Zheng <guz.fnst@cn.fujitsu.com> > Signed-off-by: Zhu Guihua <zhugh.fnst@cn.fujitsu.com> > --- > cpus.c | 37 ++++++++++++++++++++++++++++++++++ > include/sysemu/kvm.h | 1 + > kvm-all.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++- > 3 files changed, 94 insertions(+), 1 deletion(-) > > diff --git a/cpus.c b/cpus.c > index d6e5a5f..a11941f 100644 > --- a/cpus.c > +++ b/cpus.c > @@ -854,6 +854,24 @@ void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) > qemu_cpu_kick(cpu); > } > > +static void qemu_kvm_destroy_vcpu(CPUState *cpu) > +{ > + CPU_REMOVE(cpu); > + > + if (kvm_destroy_vcpu(cpu) < 0) { > + error_report("kvm_destroy_vcpu failed.\n"); > + exit(EXIT_FAILURE); > + } > + > + object_unparent(OBJECT(cpu)); > +} > + > +static void qemu_tcg_destroy_vcpu(CPUState *cpu) > +{ > + CPU_REMOVE(cpu); > + object_unparent(OBJECT(cpu)); > +} > + > static void flush_queued_work(CPUState *cpu) > { > struct qemu_work_item *wi; > @@ -946,6 +964,11 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) > } > } > qemu_kvm_wait_io_event(cpu); > + if (cpu->exit && !cpu_can_run(cpu)) { > + qemu_kvm_destroy_vcpu(cpu); > + qemu_mutex_unlock(&qemu_global_mutex); > + return NULL; > + } > } > > return NULL; > @@ -999,6 +1022,7 @@ static void tcg_exec_all(void); > static void *qemu_tcg_cpu_thread_fn(void *arg) > { > CPUState *cpu = arg; > + CPUState *remove_cpu = NULL; > > qemu_tcg_init_cpu_signals(); > qemu_thread_get_self(cpu->thread); > @@ -1032,6 +1056,16 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) > } > } > qemu_tcg_wait_io_event(); > + CPU_FOREACH(cpu) { > + if (cpu->exit && !cpu_can_run(cpu)) { > + remove_cpu = cpu; > + break; > + } > + } > + if (remove_cpu) { > + qemu_tcg_destroy_vcpu(remove_cpu); > + remove_cpu = NULL; > + } > } > > return NULL; > @@ -1389,6 +1423,9 @@ static void tcg_exec_all(void) > break; > } > } else if (cpu->stop || cpu->stopped) { > + if (cpu->exit) { > + next_cpu = CPU_NEXT(cpu); > + } > break; > } > } > diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h > index 30cb84d..560caef 100644 > --- a/include/sysemu/kvm.h > +++ b/include/sysemu/kvm.h > @@ -188,6 +188,7 @@ int kvm_has_intx_set_mask(void); > > int kvm_init_vcpu(CPUState *cpu); > int kvm_cpu_exec(CPUState *cpu); > +int kvm_destroy_vcpu(CPUState *cpu); > > #ifdef NEED_CPU_H > > diff --git a/kvm-all.c b/kvm-all.c > index 05a79c2..46e7853 100644 > --- a/kvm-all.c > +++ b/kvm-all.c > @@ -71,6 +71,12 @@ typedef struct KVMSlot > > typedef struct kvm_dirty_log KVMDirtyLog; > > +struct KVMParkedVcpu { > + unsigned long vcpu_id; > + int kvm_fd; > + QLIST_ENTRY(KVMParkedVcpu) node; > +}; > + > struct KVMState > { > AccelState parent_obj; > @@ -107,6 +113,7 @@ struct KVMState > QTAILQ_HEAD(msi_hashtab, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE]; > bool direct_msi; > #endif > + QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus; > }; > > #define TYPE_KVM_ACCEL ACCEL_CLASS_NAME("kvm") > @@ -247,6 +254,53 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) > return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); > } > > +int kvm_destroy_vcpu(CPUState *cpu) You need to provide a stub for this in kvm-stub.c without which I see that aarch64-softmmu won't compile. Regards, Bharata.
diff --git a/cpus.c b/cpus.c index d6e5a5f..a11941f 100644 --- a/cpus.c +++ b/cpus.c @@ -854,6 +854,24 @@ void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) qemu_cpu_kick(cpu); } +static void qemu_kvm_destroy_vcpu(CPUState *cpu) +{ + CPU_REMOVE(cpu); + + if (kvm_destroy_vcpu(cpu) < 0) { + error_report("kvm_destroy_vcpu failed.\n"); + exit(EXIT_FAILURE); + } + + object_unparent(OBJECT(cpu)); +} + +static void qemu_tcg_destroy_vcpu(CPUState *cpu) +{ + CPU_REMOVE(cpu); + object_unparent(OBJECT(cpu)); +} + static void flush_queued_work(CPUState *cpu) { struct qemu_work_item *wi; @@ -946,6 +964,11 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) } } qemu_kvm_wait_io_event(cpu); + if (cpu->exit && !cpu_can_run(cpu)) { + qemu_kvm_destroy_vcpu(cpu); + qemu_mutex_unlock(&qemu_global_mutex); + return NULL; + } } return NULL; @@ -999,6 +1022,7 @@ static void tcg_exec_all(void); static void *qemu_tcg_cpu_thread_fn(void *arg) { CPUState *cpu = arg; + CPUState *remove_cpu = NULL; qemu_tcg_init_cpu_signals(); qemu_thread_get_self(cpu->thread); @@ -1032,6 +1056,16 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) } } qemu_tcg_wait_io_event(); + CPU_FOREACH(cpu) { + if (cpu->exit && !cpu_can_run(cpu)) { + remove_cpu = cpu; + break; + } + } + if (remove_cpu) { + qemu_tcg_destroy_vcpu(remove_cpu); + remove_cpu = NULL; + } } return NULL; @@ -1389,6 +1423,9 @@ static void tcg_exec_all(void) break; } } else if (cpu->stop || cpu->stopped) { + if (cpu->exit) { + next_cpu = CPU_NEXT(cpu); + } break; } } diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 30cb84d..560caef 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -188,6 +188,7 @@ int kvm_has_intx_set_mask(void); int kvm_init_vcpu(CPUState *cpu); int kvm_cpu_exec(CPUState *cpu); +int kvm_destroy_vcpu(CPUState *cpu); #ifdef NEED_CPU_H diff --git a/kvm-all.c b/kvm-all.c index 05a79c2..46e7853 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -71,6 +71,12 @@ typedef struct KVMSlot typedef struct kvm_dirty_log KVMDirtyLog; +struct KVMParkedVcpu { + unsigned long vcpu_id; + int kvm_fd; + QLIST_ENTRY(KVMParkedVcpu) node; +}; + struct KVMState { AccelState parent_obj; @@ -107,6 +113,7 @@ struct KVMState QTAILQ_HEAD(msi_hashtab, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE]; bool direct_msi; #endif + QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus; }; #define TYPE_KVM_ACCEL ACCEL_CLASS_NAME("kvm") @@ -247,6 +254,53 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); } +int kvm_destroy_vcpu(CPUState *cpu) +{ + KVMState *s = kvm_state; + long mmap_size; + struct KVMParkedVcpu *vcpu = NULL; + int ret = 0; + + DPRINTF("kvm_destroy_vcpu\n"); + + mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); + if (mmap_size < 0) { + ret = mmap_size; + DPRINTF("KVM_GET_VCPU_MMAP_SIZE failed\n"); + goto err; + } + + ret = munmap(cpu->kvm_run, mmap_size); + if (ret < 0) { + goto err; + } + + vcpu = g_malloc0(sizeof(*vcpu)); + vcpu->vcpu_id = kvm_arch_vcpu_id(cpu); + vcpu->kvm_fd = cpu->kvm_fd; + QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node); +err: + return ret; +} + +static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id) +{ + struct KVMParkedVcpu *cpu; + + QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) { + if (cpu->vcpu_id == vcpu_id) { + int kvm_fd; + + QLIST_REMOVE(cpu, node); + kvm_fd = cpu->kvm_fd; + g_free(cpu); + return kvm_fd; + } + } + + return kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id); +} + int kvm_init_vcpu(CPUState *cpu) { KVMState *s = kvm_state; @@ -255,7 +309,7 @@ int kvm_init_vcpu(CPUState *cpu) DPRINTF("kvm_init_vcpu\n"); - ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)kvm_arch_vcpu_id(cpu)); + ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu)); if (ret < 0) { DPRINTF("kvm_create_vcpu failed\n"); goto err; @@ -1448,6 +1502,7 @@ static int kvm_init(MachineState *ms) #ifdef KVM_CAP_SET_GUEST_DEBUG QTAILQ_INIT(&s->kvm_sw_breakpoints); #endif + QLIST_INIT(&s->kvm_parked_vcpus); s->vmfd = -1; s->fd = qemu_open("/dev/kvm", O_RDWR); if (s->fd == -1) {