[PATCH 4/5] QEMU Release vcpu and finally exit vcpu thread safely

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Liu Ping Fan <pingfank@xxxxxxxxxxxxxxxxxx>

When guest driver tell us that the vcpu is no longer needed,
qemu can release the vcpu and finally exit vcpu thread

Signed-off-by: Liu Ping Fan <pingfank@xxxxxxxxxxxxxxxxxx>
---
 cpu-defs.h        |    5 +++++
 cpus.c            |   21 +++++++++++++++++++++
 hmp-commands.hx   |    2 +-
 hw/acpi_piix4.c   |   19 ++++++++++++++++---
 hw/pci_cpustate.c |   22 ++++++++++++++++++++++
 kvm-all.c         |   11 ++++++++++-
 monitor.c         |   12 +++++++-----
 7 files changed, 82 insertions(+), 10 deletions(-)

diff --git a/cpu-defs.h b/cpu-defs.h
index db48a7a..cb69a07 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -153,6 +153,10 @@ typedef struct CPUWatchpoint {
     QTAILQ_ENTRY(CPUWatchpoint) entry;
 } CPUWatchpoint;
 
+#define CPU_STATE_RUNNING 0
+#define CPU_STATE_ZAPREQ 1
+#define CPU_STATE_ZAPPED 2
+
 #define CPU_TEMP_BUF_NLONGS 128
 #define CPU_COMMON                                                      \
     struct TranslationBlock *current_tb; /* currently executing TB  */  \
@@ -210,6 +214,7 @@ typedef struct CPUWatchpoint {
     uint32_t created;                                                   \
     uint32_t stop;   /* Stop request */                                 \
     uint32_t stopped; /* Artificially stopped */                        \
+    uint32_t state; /*state indicator*/                             \
     struct QemuThread *thread;                                          \
     struct QemuCond *halt_cond;                                         \
     int thread_kicked;                                                  \
diff --git a/cpus.c b/cpus.c
index c996ac5..e479476 100644
--- a/cpus.c
+++ b/cpus.c
@@ -33,6 +33,7 @@
 
 #include "qemu-thread.h"
 #include "cpus.h"
+#include "cpu.h"
 
 #ifndef _WIN32
 #include "compatfd.h"
@@ -778,6 +779,7 @@ static void qemu_kvm_wait_io_event(CPUState *env)
 static void *qemu_kvm_cpu_thread_fn(void *arg)
 {
     CPUState *env = arg;
+    CPUState *prev = NULL;
     int r;
 
     qemu_mutex_lock(&qemu_global_mutex);
@@ -808,10 +810,29 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
                 cpu_handle_guest_debug(env);
             }
         }
+        /*1,try to zap; 2, can safe to destroy*/
+        if (env->state == CPU_STATE_ZAPPED) {
+            goto zapout;
+        }
         qemu_kvm_wait_io_event(env);
     }
 
     return NULL;
+zapout:
+    prev = first_cpu;
+    if (prev == env) {
+        first_cpu = env->next_cpu;
+    } else {
+        while (prev != NULL) {
+            if (prev->next_cpu == env) {
+                break;
+            }
+            prev = prev->next_cpu;
+        }
+        prev->next_cpu = env->next_cpu;
+    }
+    cpu_free(env);
+    return NULL;
 }
 
 static void *qemu_tcg_cpu_thread_fn(void *arg)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index ed5c9b9..b642a34 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1218,7 +1218,7 @@ ETEXI
     {
         .name       = "cpu_set",
         .args_type  = "cpu:i,state:s",
-        .params     = "cpu [online|offline]",
+        .params     = "cpu [online|offline|zap]",
         .help       = "change cpu state",
         .mhandler.cmd  = do_cpu_set_nr,
     },
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index f585226..1f3ed06 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -605,10 +605,23 @@ void qemu_system_cpu_hot_add(int cpu, int state)
         env->cpuid_apic_id = cpu;
     }
 
