mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
hypervisor: kvm: preserve kvmclock realtime and fill if needed
If `KVM_GET_CLOCK` already filled out the `realtime` field, it sets the `KVM_CLOCK_REALTIME` flag, but if we instead preserve this flag, the kernel will automatically adjust the kvmclock clock when calling `KVM_SET_CLOCK` based on the elapsed wall-clock time between pause and resume. This just requires removing the `reset_flags()` function, which allows the `KVM_CLOCK_REALTIME` flag to persist in the serialized clock state. However, the kernel does not always fill the `realtime` field, depending on clock source; in this case, fill `realtime` during pause based on the system time. This is not as precise as the automatic `KVM_GET_CLOCK` version, since we query the time slightly after the vCPU was paused, but it allows the clock to be resumed mostly in sync instead of being wildly off. In this case, we also set the `KVM_CLOCK_REALTIME` flag in the saved `struct kvmclock` so `KVM_SET_CLOCK` will adjust the clock on resume. Basic test case: 1. Run a VM with a Linux guest. 2. Pause the guest via `vm.pause` API. 3. Wait several minutes. 4. Resume the guest via `vm.resume` API. 5. Verify the guest time (e.g. via `date` command) is valid. 6. Verify guest is still using `kvm-clock` timesource: cat /sys/devices/system/clocksource/clocksource0/current_clocksource Before applying the patch, the guest clock would be off by the delta time between pause and resume; after the patch, the clock is (more or less) in sync with the correct wall-clock time. Old snapshots will not have the `KVM_CLOCK_REALTIME` flag populated, so they will not be affected by the new behavior. Signed-off-by: Daniel Verkamp <drv@meta.com>
This commit is contained in:
committed by
Rob Bradford
parent
81f9cd068f
commit
56e891a405
@@ -184,12 +184,28 @@ pub enum ClockData {
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
impl ClockData {
|
||||
pub fn reset_flags(&mut self) {
|
||||
pub fn has_realtime(&self) -> bool {
|
||||
match self {
|
||||
#[cfg(feature = "kvm")]
|
||||
ClockData::Kvm(s) => s.flags = 0,
|
||||
ClockData::Kvm(s) => s.flags & kvm_bindings::KVM_CLOCK_REALTIME != 0,
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => {}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_realtime(&mut self, realtime: std::time::SystemTime) {
|
||||
match self {
|
||||
#[cfg(feature = "kvm")]
|
||||
ClockData::Kvm(s) => {
|
||||
if let Ok(time_since_epoch) = realtime.duration_since(std::time::UNIX_EPOCH) {
|
||||
s.realtime = time_since_epoch.as_nanos() as u64;
|
||||
s.flags |= kvm_bindings::KVM_CLOCK_REALTIME;
|
||||
}
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => {
|
||||
let _ = realtime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user