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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.