mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
KVM: x86/xen: Prevent runstate times from becoming negative
When kvm_xen_update_runstate() is invoked to set a vCPU's runstate, the time spent in the previous runstate is accounted. This is based on the delta between the current KVM clock time, and the previous value stored in vcpu->arch.xen.runstate_entry_time. If the KVM clock goes backwards, that delta will be negative. Or, since it's an unsigned 64-bit integer, very *large*. Linux guests deal with that particularly badly, reporting 100% steal time for ever more (well, for *centuries* at least, until the delta has been consumed). So when a negative delta is detected, just refrain from updating the runstate times until the KVM clock catches up with runstate_entry_time again. Also clamp steal_ns to delta_ns to prevent steal time from exceeding the total elapsed time, and handle negative steal_ns (which can happen if run_delay goes backwards across a scheduler update). The userspace APIs for setting the runstate times do not allow them to be set past the current KVM clock, but userspace can still adjust the KVM clock *after* setting the runstate times, which would cause this situation to occur. Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> Reviewed-by: Paul Durrant <paul@xen.org> Link: https://patch.msgid.link/20260728144954.355376-21-dwmw2@infradead.org Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
parent
633d7652f8
commit
36a8520064
|
|
@ -586,29 +586,45 @@ void kvm_xen_update_runstate(struct kvm_vcpu *v, int state)
|
|||
{
|
||||
struct kvm_vcpu_xen *vx = &v->arch.xen;
|
||||
u64 now = get_kvmclock_ns(v->kvm);
|
||||
u64 delta_ns = now - vx->runstate_entry_time;
|
||||
u64 run_delay = current->sched_info.run_delay;
|
||||
s64 delta_ns = now - vx->runstate_entry_time;
|
||||
s64 steal_ns = run_delay - vx->last_steal;
|
||||
|
||||
/*
|
||||
* If the vCPU was never run before, its prior state should
|
||||
* be considered RUNSTATE_offline.
|
||||
*/
|
||||
if (unlikely(!vx->runstate_entry_time))
|
||||
vx->current_runstate = RUNSTATE_offline;
|
||||
|
||||
/*
|
||||
* If KVM clock went backwards, just update the current runstate
|
||||
* but don't account any time. Leave entry_time unchanged so the
|
||||
* next positive delta covers the full period once the clock
|
||||
* catches up. Update last_steal every time so stolen time only
|
||||
* reflects the interval since the most recent call.
|
||||
*/
|
||||
if (delta_ns < 0)
|
||||
goto update_guest;
|
||||
|
||||
/*
|
||||
* Time waiting for the scheduler isn't "stolen" if the
|
||||
* vCPU wasn't running anyway.
|
||||
*/
|
||||
if (vx->current_runstate == RUNSTATE_running) {
|
||||
u64 steal_ns = run_delay - vx->last_steal;
|
||||
if (vx->current_runstate == RUNSTATE_running && steal_ns > 0) {
|
||||
if (steal_ns > delta_ns)
|
||||
steal_ns = delta_ns;
|
||||
|
||||
delta_ns -= steal_ns;
|
||||
|
||||
vx->runstate_times[RUNSTATE_runnable] += steal_ns;
|
||||
}
|
||||
vx->last_steal = run_delay;
|
||||
|
||||
vx->runstate_times[vx->current_runstate] += delta_ns;
|
||||
vx->current_runstate = state;
|
||||
vx->runstate_entry_time = now;
|
||||
|
||||
update_guest:
|
||||
vx->current_runstate = state;
|
||||
vx->last_steal = run_delay;
|
||||
if (vx->runstate_cache.active)
|
||||
kvm_xen_update_runstate_guest(v, state == RUNSTATE_runnable);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user