From: sashiko-bot@kernel.org
To: "David Woodhouse" <dwmw2@infradead.org>, kvm@vger.kernel.org
Subject: Re: [PATCH v11 08/23] KVM: x86: Re-synchronize TSC after KVM_SET_TSC_KHZ
Date: Thu, 05 Nov 2026 18:22:09 +0000 [thread overview]
Message-ID: <sashiko-outbox-199742@kernel.org> (raw)
In-Reply-To: <20261105154955.2525419-9-dwmw2@infradead.org>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] KVM: x86: premature kvm_synchronize_tsc() in kvm_arch_vcpu_create()
- [High] KVM: x86: VM-wide user_set_tsc check in kvm_set_tsc_khz() breaks sync
- [Medium] KVM: x86: stale masterclock scaling state after kvm_set_tsc_khz()
- [Medium] KVM: x86: unmatched TSC generations in kvm_set_tsc_khz() after run
--
commit 485fbef9a92020d117515ff0401050c42d986ac4
Author: David Woodhouse <dwmw@amazon.co.uk>
KVM: x86: Re-synchronize TSC after KVM_SET_TSC_KHZ
This commit updates kvm_set_tsc_khz() to invoke kvm_synchronize_tsc() after
changing a vCPU's TSC frequency so that cur_tsc_scaling_ratio and TSC
generation tracking are updated. It also adds an explicit user_initiated
parameter to kvm_synchronize_tsc() to distinguish host userspace MSR_IA32_TSC
writes from internal frequency resynchronizations.
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 77bd3e4bfdcd7..f551056d72746 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -1064,6 +1064,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
> {
> u32 thresh_lo, thresh_hi;
> int use_scaling = 0;
> + u64 tsc;
>
> /* tsc_khz can be zero if TSC calibration fails */
> if (user_tsc_khz == 0) {
> @@ -1091,7 +1092,34 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
> user_tsc_khz, thresh_lo, thresh_hi);
> use_scaling = 1;
> }
> - return set_tsc_khz(vcpu, user_tsc_khz, use_scaling);
> + /*
> + * Read the guest TSC before changing the ratio, so we can
> + * re-synchronize to preserve continuity across the change.
> + */
> + tsc = kvm_read_l1_tsc(vcpu, rdtsc());
> +
> + if (set_tsc_khz(vcpu, user_tsc_khz, use_scaling))
> + return -1;
> +
> + /*
> + * Preserving continuity only makes sense for a vCPU which has
> + * actually run; for one which has not, synchronize as for a zero
> + * write, joining the current generation. This makes vCPU creation
> + * (which comes through here with the default frequency) join the
> + * generation *explicitly*, rather than by the accident that the
> + * scaling ratio is still zero at this point so the TSC read above
> + * is zero anyway — and it stops an explicit KVM_SET_TSC_KHZ on a
> + * never-run vCPU, whose nonzero TSC value could never match, from
> + * opening a new generation and orphaning the matched state of its
> + * siblings. If userspace has already written a TSC, preserve the
> + * value even for a never-run vCPU — a zero write would discard it —
> + * and let the user-write matching window do its usual job.
> + */
> + if (vcpu->arch.last_vmentry_cpu != -1 || vcpu->kvm->arch.user_set_tsc)
> + kvm_synchronize_tsc(vcpu, &tsc, false);
[Severity: High]
Does checking the VM-wide vcpu->kvm->arch.user_set_tsc flag here break TSC
synchronization when userspace configures or restores multiple never-run
vCPUs sequentially?
In __kvm_synchronize_tsc(), user_set_tsc is a VM-wide flag on struct kvm_arch:
if (user_set_tsc)
vcpu->kvm->arch.user_set_tsc = true;
If userspace initializes or restores vCPUs in a per-vCPU loop by calling
KVM_SET_TSC_KHZ followed by KVM_SET_MSRS(MSR_IA32_TSC) on each vCPU in turn:
1. Userspace creates vCPU 0 and vCPU 1 (both have last_vmentry_cpu == -1 and
creation-time TSC offsets ticking from ~0).
2. On vCPU 0, userspace calls KVM_SET_TSC_KHZ and then writes MSR_IA32_TSC
with a restored value T_restore (where T_restore > 1 second of guest
uptime). That sets vcpu->kvm->arch.user_set_tsc = true and sets
cur_tsc_write = T_restore.
3. On vCPU 1, before MSR_IA32_TSC is written on vCPU 1, userspace calls
KVM_SET_TSC_KHZ. Because the VM-wide user_set_tsc flag is already true,
kvm_set_tsc_khz() takes the first branch and passes vCPU 1's un-restored,
near-zero creation TSC (&tsc) instead of NULL.
4. In kvm_synchronize_tsc(), vCPU 1's near-zero tsc is more than 1 second
away from cur_tsc_write (T_restore), so it fails to match and opens a new
TSC generation with cur_tsc_write overwritten to that near-zero value.
5. When userspace then writes MSR_IA32_TSC = T_restore on vCPU 1, T_restore
is more than 1 second away from the clobbered near-zero cur_tsc_write, so
it fails to match again and leaves all_vcpus_matched_tsc false.
Should this check whether a TSC value was written by userspace on this
specific vCPU rather than checking the VM-wide vcpu->kvm->arch.user_set_tsc
(which is also read here without holding kvm->arch.tsc_write_lock)?
[Severity: Medium]
What happens in kvm_set_tsc_khz() when KVM_SET_TSC_KHZ is called on a
multi-vCPU guest whose vCPUs have already run (last_vmentry_cpu != -1), if
userspace has never explicitly written MSR_IA32_TSC?
Because kvm_set_tsc_khz() passes &tsc (non-zero) with user_initiated = false,
kvm->arch.user_set_tsc remains false. When kvm_synchronize_tsc() runs for each
vCPU:
if (vcpu->arch.virtual_tsc_khz) {
if (data == 0) {
synchronizing = true;
} else if (kvm->arch.user_set_tsc) {
...
}
}
Since data != 0 and kvm->arch.user_set_tsc is false, synchronizing is false
for every vCPU. Doesn't each vCPU open a separate TSC generation with
nr_vcpus_matched_tsc = 1, orphaning its siblings and leaving
all_vcpus_matched_tsc permanently false?
> + else
> + kvm_synchronize_tsc(vcpu, NULL, false);
> + return 0;
[Severity: High]
Can calling kvm_synchronize_tsc() unconditionally from kvm_set_tsc_khz()
corrupt VM-wide TSC matching state during KVM_CREATE_VCPU?
During vCPU creation, kvm_vm_ioctl_create_vcpu() calls:
kvm_vm_ioctl_create_vcpu()
-> kvm_arch_vcpu_create()
-> kvm_set_tsc_khz(vcpu, vcpu->kvm->arch.default_tsc_khz)
-> kvm_synchronize_tsc(vcpu, NULL, false)
-> __kvm_synchronize_tsc()
-> kvm_track_tsc_matching()
At the point kvm_arch_vcpu_create() runs, atomic_inc(&kvm->online_vcpus) has
not happened yet:
virt/kvm/kvm_main.c:kvm_vm_ioctl_create_vcpu() {
...
r = kvm_arch_vcpu_create(vcpu);
if (r)
goto vcpu_free_run_page;
...
smp_wmb();
atomic_inc(&kvm->online_vcpus);
mutex_unlock(&vcpu->mutex);
kvm_arch_vcpu_postcreate(vcpu);
}
Running __kvm_synchronize_tsc() and kvm_track_tsc_matching() before
online_vcpus is incremented appears to cause several regressions:
1. In kvm_track_tsc_matching():
int online = atomic_read(&vcpu->kvm->online_vcpus);
WRITE_ONCE(ka->all_vcpus_matched_tsc,
ka->nr_vcpus_matched_tsc >= online);
update_mclock |= (prev_matched_tsc != ka->all_vcpus_matched_tsc);
if (ka->all_vcpus_matched_tsc ||
ka->nr_vcpus_matched_freq >= online)
ka->all_vcpus_matched_freq = true;
If vCPU 0 is already online (online == 1) and configured to a non-default
frequency F != default_tsc_khz, creating vCPU 1 runs
__kvm_synchronize_tsc() at default_tsc_khz while online is still 1. That
resets ka->all_vcpus_matched_freq = false, increments
ka->nr_vcpus_matched_freq to 1, and sets ka->cur_tsc_khz = default_tsc_khz.
Then kvm_track_tsc_matching() sees nr_vcpus_matched_freq (1) >= online (1)
and latches ka->all_vcpus_matched_freq = true. When
kvm_arch_vcpu_postcreate() later runs with online == 2,
vcpu->arch.virtual_tsc_khz already equals ka->cur_tsc_khz, so
all_vcpus_matched_freq is never cleared and kvm_update_masterclock()
enables masterclock mode across frequency-mismatched vCPUs.
2. If userspace creates and configures vCPUs one by one (create vCPU 0, call
KVM_SET_TSC_KHZ(vcpu 0, F), then create vCPU 1, call
KVM_SET_TSC_KHZ(vcpu 1, F)), creating vCPU 1 synchronizes it at
default_tsc_khz, clobbering cur_tsc_khz, cur_tsc_offset,
cur_tsc_freq_generation, and cur_tsc_generation so that the subsequent
KVM_SET_TSC_KHZ(vcpu 1, F) only counts vCPU 1 and leaves
all_vcpus_matched_freq and all_vcpus_matched_tsc false.
3. If kvm_dirty_ring_alloc(), xa_insert(), or create_vcpu_fd() fails in
kvm_vm_ioctl_create_vcpu() after kvm_arch_vcpu_create(), the destroyed
vCPU's increments and generation changes in kvm->arch remain permanently
recorded.
Should kvm_set_tsc_khz() skip kvm_synchronize_tsc() during
kvm_arch_vcpu_create() and leave initial synchronization to
kvm_arch_vcpu_postcreate() after online_vcpus has been incremented?
[Severity: Medium]
Does the KVM_SET_TSC_KHZ ioctl path also need to process
KVM_REQ_MASTERCLOCK_UPDATE before returning to userspace?
Calling kvm_synchronize_tsc() from kvm_set_tsc_khz() updates
ka->cur_tsc_scaling_ratio and sets KVM_REQ_MASTERCLOCK_UPDATE on the vCPU via
kvm_track_tsc_matching(), but kvm_arch_vcpu_ioctl() returns to userspace
without calling kvm_update_masterclock().
In __get_kvmclock_master_clock(), get_kvmclock() uses
ka->master_tsc_scaling_ratio, ka->master_tsc_shift, and ka->master_tsc_mul,
which are only updated from ka->cur_tsc_scaling_ratio when
pvclock_update_vm_gtod_copy() runs via kvm_update_masterclock():
hv_clock.tsc_shift = ka->master_tsc_shift;
hv_clock.tsc_to_system_mul = ka->master_tsc_mul;
if (kvm_caps.has_tsc_control) {
u64 tsc_delta = data->host_tsc - ka->master_cycle_now;
tsc_delta = kvm_scale_tsc(tsc_delta, ka->master_tsc_scaling_ratio);
If userspace calls KVM_SET_TSC_KHZ and then queries KVM_GET_CLOCK before
entering KVM_RUN, won't get_kvmclock() still use the stale masterclock
scaling parameters (or remain in masterclock mode despite a frequency
mismatch)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261105154955.2525419-1-dwmw2@infradead.org?part=8
next prev parent reply other threads:[~2026-11-05 18:22 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 15:49 [PATCH v11 00/23] KVM: x86: Cleaning up the KVM clock mess, part 2 David Woodhouse
2026-11-05 15:49 ` [PATCH v11 01/23] KVM: x86: Improve synchronization in kvm_synchronize_tsc() David Woodhouse
2026-11-05 15:49 ` [PATCH v11 02/23] KVM: x86: Kill last_tsc_{nsec,write,offset} fields David Woodhouse
2026-11-05 16:47 ` sashiko-bot
2026-11-05 15:49 ` [PATCH v11 03/23] KVM: x86: Replace nr_vcpus_matched_tsc count with all_vcpus_matched_tsc bool David Woodhouse
2026-11-05 15:49 ` [PATCH v11 04/23] KVM: x86: Allow KVM master clock mode when TSCs are offset from each other David Woodhouse
2026-11-05 17:27 ` sashiko-bot
2026-11-05 15:49 ` [PATCH v11 05/23] KVM: x86: Factor out kvm_use_master_clock() David Woodhouse
2026-11-05 15:49 ` [PATCH v11 06/23] KVM: x86: Avoid gratuitous global clock updates David Woodhouse
2026-11-05 15:49 ` [PATCH v11 07/23] KVM: x86: Avoid redundant masterclock updates from multiple vCPUs David Woodhouse
2026-11-05 18:00 ` sashiko-bot
2026-11-05 15:49 ` [PATCH v11 08/23] KVM: x86: Re-synchronize TSC after KVM_SET_TSC_KHZ David Woodhouse
2026-11-05 18:22 ` sashiko-bot [this message]
2026-11-05 15:49 ` [PATCH v11 09/23] KVM: x86: Cache host vclock_mode for masterclock eligibility checks David Woodhouse
2026-11-05 15:49 ` [PATCH v11 10/23] KVM: x86: Remove pvclock_gtod_data and private timekeeping code David Woodhouse
2026-11-05 15:49 ` [PATCH v11 11/23] KVM: x86: Activate master clock from kvm_arch_init_vm() David Woodhouse
2026-11-05 19:15 ` sashiko-bot
2026-11-05 15:49 ` [PATCH v11 12/23] UAPI: x86: Move pvclock-abi to UAPI for x86 platforms David Woodhouse
2026-11-05 15:49 ` [PATCH v11 13/23] KVM: selftests: Use UAPI pvclock-abi.h in xen_shinfo_test David Woodhouse
2026-11-05 15:49 ` [PATCH v11 14/23] KVM: x86: Add KVM_[GS]ET_CLOCK_GUEST for accurate KVM clock migration David Woodhouse
2026-11-05 19:51 ` sashiko-bot
2026-11-05 15:49 ` [PATCH v11 15/23] KVM: selftests: Add library helpers for clock and TSC-offset ioctls David Woodhouse
2026-11-05 15:49 ` [PATCH v11 16/23] KVM: x86: Add KVM_VCPU_TSC_SCALE and fix the documentation on TSC migration David Woodhouse
2026-11-05 20:06 ` sashiko-bot
2026-11-05 15:49 ` [PATCH v11 17/23] KVM: selftests: Add KVM/PV clock selftest to prove timer correction David Woodhouse
2026-11-05 15:49 ` [PATCH v11 18/23] KVM: selftests: Add master clock offset test David Woodhouse
2026-11-05 20:25 ` sashiko-bot
2026-11-05 15:49 ` [PATCH v11 19/23] KVM: selftests: Add Xen/generic CPUID timing leaf test David Woodhouse
2026-11-05 15:49 ` [PATCH v11 20/23] KVM: selftests: Add Xen runstate migration test David Woodhouse
2026-11-05 15:49 ` [PATCH v11 21/23] KVM: selftests: Test that the first user TSC write is honoured exactly David Woodhouse
2026-11-05 20:50 ` sashiko-bot
2026-11-05 15:49 ` [PATCH v11 22/23] KVM: x86/xen: Drop open-coded fallback clock read in kvm_xen_start_timer() David Woodhouse
2026-11-05 15:49 ` [PATCH v11 23/23] KVM: x86: Use a single time snapshot in kvm_vm_ioctl_set_clock() 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-199742@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