-    if (state)
-        enable_processor(s, cpu);
-    else
+    switch (state) {
+    /*zap vcpu*/
+    case 0:
+        env = qemu_get_cpu(cpu);
+        /*1 means try to zap*/
+        env->state = CPU_STATE_ZAPREQ;
+        disable_processor(s, cpu);
+        break;
+    /*offline vcpu*/
+    case 1:
         disable_processor(s, cpu);
+        break;
+    /*onine vcpu*/
+    case 2:
+        enable_processor(s, cpu);
+        break;
+    }
 
     pm_update_sci(s);
 }
diff --git a/hw/pci_cpustate.c b/hw/pci_cpustate.c
index fd31a1f..18402cf 100644
--- a/hw/pci_cpustate.c
+++ b/hw/pci_cpustate.c
@@ -24,6 +24,8 @@
 #include "loader.h"
 #include "sysemu.h"
 #include "iov.h"
+#include <linux/kvm.h>
+#include "kvm.h"
 
 #define PCI_DEVICE_ID_CPUSTATE  0x1010
 #define CPUSTATE_REGS_SIZE  0x1000
@@ -52,6 +54,26 @@ static void
 cpustate_mmio_write(void *opaque, target_phys_addr_t addr, uint64_t val,
                  unsigned size)
 {
+    CPUState *env;
+    int ret;
+    struct kvm_vcpu_state state;
+    switch (addr) {
+    /*apic id*/
+    case 0:
+        env = cpu_phyid_to_cpu(val);
+        if (env != NULL) {
+            if (env->state == CPU_STATE_ZAPREQ) {
+                state.vcpu_id = env->cpu_index;
+                state.state = 1;
+                ret = kvm_vm_ioctl(env->kvm_state, KVM_SETSTATE_VCPU, &state);
+            }
+        }
+        break;
+    case 4:
+        break;
+    default:
+        break;
+    }
 }
 
 static uint64_t
diff --git a/kvm-all.c b/kvm-all.c
index 8dd354e..b295262 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -64,6 +64,7 @@ struct KVMState
     int vmfd;
     int coalesced_mmio;
     struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
+    long mmap_size;
     int broken_set_mem_region;
     int migration_log;
     int vcpu_events;
@@ -228,7 +229,7 @@ int kvm_init_vcpu(CPUState *env)
         DPRINTF("KVM_GET_VCPU_MMAP_SIZE failed\n");
         goto err;
     }
-
+    env->kvm_state->mmap_size = mmap_size;
     env->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
                         env->kvm_fd, 0);
     if (env->kvm_run == MAP_FAILED) {
@@ -1026,6 +1027,13 @@ int kvm_cpu_exec(CPUState *env)
         case KVM_EXIT_INTERNAL_ERROR:
             ret = kvm_handle_internal_error(env, run);
             break;
+        case KVM_EXIT_VCPU_DEAD:
+            ret = munmap(env->kvm_run, env->kvm_state->mmap_size);
+            ret = close(env->kvm_fd);
+            env->state = CPU_STATE_ZAPPED;
+            qemu_mutex_unlock_iothread();
+            goto out;
+            break;
         default:
             DPRINTF("kvm_arch_handle_exit\n");
             ret = kvm_arch_handle_exit(env, run);
@@ -1033,6 +1041,7 @@ int kvm_cpu_exec(CPUState *env)
         }
     } while (ret == 0);
 
+out:
     if (ret < 0) {
         cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
         vm_stop(VMSTOP_PANIC);
diff --git a/monitor.c b/monitor.c
index cb485bf..51c8c52 100644
--- a/monitor.c
+++ b/monitor.c
@@ -971,11 +971,13 @@ static void do_cpu_set_nr(Monitor *mon, const QDict *qdict)
     status = qdict_get_str(qdict, "state");
     value = qdict_get_int(qdict, "cpu");
 
-    if (!strcmp(status, "online"))
-       state = 1;
-    else if (!strcmp(status, "offline"))
-       state = 0;
-    else {
+    if (!strcmp(status, "online")) {
+        state = 2;
+    } else if (!strcmp(status, "offline")) {
+        state = 1;
+    } else if (!strcmp(status, "zap")) {
+        state = 0;
+    } else {
         monitor_printf(mon, "invalid status: %s\n", status);
         return;
     }
-- 
1.7.4.4

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux