Thanks to visit codestin.com
Credit goes to github.com

Skip to content

hypervisor: kvm: preserve kvmclock realtime and fill if needed - #8256

Merged
rbradford merged 1 commit into
cloud-hypervisor:mainfrom
danielverkamp:kvm-clock-sync
Jun 3, 2026
Merged

rbradford merged 1 commit into
cloud-hypervisor:mainfrom
danielverkamp:kvm-clock-sync

Conversation

@danielverkamp

Copy link
Copy Markdown
Contributor

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.

@danielverkamp
danielverkamp requested a review from a team as a code owner May 19, 2026 20:06
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 <[email protected]>

@likebreath likebreath left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a behavior change: kvmclock is now automatically adjusted on resume, restore, and live-migration. It's a quick way to keep the guest's wall clock correct, but it comes at the cost of guest-visible discontinuities that can trigger softlockup/RCU stall warnings, timer storms, etc.

I'd suggest separating the two concerns. Let pause/resume focus on guest execution continuity by keeping kvmclock frozen across the transition, and use a dedicated mechanism, say virtio-rtc,to notify the guest about the wall-clock shift. The guest can then adjust its wall clock without disturbing the rest of its timekeeping. This seems like a cleaner and more programmatic split of responsibility between the VMM and the guest.

@danielverkamp

Copy link
Copy Markdown
Contributor Author

This is a behavior change: kvmclock is now automatically adjusted on resume, restore, and live-migration. It's a quick way to keep the guest's wall clock correct, but it comes at the cost of guest-visible discontinuities that can trigger softlockup/RCU stall warnings, timer storms, etc.

I think softlockup is avoided due to KVM_KVMCLOCK_CTRL, but agreed that it does cause some potential issues due to discontinuity.

I'd suggest separating the two concerns. Let pause/resume focus on guest execution continuity by keeping kvmclock frozen across the transition, and use a dedicated mechanism, say virtio-rtc,to notify the guest about the wall-clock shift. The guest can then adjust its wall clock without disturbing the rest of its timekeeping. This seems like a cleaner and more programmatic split of responsibility between the VMM and the guest.

Agreed, I think this is the better long-term plan (especially since virtio-rtc can work on non-x86 platforms, unlike kvmclock). However, I am not sure of the status of virtio-rtc implementation in cloud-hypervisor, and I don't think it currently has a direct mechanism to notify the guest of a potential discontinuity (e.g. pause/resume) where re-reading the RTC should be performed (maybe alarm could be abused to do this, but I don't think that's what it was intended for); this might need an extra feature in the virtio-rtc spec, and I'm not sure even that would fully solve the problem, since the guest will not immediately update the clock on resume, only after guest code runs for some time with the old clock state (whereas the kvmclock state can be updated before resuming the guest).

@rbradford

Copy link
Copy Markdown
Member

@likebreath Even though this is a behaviour change I think this is actually better - I think the clock lagging behind on pause/resume is almost certainly not the behaviour that the user wants. It is unfortunate that this not available on ARM immediately (we would need to extend the virtio-rtc spec to cover that) but I don't see that a reason not to improve things for the x86-64 users.

In terms of timers (mis-)firing - is this different behaviour to NTP bringing the clock forward?

It's also worth reminding ourselves that majority of the time explicit pause/resume is only really part of snapshot/restore and it's almost certainly the case that shifting to the current wallclock time is desired or implicitly part of live migration when in fact we would also not want that time to "disappear".

@likebreath

Copy link
Copy Markdown
Member

I think softlockup is avoided due to KVM_KVMCLOCK_CTRL, but agreed that it does cause some potential issues due to discontinuity.

Right. Good callout. We are already doing that from CpuManager::pause().

In terms of timers (mis-)firing - is this different behaviour to NTP bringing the clock forward?

I think so. NTP only adjusts CLOCK_REALTIME (the wall clock) and leaves CLOCK_MONOTONIC untouched. Adjusting kvmclock moves both.

To my understanding, the distinction matters because the two clocks have different contracts: CLOCK_REALTIME is meant to be adjustable (say via NTP), while CLOCK_MONOTONIC is meant to be anchored per boot and never jump. According to Claude, most kernel-internal timing, the scheduler tick, TCP retransmits, hrtimer deadlines, softlockup/RCU/hung-task watchdogs, is anchored to `CLOCK_MONOTONIC, which is supposed to be immune to wall-clock changes.

For context, I referred QEMU's implementation (which keeps kvmclock frozen across pause/resume), and came to the conclusion that separating the two concerns is the more programmatic direction.

That said, I may be missing context, and if there's a real use case demanding a quicker wall-clock fix, this isn't a blocker from my side.

Comment thread hypervisor/src/lib.rs
}
}

pub fn set_realtime(&mut self, realtime: std::time::SystemTime) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This(realtime) variable is only compiled if KVM is enabled. Shouldn't make this as kvm feature guarded?

Also, How this differs if the VMM provides an emulated RTC?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. This does the right thing on MSHV as ClockData wont be ClockData::Kvm
  2. This actually more closely matches what happens with virtio-rtc. It always returns the current time when queried.

@rbradford

Copy link
Copy Markdown
Member

I think softlockup is avoided due to KVM_KVMCLOCK_CTRL, but agreed that it does cause some potential issues due to discontinuity.

Right. Good callout. We are already doing that from CpuManager::pause().

In terms of timers (mis-)firing - is this different behaviour to NTP bringing the clock forward?

I think so. NTP only adjusts CLOCK_REALTIME (the wall clock) and leaves CLOCK_MONOTONIC untouched. Adjusting kvmclock moves both.

To my understanding, the distinction matters because the two clocks have different contracts: CLOCK_REALTIME is meant to be adjustable (say via NTP), while CLOCK_MONOTONIC is meant to be anchored per boot and never jump. According to Claude, most kernel-internal timing, the scheduler tick, TCP retransmits, hrtimer deadlines, softlockup/RCU/hung-task watchdogs, is anchored to `CLOCK_MONOTONIC, which is supposed to be immune to wall-clock changes.

For context, I referred QEMU's implementation (which keeps kvmclock frozen across pause/resume), and came to the conclusion that separating the two concerns is the more programmatic direction.

I don't think we should be thinking about this in terms of pause/resume as in that case the TSC continues to run. But rather frame this as what does a user reasonably expect the guest clock to be after restoring (or after a live migration). It would expect it to reflect the current time.

Providing time catch-up after a migration is the intended use of KVM_SET_CLOCK. From the documentation describing how to handle a migration: https://www.kernel.org/doc/Documentation/virt/kvm/devices/vcpu.rst

  1. Invoke the KVM_SET_CLOCK ioctl, providing the source nanoseconds from
    kvmclock (guest_src) and CLOCK_REALTIME (host_src) in their respective
    fields. Ensure that the KVM_CLOCK_REALTIME flag is set in the provided
    structure.

I don't think the concern about CLOCK_MONOTONIC is quite right - it's allowed to jump but never backwards (the _RAW variant is like that).

I think we should go ahead with this even though it is a change in behaviour - I would argue that this new behaviour is an improvement.

@rbradford
rbradford added this pull request to the merge queue Jun 3, 2026
Merged via the queue into cloud-hypervisor:main with commit 56e891a Jun 3, 2026
41 checks passed
@rbradford rbradford added the bug-fix Bug fix to include in release notes label Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix Bug fix to include in release notes

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

5 participants