From: sashiko-bot@kernel.org
To: "David Woodhouse" <dwmw2@infradead.org>, kvm@vger.kernel.org
Subject: Re: [PATCH v12 14/24] KVM: x86: Add KVM_[GS]ET_CLOCK_GUEST for accurate KVM clock migration
Date: Mon, 09 Nov 2026 01:53:59 +0000 [thread overview]
Message-ID: <sashiko-outbox-204333@kernel.org> (raw)
In-Reply-To: <20261109012112.3415328-15-dwmw2@infradead.org>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] KVM: x86: stale masterclock state read in
kvm_vcpu_ioctl_get_clock_guest()
- [Medium] KVM: x86: mismatched TSC scaling in KVM_[GS]ET_CLOCK_GUEST
for protected TSC
--
commit c242a430a092692493307282dff57c9d0a945477
Author: Jack Allister <jalliste@amazon.com>
KVM: x86: Add KVM_[GS]ET_CLOCK_GUEST for accurate KVM clock migration
This commit adds the KVM_GET_CLOCK_GUEST and KVM_SET_CLOCK_GUEST vCPU ioctls
and KVM_CAP_CLOCK_GUEST capability to save and restore the guest pvclock
relationship to the guest TSC across migration.
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 4afafe7ed8b8a..00e6b2bdaffb5 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
[ ... ]
> @@ -3674,6 +3677,197 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
> }
> }
>
> +#ifdef CONFIG_X86_64
> +static int kvm_vcpu_ioctl_get_clock_guest(struct kvm_vcpu *v, void __user *argp)
> +{
> + struct pvclock_vcpu_time_info hv_clock = {};
> + struct kvm_arch *ka = &v->kvm->arch;
> + bool use_master_clock;
> + unsigned int seq;
> +
> + /*
> + * Construct the pvclock purely from the master clock state. The
> + * master mul/shift are computed for the guest TSC frequency, which
> + * in master clock mode is the frequency of every vCPU; only the
> + * tsc_timestamp is per-vCPU, translating the master snapshot into
> + * this vCPU's TSC domain via its scaling ratio and offset.
> + *
> + * Note, this deliberately does NOT invoke kvm_guest_time_update(),
> + * which would write the guest's pvclock pages: dirtying guest
> + * memory after the final KVM_RUN would break post-copy migration
> + * flows. The pvclock returned here describes the same clock as the
> + * guest-visible copy (the same linear function of the guest TSC),
> + * anchored at the current master clock snapshot.
> + *
> + * Translating the snapshot through the vCPU's *current* scaling
> + * ratio and offset is correct even if they changed after the
> + * snapshot was taken: the snapshot anchors a host TSC value, not
> + * a guest one. A frequency change whose masterclock update is
> + * still pending does leave stale mul/shift here, but that is the
> + * paused-VM migration path reading a frequency userspace itself
> + * has just changed — and the result fails safe, as the same-vCPU
> + * KVM_SET_CLOCK_GUEST on the destination rejects a mul/shift
> + * inconsistent with the vCPU's frequency with -ERANGE.
> + */
> + do {
> + seq = read_seqcount_begin(&ka->pvclock_sc);
> +
> + use_master_clock = ka->use_master_clock;
> + if (!use_master_clock)
> + continue;
> +
> + hv_clock.tsc_timestamp = kvm_read_l1_tsc(v, ka->master_cycle_now);
> + hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset;
> + hv_clock.tsc_shift = ka->master_tsc_shift;
> + hv_clock.tsc_to_system_mul = ka->master_tsc_mul;
> + hv_clock.flags = READ_ONCE(ka->all_vcpus_matched_tsc) ?
> + PVCLOCK_TSC_STABLE_BIT : 0;
> + } while (read_seqcount_retry(&ka->pvclock_sc, seq));
[Severity: High]
Can kvm_vcpu_ioctl_get_clock_guest() return stale or corrupted pvclock data
when a KVM_REQ_MASTERCLOCK_UPDATE is pending?
Events that invalidate or change the master clock (such as a host suspend
and resume with a backwards TSC, a host clocksource change away from TSC, or
a per-vCPU KVM_SET_TSC_KHZ) only queue KVM_REQ_MASTERCLOCK_UPDATE on vCPUs
without updating ka->use_master_clock, ka->master_cycle_now, or
ka->master_tsc_mul and ka->master_tsc_shift until vcpu_enter_guest() runs.
If the host suspends and resumes while the VM is paused,
kvm_arch_enable_virtualization_cpu() sets ka->backwards_tsc_observed, adds
vcpu->arch.tsc_offset_adjustment, and requests KVM_REQ_MASTERCLOCK_UPDATE.
When userspace then calls KVM_GET_CLOCK_GUEST, vcpu_load() ->
kvm_arch_vcpu_load() applies tsc_offset_adjustment to v->arch.l1_tsc_offset
before kvm_vcpu_ioctl_get_clock_guest() runs:
arch/x86/kvm/x86.c:kvm_arch_vcpu_load() {
...
if (unlikely(vcpu->arch.tsc_offset_adjustment)) {
adjust_tsc_offset_host(vcpu, vcpu->arch.tsc_offset_adjustment);
vcpu->arch.tsc_offset_adjustment = 0;
kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
}
...
}
kvm_vcpu_ioctl_get_clock_guest() still sees ka->use_master_clock == true,
combines the post-resume l1_tsc_offset with the pre-suspend
ka->master_cycle_now, and succeeds instead of returning -ENODATA. Because
ka->master_tsc_mul and ka->master_tsc_shift still match the vCPU's TSC
frequency, KVM_SET_CLOCK_GUEST does not reject the state with -ERANGE and
instead corrupts ka->kvmclock_offset. Similarly, if KVM_SET_TSC_KHZ changes
one vCPU's frequency in a multi-vCPU VM, ka->all_vcpus_matched_freq becomes
false, but calling KVM_GET_CLOCK_GUEST on an unmodified vCPU sees stale
ka->use_master_clock == true with a mul/shift that still matches that vCPU.
Calling kvm_update_masterclock() when needed would refresh the host-side
master clock state in struct kvm_arch without calling
kvm_guest_time_update() or dirtying guest pvclock pages.
[ ... ]
> + /*
> + * Nonzero, or pvclock_update_vm_gtod_copy() — which read it on
> + * this CPU, with interrupts still disabled — would have cleared
> + * use_master_clock above.
> + */
> + curr_tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ;
> +
> + if (kvm_caps.has_tsc_control)
> + curr_tsc_hz = kvm_scale_tsc(curr_tsc_hz,
> + v->arch.l1_tsc_scaling_ratio);
> +
> + /*
> + * The mul/shift in the provided pvclock structure encode the guest
> + * TSC frequency at which it was generated. Sanity-check that it is
> + * consistent with this vCPU's effective TSC frequency, allowing a
> + * discrepancy of 1 kHz either way since independently calibrated
> + * hosts will not measure precisely the same value even for the
> + * same nominal frequency. Compare in kHz: the reconstruction of
> + * each side's frequency in Hz carries a few Hz of rounding, which
> + * must not push two hosts calibrated exactly 1 kHz apart over the
> + * line.
> + */
> + user_tsc_khz = DIV_ROUND_CLOSEST_ULL(user_tsc_hz, HZ_PER_KHZ);
> + curr_tsc_khz = DIV_ROUND_CLOSEST_ULL(curr_tsc_hz, HZ_PER_KHZ);
> + if (user_tsc_khz + 1 < curr_tsc_khz ||
> + user_tsc_khz > curr_tsc_khz + 1) {
> + rc = -ERANGE;
> + goto out;
> + }
[Severity: Medium]
Does KVM_GET_CLOCK_GUEST return an unscaled mul/shift that
KVM_SET_CLOCK_GUEST rejects with -ERANGE when a protected-TSC guest uses a
non-default TSC frequency?
For guests with vcpu->arch.guest_tsc_protected set (such as TDX or SEV-SNP
with Secure TSC), userspace configures the guest TSC frequency via the VM
KVM_SET_TSC_KHZ ioctl before creating vCPUs, which sets
kvm->arch.default_tsc_khz without updating kvm->arch.cur_tsc_scaling_ratio.
During KVM_CREATE_VCPU, kvm_arch_vcpu_create() sets
vcpu->arch.l1_tsc_scaling_ratio from default_tsc_khz, but
kvm_arch_vcpu_postcreate() -> kvm_synchronize_tsc() ->
__kvm_synchronize_tsc() returns early before updating
kvm->arch.cur_tsc_scaling_ratio:
arch/x86/kvm/x86.c:__kvm_synchronize_tsc() {
...
if (vcpu->arch.guest_tsc_protected)
return;
...
kvm->arch.cur_tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio;
...
}
pvclock_update_vm_gtod_copy() then computes ka->master_tsc_shift and
ka->master_tsc_mul from ka->cur_tsc_scaling_ratio, which is still
kvm_caps.default_tsc_scaling_ratio. As a result,
kvm_vcpu_ioctl_get_clock_guest() scales hv_clock.tsc_timestamp with
v->arch.l1_tsc_scaling_ratio via kvm_read_l1_tsc(), but copies the unscaled
ka->master_tsc_shift and ka->master_tsc_mul, and
kvm_vcpu_ioctl_set_clock_guest() rejects that structure with -ERANGE when
comparing against curr_tsc_hz scaled by v->arch.l1_tsc_scaling_ratio.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261109012112.3415328-1-dwmw2@infradead.org?part=14
next prev parent reply other threads:[~2026-11-09 1:54 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 1:20 [PATCH v12 00/24] KVM: x86: Cleaning up the KVM clock mess, part 2 David Woodhouse
2026-11-09 1:20 ` [PATCH v12 01/24] KVM: x86: Improve synchronization in kvm_synchronize_tsc() David Woodhouse
2026-11-09 1:20 ` [PATCH v12 02/24] KVM: x86: Kill last_tsc_{nsec,write,offset} fields David Woodhouse
2026-11-09 1:20 ` [PATCH v12 03/24] KVM: x86: Replace nr_vcpus_matched_tsc count with all_vcpus_matched_tsc bool David Woodhouse
2026-11-09 1:53 ` sashiko-bot
2026-11-09 1:20 ` [PATCH v12 04/24] KVM: x86: Allow KVM master clock mode when TSCs are offset from each other David Woodhouse
2026-11-09 1:45 ` sashiko-bot
2026-11-09 1:20 ` [PATCH v12 05/24] KVM: x86: Factor out kvm_use_master_clock() David Woodhouse
2026-11-09 1:20 ` [PATCH v12 06/24] KVM: x86: Avoid gratuitous global clock updates David Woodhouse
2026-11-09 1:20 ` [PATCH v12 07/24] KVM: x86: Avoid redundant masterclock updates from multiple vCPUs David Woodhouse
2026-11-09 1:53 ` sashiko-bot
2026-11-09 1:20 ` [PATCH v12 08/24] KVM: x86: Re-synchronize TSC after KVM_SET_TSC_KHZ David Woodhouse
2026-11-09 1:53 ` sashiko-bot
2026-11-09 6:24 ` kernel test robot
2026-11-10 5:21 ` kernel test robot
2026-11-09 1:20 ` [PATCH v12 09/24] KVM: x86: Cache host vclock_mode for masterclock eligibility checks David Woodhouse
2026-11-09 1:20 ` [PATCH v12 10/24] KVM: x86: Remove pvclock_gtod_data and private timekeeping code David Woodhouse
2026-11-09 1:20 ` [PATCH v12 11/24] KVM: x86: Activate master clock from kvm_arch_init_vm() David Woodhouse
2026-11-09 1:56 ` sashiko-bot
2026-11-09 1:20 ` [PATCH v12 12/24] UAPI: x86: Move pvclock-abi to UAPI for x86 platforms David Woodhouse
2026-11-09 1:20 ` [PATCH v12 13/24] KVM: selftests: Use UAPI pvclock-abi.h in xen_shinfo_test David Woodhouse
2026-11-09 1:21 ` [PATCH v12 14/24] KVM: x86: Add KVM_[GS]ET_CLOCK_GUEST for accurate KVM clock migration David Woodhouse
2026-11-09 1:53 ` sashiko-bot [this message]
2026-11-09 1:21 ` [PATCH v12 15/24] KVM: selftests: Add library helpers for clock and TSC-offset ioctls David Woodhouse
2026-11-09 1:21 ` [PATCH v12 16/24] KVM: x86: Add KVM_VCPU_TSC_SCALE and fix the documentation on TSC migration David Woodhouse
2026-11-09 1:44 ` sashiko-bot
2026-11-09 1:21 ` [PATCH v12 17/24] KVM: selftests: Add KVM/PV clock selftest to prove timer correction David Woodhouse
2026-11-09 1:21 ` [PATCH v12 18/24] KVM: selftests: Add master clock offset test David Woodhouse
2026-11-09 1:47 ` sashiko-bot
2026-11-09 1:21 ` [PATCH v12 19/24] KVM: selftests: Add Xen/generic CPUID timing leaf test David Woodhouse
2026-11-09 1:21 ` [PATCH v12 20/24] KVM: selftests: Add Xen runstate migration test David Woodhouse
2026-11-09 1:21 ` [PATCH v12 21/24] KVM: selftests: Test that the first user TSC write is honoured exactly David Woodhouse
2026-11-09 1:21 ` [PATCH v12 22/24] KVM: x86/xen: Drop open-coded fallback clock read in kvm_xen_start_timer() David Woodhouse
2026-11-09 1:21 ` [PATCH v12 23/24] KVM: x86: Use a single time snapshot in kvm_vm_ioctl_set_clock() David Woodhouse
2026-11-09 1:21 ` [PATCH v12 24/24] KVM: x86: Keep master clock for guests using legacy MSR_KVM_SYSTEM_TIME David Woodhouse
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-204333@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dwmw2@infradead.org \
--cc=kvm@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox