@@ -178,6 +178,8 @@ bool kvm_has_guest_debug;
int kvm_sstep_flags;
static bool kvm_immediate_exit;
static hwaddr kvm_max_slot_size = ~0;
+static QemuEvent mem_transaction_proceed;
+
static const KVMCapabilityInfo kvm_required_capabilites[] = {
KVM_CAP_INFO(USER_MEMORY),
@@ -1523,6 +1525,38 @@ static void kvm_region_del(MemoryListener *listener,
memory_region_unref(section->mr);
}
+static void kvm_begin(MemoryListener *listener)
+{
+ KVMState *s = kvm_state;
+
+ /*
+ * Make sure BQL is taken so cpus in kvm_cpu_exec that just exited from
+ * KVM_RUN do not continue, since many run->exit_reason take it anyways.
+ */
+ assert(qemu_mutex_iothread_locked());
+
+ /*
+ * Stop incoming cpus that want to execute KVM_RUN from running.
+ * Makes cpus calling qemu_event_wait() in kvm_cpu_exec() block.
+ */
+ qemu_event_reset(&mem_transaction_proceed);
+
+ /* Ask KVM to stop all vcpus that are currently running KVM_RUN */
+ kvm_vm_ioctl(s, KVM_KICK_ALL_RUNNING_VCPUS);
+}
+
+static void kvm_commit(MemoryListener *listener)
+{
+ KVMState *s = kvm_state;
+ assert(qemu_mutex_iothread_locked());
+
+ /* Ask KVM to resume all vcpus that are currently blocked in KVM_RUN */
+ kvm_vm_ioctl(s, KVM_RESUME_ALL_KICKED_VCPUS);
+
+ /* Resume cpus waiting in qemu_event_wait() in kvm_cpu_exec() */
+ qemu_event_set(&mem_transaction_proceed);
+}
+
static void kvm_log_sync(MemoryListener *listener,
MemoryRegionSection *section)
{
@@ -1668,6 +1702,8 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
kml->listener.region_del = kvm_region_del;
kml->listener.log_start = kvm_log_start;
kml->listener.log_stop = kvm_log_stop;
+ kml->listener.begin = kvm_begin;
+ kml->listener.commit = kvm_commit;
kml->listener.priority = 10;
kml->listener.name = name;
@@ -2611,6 +2647,7 @@ static int kvm_init(MachineState *ms)
}
kvm_state = s;
+ qemu_event_init(&mem_transaction_proceed, false);
ret = kvm_arch_init(ms, s);
if (ret < 0) {
@@ -2875,6 +2912,19 @@ int kvm_cpu_exec(CPUState *cpu)
}
qemu_mutex_unlock_iothread();
+
+ /*
+ * Wait that a running memory transaction (memslot update) is concluded.
+ *
+ * If the event state is EV_SET, it means kvm_commit() has already finished
+ * and called qemu_event_set(), therefore cpu can execute.
+ *
+ * If it's EV_FREE, it means kvm_begin() has already called
+ * qemu_event_reset(), therefore a memory transaction is happening and the
+ * cpu must wait.
+ */
+ qemu_event_wait(&mem_transaction_proceed);
+
cpu_exec_start(cpu);
do {
These callback make sure that all vcpus are blocked before performing memslot updates, and resumed once we are finished. They rely on kvm support for KVM_KICK_ALL_RUNNING_VCPUS and KVM_RESUME_ALL_KICKED_VCPUS ioctls to respectively pause and resume all vcpus that are in KVM_RUN state. Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> --- accel/kvm/kvm-all.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)