Skip to content

Commit

Permalink
kvmclock: clock should count only if vm is running
Browse files Browse the repository at this point in the history
kvmclock should not count while vm is paused, because:

1) if the vm is paused for long periods, timekeeping
math can overflow while converting the (large) clocksource
delta to nanoseconds.

2) Users rely on CLOCK_MONOTONIC to count run time, that is,
time which OS has been in a runnable state (see CLOCK_BOOTTIME).

Change kvmclock driver so as to save clock value when vm transitions
from runnable to stopped state, and to restore clock value from stopped
to runnable transition.

Cc: qemu-stable@nongnu.org
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 00f4d64)

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
  • Loading branch information
matosatti authored and mdroth committed Aug 12, 2013
1 parent f7fe3d2 commit 1eeacd4
Showing 1 changed file with 30 additions and 34 deletions.
64 changes: 30 additions & 34 deletions hw/i386/kvm/clock.c
Expand Up @@ -28,38 +28,6 @@ typedef struct KVMClockState {
bool clock_valid;
} KVMClockState;

static void kvmclock_pre_save(void *opaque)
{
KVMClockState *s = opaque;
struct kvm_clock_data data;
int ret;

if (s->clock_valid) {
return;
}
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
if (ret < 0) {
fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
data.clock = 0;
}
s->clock = data.clock;
/*
* If the VM is stopped, declare the clock state valid to avoid re-reading
* it on next vmsave (which would return a different value). Will be reset
* when the VM is continued.
*/
s->clock_valid = !runstate_is_running();
}

static int kvmclock_post_load(void *opaque, int version_id)
{
KVMClockState *s = opaque;
struct kvm_clock_data data;

data.clock = s->clock;
data.flags = 0;
return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
}

static void kvmclock_vm_state_change(void *opaque, int running,
RunState state)
Expand All @@ -70,8 +38,18 @@ static void kvmclock_vm_state_change(void *opaque, int running,
int ret;

if (running) {
struct kvm_clock_data data;

s->clock_valid = false;

data.clock = s->clock;
data.flags = 0;
ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
if (ret < 0) {
fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(ret));
abort();
}

if (!cap_clock_ctrl) {
return;
}
Expand All @@ -84,6 +62,26 @@ static void kvmclock_vm_state_change(void *opaque, int running,
return;
}
}
} else {
struct kvm_clock_data data;
int ret;

if (s->clock_valid) {
return;
}
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
if (ret < 0) {
fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
abort();
}
s->clock = data.clock;

/*
* If the VM is stopped, declare the clock state valid to
* avoid re-reading it on next vmsave (which would return
* a different value). Will be reset when the VM is continued.
*/
s->clock_valid = true;
}
}

Expand All @@ -100,8 +98,6 @@ static const VMStateDescription kvmclock_vmsd = {
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.pre_save = kvmclock_pre_save,
.post_load = kvmclock_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT64(clock, KVMClockState),
VMSTATE_END_OF_LIST()
Expand Down

0 comments on commit 1eeacd4

Please sign in to comment.