Skip to content

Commit

Permalink
Make sure all pause events are popped for resuming
Browse files Browse the repository at this point in the history
  • Loading branch information
Dorian Eikenberg committed May 17, 2022
1 parent 6da9184 commit 322c6b4
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 51 deletions.
69 changes: 26 additions & 43 deletions libvmi/driver/kvm/kvm.c
Expand Up @@ -993,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 @@ -1002,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 @@ -1016,54 +1016,37 @@ 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) {
// make sure that there are no unprocessed pause events
if (kvm_process_pending_events(vmi) == VMI_FAILURE)
return VMI_FAILURE;

// process pause events previously inserted into pause_events_list
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
return VMI_FAILURE;
}
if (!kvm->pause_events_list[vcpu]) {
errprint("%s: Missing pause event for vcpu %u\n", __func__, vcpu);
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;
}
16 changes: 10 additions & 6 deletions libvmi/driver/kvm/kvm_events.c
Expand Up @@ -938,8 +938,8 @@ process_single_event(vmi_instance_t vmi, struct kvmi_dom_event **event)
return status;
}

static status_t
process_pending_events(vmi_instance_t vmi)
status_t
kvm_process_pending_events(vmi_instance_t vmi)
{
kvm_instance_t *kvm = kvm_get_instance(vmi);
struct kvmi_dom_event *event = NULL;
Expand Down Expand Up @@ -973,7 +973,7 @@ process_events_with_timeout(vmi_instance_t vmi, uint32_t timeout)
process_single_event(vmi, &event);

// make sure that all pending events are processed
return process_pending_events(vmi);
return kvm_process_pending_events(vmi);
}

status_t
Expand Down Expand Up @@ -1008,8 +1008,10 @@ 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 (process_pending_events(vmi) == VMI_FAILURE) {
if (kvm_pause_vm(vmi) == VMI_FAILURE) {
return VMI_FAILURE;
}
if (kvm_process_pending_events(vmi) == VMI_FAILURE) {
return VMI_FAILURE;
}

Expand All @@ -1027,7 +1029,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
3 changes: 3 additions & 0 deletions libvmi/driver/kvm/kvm_events.h
Expand Up @@ -38,6 +38,9 @@ kvm_events_init(
void
kvm_events_destroy(vmi_instance_t vmi);

status_t
kvm_process_pending_events(vmi_instance_t vmi);

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

0 comments on commit 322c6b4

Please sign in to comment.