Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pop pending events after pausing vm #1026

Merged
merged 3 commits into from Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
75 changes: 23 additions & 52 deletions libvmi/driver/kvm/kvm.c
Expand Up @@ -31,24 +31,13 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/un.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <glib.h>
#include <math.h>
#include <glib/gstdio.h>
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <libkvmi.h>

#include "private.h"
#include "msr-index.h"
#include "driver/driver_wrapper.h"
#include "driver/memory_cache.h"
#include "driver/kvm/kvm.h"
#include "driver/kvm/kvm_private.h"
Expand Down Expand Up @@ -1004,7 +993,7 @@ kvm_pause_vm(
{
kvm_instance_t *kvm = kvm_get_instance(vmi);
// already paused ?
if (kvm->expected_pause_count)
if (kvm->paused)
return VMI_SUCCESS;

// pause vcpus
Expand All @@ -1013,9 +1002,9 @@ kvm_pause_vm(
return VMI_FAILURE;
}

kvm->expected_pause_count = vmi->num_vcpus;
kvm->paused = true;

dbprint(VMI_DEBUG_KVM, "--We should receive %u pause events\n", kvm->expected_pause_count);
dbprint(VMI_DEBUG_KVM, "--We should receive %u pause events\n", vmi->num_vcpus);

return VMI_SUCCESS;
}
Expand All @@ -1027,54 +1016,36 @@ kvm_resume_vm(
kvm_instance_t *kvm = kvm_get_instance(vmi);

// already resumed ?
if (!kvm->expected_pause_count)
if (!kvm->paused)
return VMI_SUCCESS;

// wait to receive pause events
while (kvm->expected_pause_count) {
// iterate over pause_events_list and unpause every single vcpu by sending a continue reply for each pause event
for (unsigned int vcpu = 0; vcpu < vmi->num_vcpus; vcpu++) {
struct kvmi_dom_event *ev = NULL;
unsigned int ev_id = 0;

// check pause events poped by vmi_events_listen first
for (unsigned int vcpu = 0; vcpu < vmi->num_vcpus; vcpu++) {
if (kvm->pause_events_list[vcpu]) {
dbprint(VMI_DEBUG_KVM, "--Removing PAUSE_VCPU event from the buffer\n");
ev = kvm->pause_events_list[vcpu];
kvm->pause_events_list[vcpu] = NULL;
break;
}
}

// if no pause event is waiting in the list, pop next one
if (!ev) {
if (VMI_FAILURE == kvm_get_next_event(kvm, &ev, 1000)) {
errprint("Failed to get next KVMi event\n");
}
if (!ev) {
// no new events
// report error
// wait until the pause event for the current vcpu is received
while (!kvm->pause_events_list[vcpu]) {
rageagainsthepc marked this conversation as resolved.
Show resolved Hide resolved
dbprint(VMI_DEBUG_KVM, "--Waiting to receive PAUSE_VCPU event for vcpu %u\n", vcpu);
if (kvm_process_events_with_timeout(vmi, 100) == VMI_FAILURE) {
return VMI_FAILURE;
}
}

dbprint(VMI_DEBUG_KVM, "--Removing PAUSE_VCPU event from the buffer\n");
ev = kvm->pause_events_list[vcpu];
kvm->pause_events_list[vcpu] = NULL;

// handle event
ev_id = ev->event.common.event;
switch (ev_id) {
case KVMI_EVENT_PAUSE_VCPU:
dbprint(VMI_DEBUG_KVM, "--Received VCPU pause event\n");
kvm->expected_pause_count--;
if (reply_continue(kvm, ev) == VMI_FAILURE) {
errprint("%s: Fail to send continue reply", __func__);
free(ev);
return VMI_FAILURE;
}
free(ev);
break;
default:
errprint("%s: Unexpected event %u\n", __func__, ev_id);
free(ev);
return VMI_FAILURE;
dbprint(VMI_DEBUG_KVM, "--Sending continue reply\n");
if (reply_continue(kvm, ev) == VMI_FAILURE) {
errprint("%s: Failed to send continue reply\n", __func__);
free(ev);
return VMI_FAILURE;
}
free(ev);
}

kvm->paused = false;

return VMI_SUCCESS;
}
20 changes: 12 additions & 8 deletions libvmi/driver/kvm/kvm_events.c
Expand Up @@ -821,7 +821,7 @@ kvm_events_destroy(
dbprint(VMI_DEBUG_KVM, "--Destroying KVM driver events\n");
// pause VM
dbprint(VMI_DEBUG_KVM, "--Ensure VM is paused\n");
if (VMI_FAILURE == vmi_pause_vm(vmi))
if (VMI_FAILURE == kvm_pause_vm(vmi))
errprint("--Failed to pause VM while destroying events\n");

reg_event_t regevent = { .in_access = VMI_REGACCESS_N };
Expand Down Expand Up @@ -878,13 +878,13 @@ kvm_events_destroy(
// clean event queue
if (kvm_are_events_pending(vmi)) {
dbprint(VMI_DEBUG_KVM, "--Cleanup event queue\n");
if (VMI_FAILURE == vmi_events_listen(vmi, 0))
if (VMI_FAILURE == kvm_events_listen(vmi, 0))
errprint("--Failed to clean event queue\n");
}

// resume VM
dbprint(VMI_DEBUG_KVM, "--Resume VM\n");
if (VMI_FAILURE == vmi_resume_vm(vmi))
if (VMI_FAILURE == kvm_resume_vm(vmi))
errprint("--Failed to resume VM while destroying events\n");
}

Expand Down Expand Up @@ -952,8 +952,8 @@ process_pending_events(vmi_instance_t vmi)
return VMI_SUCCESS;
}

static status_t
process_events_with_timeout(vmi_instance_t vmi, uint32_t timeout)
status_t
kvm_process_events_with_timeout(vmi_instance_t vmi, uint32_t timeout)
{
kvm_instance_t *kvm = kvm_get_instance(vmi);
struct kvmi_dom_event *event = NULL;
Expand Down Expand Up @@ -992,7 +992,7 @@ kvm_events_listen(

GSList *loop;

if (process_events_with_timeout(vmi, timeout) == VMI_FAILURE) {
if (kvm_process_events_with_timeout(vmi, timeout) == VMI_FAILURE) {
return VMI_FAILURE;
}

Expand All @@ -1004,7 +1004,9 @@ kvm_events_listen(
* are pending we can remove/swap the events.
*/
if (vmi->swap_events || (vmi->clear_events && g_hash_table_size(vmi->clear_events))) {
vmi_pause_vm(vmi);
if (kvm_pause_vm(vmi) == VMI_FAILURE) {
return VMI_FAILURE;
}
if (process_pending_events(vmi) == VMI_FAILURE) {
return VMI_FAILURE;
}
Expand All @@ -1023,7 +1025,9 @@ kvm_events_listen(

g_hash_table_foreach_remove(vmi->clear_events, clear_events_full, vmi);

vmi_resume_vm(vmi);
if (kvm_resume_vm(vmi) == VMI_FAILURE) {
return VMI_FAILURE;
}
}

return VMI_SUCCESS;
Expand Down
5 changes: 5 additions & 0 deletions libvmi/driver/kvm/kvm_events.h
Expand Up @@ -38,6 +38,11 @@ kvm_events_init(
void
kvm_events_destroy(vmi_instance_t vmi);

status_t
kvm_process_events_with_timeout(
vmi_instance_t vmi,
uint32_t timeout);

status_t
kvm_events_listen(
vmi_instance_t vmi,
Expand Down
4 changes: 2 additions & 2 deletions libvmi/driver/kvm/kvm_private.h
Expand Up @@ -56,8 +56,8 @@ typedef struct kvm_instance {
libkvmi_wrapper_t libkvmi;
pthread_mutex_t kvm_connect_mutex;
pthread_cond_t kvm_start_cond;
unsigned int expected_pause_count;
// store KVMI_EVENT_PAUSE_VCPU events poped by vmi_events_listen(vmi, 0)
bool paused;
// store KVMI_EVENT_PAUSE_VCPU events popped by vmi_events_listen(vmi, 0)
// to be used by vmi_resume_vm()
struct kvmi_dom_event** pause_events_list;
// dispatcher to handle VM events in each process_xxx functions
Expand Down