Linux Kernel Selftest development
 help / color / mirror / Atom feed
* [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64)
@ 2026-08-16  5:33 Dongli Zhang
  2026-08-16  5:33 ` [PATCH 1/4] KVM: x86: Reset last_steal on vCPU pid change Dongli Zhang
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Dongli Zhang @ 2026-08-16  5:33 UTC (permalink / raw)
  To: kvm, kvmarm, linux-kselftest
  Cc: seanjc, pbonzini, maz, oupton, fuad.tabba, joey.gouly, seiden,
	suzuki.poulose, yuzenghui, dwmw2, joe.jin

I previously sent the patchset below, but I am not sending this series as
v2 because the topic has changed significantly.

[PATCH 0/5] Fix and enhance KVM steal accounting for both guest and host
https://lore.kernel.org/all/20260505003044.78693-1-dongli.zhang@oracle.com

KVM does not support vCPU hotplug. When a vCPU is removed, its
corresponding data structures are not freed by KVM. Instead, QEMU destroys
only the userspace state and the vCPU thread, while the KVM vCPU fd remains
open and parked in QEMU.

As a result, vcpu->arch.st.last_steal is not reset. If the same vCPU is
later re-created by QEMU, last_steal retains its old value, while
current->sched_info.run_delay starts from zero since a new vCPU thread is
created. This causes current->sched_info.run_delay - vcpu->arch.st.last_steal
to produce a large, bogus value.

For instance, current->sched_info.run_delay can become smaller than
vcpu->arch.st.last_steal (see line 3804) if a QEMU vCPU is re-added after
it has previously been removed.

As a result, st->steal restarts from a very small value, close to
current->sched_info.run_delay.

3720 static void record_steal_time(struct kvm_vcpu *vcpu)
3721 {
... ...
3803         unsafe_get_user(steal, &st->steal, out);
3804         steal += current->sched_info.run_delay -
3805                 vcpu->arch.st.last_steal;
3806         vcpu->arch.st.last_steal = current->sched_info.run_delay;
3807         unsafe_put_user(steal, &st->steal, out);


This patchset:

1. Resets vcpu->arch.st.last_steal when the vCPU PID changes, as suggested
by Sean. Both x86 and arm64 are supported.

2. Although David suggested accounting the run_delay left over from the
previous vCPU PID, this series does not do that. It would be easy to make
that work if KVM could simply assume every transition is a vCPU PID change.
In practice, KVM does not always have enough information about the previous
vCPU PID, e.g. after live migration, unless a new ioctl is introduced. For
now, this series simply resets last_steal.

3. Although David also suggested doing the same for Xen-on-KVM vCPUs, this
series does not reset last_steal for Xen vCPUs. That change itself would
not be difficult, but Xen uses a different mechanism to account downtime,
including runnable time and offline time when a vCPU is not running. It may
therefore need no additional ioctl, or a smaller ioctl extension, to account
run_delay left over from the previous PID. For now, this series changes only
regular x86 steal time and arm64 PV time.

4. Guest kernel changes are not included. I may send it separately to keep
this series limited to the KVM hypervisor.

[PATCH 1/5] x86/kvm: Reset prev_steal_time and prev_steal_time_rq when enabling steal time
https://lore.kernel.org/all/20260505003044.78693-2-dongli.zhang@oracle.com

5. There is one remaining corner case: this series resets last_steal when
the vCPU run PID changes, but not when steal time is enabled. If additional
host run_delay is accumulated after the PID changes but before the guest
enables steal time, that delta could be unexpectedly accounted to guest
vCPU steal time. In practice, this should not happen for Linux guests.


Dongli Zhang (4)
  KVM: x86: Reset last_steal on vCPU pid change
  KVM: arm64: Reset last_steal on vCPU pid change
  KVM: selftests: Test steal time across vCPU pid changes on x86
  KVM: selftests: Add arm64 coverage for steal time pid changes

 arch/arm64/include/asm/kvm_host.h               |   1 +
 arch/arm64/kvm/arm.c                            |   2 +
 arch/arm64/kvm/pvtime.c                         |   5 +
 arch/x86/kvm/Kconfig                            |   1 +
 arch/x86/kvm/x86.c                              |   7 +
 tools/testing/selftests/kvm/Makefile.kvm        |   2 +
 .../selftests/kvm/steal_time_change_pid.c       | 216 +++++++++++++++++++
 7 files changed, 234 insertions(+)

base-commit: 3eb40771c00a8488fa6ed2cc1fe203477908bf38

Thank you very much!

Dongli Zhang


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/4] KVM: x86: Reset last_steal on vCPU pid change
  2026-08-16  5:33 [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64) Dongli Zhang
@ 2026-08-16  5:33 ` Dongli Zhang
  2026-08-16  5:33 ` [PATCH 2/4] KVM: arm64: " Dongli Zhang
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Dongli Zhang @ 2026-08-16  5:33 UTC (permalink / raw)
  To: kvm, kvmarm, linux-kselftest
  Cc: seanjc, pbonzini, maz, oupton, fuad.tabba, joey.gouly, seiden,
	suzuki.poulose, yuzenghui, dwmw2, joe.jin

KVM does not support vCPU hotplug. When a vCPU is removed, its
corresponding data structures are not freed by KVM. Instead, QEMU destroys
only the userspace state and the vCPU thread, while the KVM vCPU fd remains
open and parked in QEMU.

As a result, vcpu->arch.st.last_steal is not reset.

If the same vCPU is later re-created by QEMU, last_steal retains its old
value, while current->sched_info.run_delay starts from zero since a new
vCPU thread is created. This causes
current->sched_info.run_delay - vcpu->arch.st.last_steal to produce a
large, bogus value.

Fix this by resetting vcpu->arch.st.last_steal unconditionally to
current->sched_info.run_delay when KVM vCPU PID is changed.

Assisted-by: Codex:GPT-5.5
Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
---
 arch/x86/kvm/Kconfig | 1 +
 arch/x86/kvm/x86.c   | 7 +++++++
 2 files changed, 8 insertions(+)

diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 801bf9e520db..b7cb2ceda6d9 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -40,6 +40,7 @@ config KVM_X86
 	select HAVE_KVM_MSI
 	select HAVE_KVM_CPU_RELAX_INTERCEPT
 	select HAVE_KVM_NO_POLL
+	select HAVE_KVM_VCPU_RUN_PID_CHANGE
 	select VIRT_XFER_TO_GUEST_WORK
 	select KVM_GENERIC_DIRTYLOG_READ_PROTECT
 	select KVM_VFIO
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 47cb9eba113b..33be45eec32b 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3717,6 +3717,13 @@ void kvm_service_local_tlb_flush_requests(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_service_local_tlb_flush_requests);
 
+int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.st.last_steal = current->sched_info.run_delay;
+
+	return 0;
+}
+
 static void record_steal_time(struct kvm_vcpu *vcpu)
 {
 	struct gfn_to_hva_cache *ghc = &vcpu->arch.st.cache;
-- 
2.43.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/4] KVM: arm64: Reset last_steal on vCPU pid change
  2026-08-16  5:33 [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64) Dongli Zhang
  2026-08-16  5:33 ` [PATCH 1/4] KVM: x86: Reset last_steal on vCPU pid change Dongli Zhang
@ 2026-08-16  5:33 ` Dongli Zhang
  2026-08-17  8:42   ` Marc Zyngier
  2026-08-16  5:33 ` [PATCH 3/4] KVM: selftests: Test steal time across vCPU pid changes on x86 Dongli Zhang
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 7+ messages in thread
From: Dongli Zhang @ 2026-08-16  5:33 UTC (permalink / raw)
  To: kvm, kvmarm, linux-kselftest
  Cc: seanjc, pbonzini, maz, oupton, fuad.tabba, joey.gouly, seiden,
	suzuki.poulose, yuzenghui, dwmw2, joe.jin

The previous commit resets x86 steal time accounting when the vCPU PID is
changed. Do the same for arm64.

KVM keeps a vCPU fd alive when userspace hot-unplugs a vCPU. If the fd is
later reused from a new vCPU thread, vcpu->arch.steal.last_steal still
reflects the old task's run_delay, while current->sched_info.run_delay
belongs to the new task.

Reset vcpu->arch.steal.last_steal from kvm_arch_vcpu_run_pid_change()
unconditionally so the next stolen time update computes its delta against
the new task's run_delay.

Assisted-by: Codex:GPT-5.5
Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
---
 arch/arm64/include/asm/kvm_host.h | 1 +
 arch/arm64/kvm/arm.c              | 2 ++
 arch/arm64/kvm/pvtime.c           | 5 +++++
 3 files changed, 8 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index bae2c4f92ef5..4607f956e787 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1339,6 +1339,7 @@ static inline bool kvm_arch_pmi_in_guest(struct kvm_vcpu *vcpu)
 long kvm_hypercall_pv_features(struct kvm_vcpu *vcpu);
 gpa_t kvm_init_stolen_time(struct kvm_vcpu *vcpu);
 void kvm_update_stolen_time(struct kvm_vcpu *vcpu);
+void kvm_reset_stolen_time(struct kvm_vcpu *vcpu);
 
 bool kvm_arm_pvtime_supported(void);
 int kvm_arm_pvtime_set_attr(struct kvm_vcpu *vcpu,
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 9a6c72a18672..0f6e63eace21 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -929,6 +929,8 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
 	if (!kvm_arm_vcpu_is_finalized(vcpu))
 		return -EPERM;
 
+	kvm_reset_stolen_time(vcpu);
+
 	if (likely(vcpu_has_run_once(vcpu)))
 		return 0;
 
diff --git a/arch/arm64/kvm/pvtime.c b/arch/arm64/kvm/pvtime.c
index 4ceabaa4c30b..000bf49cc0fd 100644
--- a/arch/arm64/kvm/pvtime.c
+++ b/arch/arm64/kvm/pvtime.c
@@ -32,6 +32,11 @@ void kvm_update_stolen_time(struct kvm_vcpu *vcpu)
 	srcu_read_unlock(&kvm->srcu, idx);
 }
 
+void kvm_reset_stolen_time(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.steal.last_steal = current->sched_info.run_delay;
+}
+
 long kvm_hypercall_pv_features(struct kvm_vcpu *vcpu)
 {
 	u32 feature = smccc_get_arg1(vcpu);
-- 
2.43.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/4] KVM: selftests: Test steal time across vCPU pid changes on x86
  2026-08-16  5:33 [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64) Dongli Zhang
  2026-08-16  5:33 ` [PATCH 1/4] KVM: x86: Reset last_steal on vCPU pid change Dongli Zhang
  2026-08-16  5:33 ` [PATCH 2/4] KVM: arm64: " Dongli Zhang
@ 2026-08-16  5:33 ` Dongli Zhang
  2026-08-16  5:33 ` [PATCH 4/4] KVM: selftests: Add arm64 coverage for steal time pid changes Dongli Zhang
  2026-08-17  8:15 ` [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64) Marc Zyngier
  4 siblings, 0 replies; 7+ messages in thread
From: Dongli Zhang @ 2026-08-16  5:33 UTC (permalink / raw)
  To: kvm, kvmarm, linux-kselftest
  Cc: seanjc, pbonzini, maz, oupton, fuad.tabba, joey.gouly, seiden,
	suzuki.poulose, yuzenghui, dwmw2, joe.jin

Add a selftest for the case where the same vCPU fd is run from a new host
thread after steal time has already been enabled and updated.

Pin the vCPU thread and a busy-loop thread to CPU 0, force host-side
run_delay to accumulate, and run the vCPU again to observe guest steal
time. Then run the same vCPU fd from a newly created host thread and verify
that the next steal time value observed on the new thread remains monotonic
and sane relative to the value observed on the old thread.

This indirectly validates that vcpu->arch.st.last_steal is reset when the
vCPU run PID changes.

Assisted-by: Codex:GPT-5.5
Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 .../selftests/kvm/steal_time_change_pid.c     | 162 ++++++++++++++++++
 2 files changed, 163 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/steal_time_change_pid.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 6fc34e9bf8e1..c8ce17851561 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -159,6 +159,7 @@ TEST_GEN_PROGS_x86 += hardware_disable_test
 TEST_GEN_PROGS_x86 += mmu_stress_test
 TEST_GEN_PROGS_x86 += rseq_test
 TEST_GEN_PROGS_x86 += steal_time
+TEST_GEN_PROGS_x86 += steal_time_change_pid
 TEST_GEN_PROGS_x86 += system_counter_offset_test
 TEST_GEN_PROGS_x86 += pre_fault_memory_test
 
diff --git a/tools/testing/selftests/kvm/steal_time_change_pid.c b/tools/testing/selftests/kvm/steal_time_change_pid.c
new file mode 100644
index 000000000000..3c39594db398
--- /dev/null
+++ b/tools/testing/selftests/kvm/steal_time_change_pid.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Verify that KVM resets steal-time accounting when a vCPU fd is run from
+ * a different host PID.
+ */
+
+#include <pthread.h>
+#include <asm/kvm_para.h>
+#include "kvm_util.h"
+#include "processor.h"
+
+#define ST_GPA_BASE		(1 << 30)
+#define ST_SANE_DELTA_NS	(1ULL << 63)
+
+static void *st_gva;
+static u64 guest_stolen_time;
+static u64 main_steal;
+static u64 thread_steal;
+
+#if defined(__x86_64__)
+
+#define STEAL_TIME_SIZE	((sizeof(struct kvm_steal_time) + 63) & ~63)
+
+static void guest_code(void)
+{
+	struct kvm_steal_time *st = st_gva;
+
+	WRITE_ONCE(guest_stolen_time, READ_ONCE(st->steal));
+	GUEST_SYNC(0);
+
+	WRITE_ONCE(guest_stolen_time, READ_ONCE(st->steal));
+	GUEST_SYNC(1);
+
+	WRITE_ONCE(guest_stolen_time, READ_ONCE(st->steal));
+	GUEST_DONE();
+}
+
+static bool steal_time_supported(struct kvm_vcpu *vcpu)
+{
+	return kvm_cpu_has(X86_FEATURE_KVM_STEAL_TIME);
+}
+
+static void steal_time_enable(struct kvm_vcpu *vcpu)
+{
+	vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME,
+		     (ulong)st_gva | KVM_MSR_ENABLED);
+}
+
+#else
+#error "steal_time_change_pid is not implemented on this architecture"
+#endif
+
+static void run_vcpu(struct kvm_vcpu *vcpu)
+{
+	struct ucall uc;
+
+	vcpu_run(vcpu);
+
+	switch (get_ucall(vcpu, &uc)) {
+	case UCALL_SYNC:
+	case UCALL_DONE:
+		break;
+	case UCALL_ABORT:
+		REPORT_GUEST_ASSERT(uc);
+	default:
+		TEST_ASSERT(false, "Unexpected exit: %s",
+			    exit_reason_str(vcpu->run->exit_reason));
+	}
+}
+
+static void *do_steal_time(void *arg)
+{
+	struct timespec ts, stop;
+
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	stop = timespec_add_ns(ts, MIN_RUN_DELAY_NS);
+
+	while (timespec_to_ns(timespec_sub(ts, stop)) < 0)
+		clock_gettime(CLOCK_MONOTONIC, &ts);
+
+	return NULL;
+}
+
+static void *vcpu_thread(void *arg)
+{
+	struct kvm_vcpu *vcpu = arg;
+
+	run_vcpu(vcpu);
+	sync_global_from_guest(vcpu->vm, guest_stolen_time);
+	thread_steal = guest_stolen_time;
+
+	return NULL;
+}
+
+int main(void)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	pthread_attr_t attr;
+	pthread_t thread;
+	cpu_set_t cpuset;
+	long run_delay;
+	long run_delay_delta;
+
+	ksft_print_header();
+	ksft_set_plan(1);
+
+	CPU_ZERO(&cpuset);
+	CPU_SET(0, &cpuset);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset);
+	pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    ST_GPA_BASE, 1, 1, 0);
+	virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, 1);
+
+	st_gva = (void *)ST_GPA_BASE;
+	sync_global_to_guest(vm, st_gva);
+	memset(addr_gva2hva(vm, ST_GPA_BASE), 0, STEAL_TIME_SIZE);
+
+	TEST_REQUIRE(steal_time_supported(vcpu));
+
+	steal_time_enable(vcpu);
+	run_vcpu(vcpu);
+
+	run_delay = get_run_delay();
+	pthread_create(&thread, &attr, do_steal_time, NULL);
+
+	while (get_run_delay() - run_delay < MIN_RUN_DELAY_NS)
+		sched_yield();
+
+	pthread_join(thread, NULL);
+	run_delay_delta = get_run_delay() - run_delay;
+	TEST_ASSERT(run_delay_delta >= MIN_RUN_DELAY_NS,
+		    "Expected run_delay >= %ld, got %ld",
+		    MIN_RUN_DELAY_NS, run_delay_delta);
+
+	run_vcpu(vcpu);
+	sync_global_from_guest(vm, guest_stolen_time);
+	main_steal = guest_stolen_time;
+
+	TEST_ASSERT(main_steal >= MIN_RUN_DELAY_NS,
+		    "Expected steal time >= %ld, got %"PRIu64,
+		    MIN_RUN_DELAY_NS, main_steal);
+
+	pthread_create(&thread, NULL, vcpu_thread, vcpu);
+	pthread_join(thread, NULL);
+
+	TEST_ASSERT(thread_steal >= main_steal &&
+		    thread_steal - main_steal < ST_SANE_DELTA_NS,
+		    "Expected sane steal after vCPU pid change: "
+		    "old=%"PRIu64", new=%"PRIu64,
+		    main_steal, thread_steal);
+
+	ksft_test_result_pass("steal time remains sane across vCPU pid change\n");
+
+	pthread_attr_destroy(&attr);
+	kvm_vm_free(vm);
+	ksft_finished();
+}
-- 
2.43.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/4] KVM: selftests: Add arm64 coverage for steal time pid changes
  2026-08-16  5:33 [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64) Dongli Zhang
                   ` (2 preceding siblings ...)
  2026-08-16  5:33 ` [PATCH 3/4] KVM: selftests: Test steal time across vCPU pid changes on x86 Dongli Zhang
@ 2026-08-16  5:33 ` Dongli Zhang
  2026-08-17  8:15 ` [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64) Marc Zyngier
  4 siblings, 0 replies; 7+ messages in thread
From: Dongli Zhang @ 2026-08-16  5:33 UTC (permalink / raw)
  To: kvm, kvmarm, linux-kselftest
  Cc: seanjc, pbonzini, maz, oupton, fuad.tabba, joey.gouly, seiden,
	suzuki.poulose, yuzenghui, dwmw2, joe.jin

The previous patch added the common steal_time_change_pid test with x86
support. Add the arm64 support so the same test also covers arm64.

Use KVM_ARM_VCPU_PVTIME_IPA to enable the steal time shared page from
userspace, and use the PV_TIME_ST SMCCC call in the guest to retrieve and
read that page.

Assisted-by: Codex:GPT-5.5
Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |  1 +
 .../selftests/kvm/steal_time_change_pid.c     | 54 +++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index c8ce17851561..b01a3403d602 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -199,6 +199,7 @@ TEST_GEN_PROGS_arm64 += guest_memfd_test
 TEST_GEN_PROGS_arm64 += mmu_stress_test
 TEST_GEN_PROGS_arm64 += rseq_test
 TEST_GEN_PROGS_arm64 += steal_time
+TEST_GEN_PROGS_arm64 += steal_time_change_pid
 
 TEST_GEN_PROGS_s390 = $(TEST_GEN_PROGS_COMMON)
 TEST_GEN_PROGS_s390 += s390/memop
diff --git a/tools/testing/selftests/kvm/steal_time_change_pid.c b/tools/testing/selftests/kvm/steal_time_change_pid.c
index 3c39594db398..12d4927d1c01 100644
--- a/tools/testing/selftests/kvm/steal_time_change_pid.c
+++ b/tools/testing/selftests/kvm/steal_time_change_pid.c
@@ -46,6 +46,60 @@ static void steal_time_enable(struct kvm_vcpu *vcpu)
 		     (ulong)st_gva | KVM_MSR_ENABLED);
 }
 
+#elif defined(__aarch64__)
+
+#define STEAL_TIME_SIZE	((sizeof(struct st_time) + 63) & ~63)
+
+#define PV_TIME_ST	0xc5000021
+
+struct st_time {
+	u32 rev;
+	u32 attr;
+	u64 st_time;
+};
+
+static void guest_code(void)
+{
+	struct arm_smccc_res res;
+	struct st_time *st;
+
+	do_smccc(PV_TIME_ST, 0, 0, 0, 0, 0, 0, 0, &res);
+	GUEST_ASSERT_NE(res.a0, -1);
+	GUEST_ASSERT_EQ(res.a0, (ulong)st_gva);
+
+	st = (struct st_time *)res.a0;
+	WRITE_ONCE(guest_stolen_time, READ_ONCE(st->st_time));
+	GUEST_SYNC(0);
+
+	WRITE_ONCE(guest_stolen_time, READ_ONCE(st->st_time));
+	GUEST_SYNC(1);
+
+	WRITE_ONCE(guest_stolen_time, READ_ONCE(st->st_time));
+	GUEST_DONE();
+}
+
+static bool steal_time_supported(struct kvm_vcpu *vcpu)
+{
+	struct kvm_device_attr dev = {
+		.group = KVM_ARM_VCPU_PVTIME_CTRL,
+		.attr = KVM_ARM_VCPU_PVTIME_IPA,
+	};
+
+	return !__vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev);
+}
+
+static void steal_time_enable(struct kvm_vcpu *vcpu)
+{
+	u64 st_ipa = (ulong)st_gva;
+	struct kvm_device_attr dev = {
+		.group = KVM_ARM_VCPU_PVTIME_CTRL,
+		.attr = KVM_ARM_VCPU_PVTIME_IPA,
+		.addr = (u64)&st_ipa,
+	};
+
+	vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev);
+}
+
 #else
 #error "steal_time_change_pid is not implemented on this architecture"
 #endif
-- 
2.43.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64)
  2026-08-16  5:33 [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64) Dongli Zhang
                   ` (3 preceding siblings ...)
  2026-08-16  5:33 ` [PATCH 4/4] KVM: selftests: Add arm64 coverage for steal time pid changes Dongli Zhang
@ 2026-08-17  8:15 ` Marc Zyngier
  4 siblings, 0 replies; 7+ messages in thread
From: Marc Zyngier @ 2026-08-17  8:15 UTC (permalink / raw)
  To: Dongli Zhang
  Cc: kvm, kvmarm, linux-kselftest, seanjc, pbonzini, oupton,
	fuad.tabba, joey.gouly, seiden, suzuki.poulose, yuzenghui, dwmw2,
	joe.jin

On Sun, 16 Aug 2026 06:33:01 +0100,
Dongli Zhang <dongli.zhang@oracle.com> wrote:

[...]

> 4. Guest kernel changes are not included. I may send it separately to keep
> this series limited to the KVM hypervisor.

Hold on. Do you mean you are changing the guest visible behaviour of a
PV interface? That's an ABI. It *cannot* change unilaterally.

> 
> [PATCH 1/5] x86/kvm: Reset prev_steal_time and prev_steal_time_rq when enabling steal time
> https://lore.kernel.org/all/20260505003044.78693-2-dongli.zhang@oracle.com
> 
> 5. There is one remaining corner case: this series resets last_steal when
> the vCPU run PID changes, but not when steal time is enabled. If additional
> host run_delay is accumulated after the PID changes but before the guest
> enables steal time, that delta could be unexpectedly accounted to guest
> vCPU steal time. In practice, this should not happen for Linux guests.

Why is Linux immune to this? Also, KVM does not cater for Linux guests
only.

	M.

-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/4] KVM: arm64: Reset last_steal on vCPU pid change
  2026-08-16  5:33 ` [PATCH 2/4] KVM: arm64: " Dongli Zhang
@ 2026-08-17  8:42   ` Marc Zyngier
  0 siblings, 0 replies; 7+ messages in thread
From: Marc Zyngier @ 2026-08-17  8:42 UTC (permalink / raw)
  To: Dongli Zhang
  Cc: kvm, kvmarm, linux-kselftest, seanjc, pbonzini, oupton,
	fuad.tabba, joey.gouly, seiden, suzuki.poulose, yuzenghui, dwmw2,
	joe.jin

On Sun, 16 Aug 2026 06:33:03 +0100,
Dongli Zhang <dongli.zhang@oracle.com> wrote:
> 
> The previous commit resets x86 steal time accounting when the vCPU PID is
> changed. Do the same for arm64.

Drop this statement, it really doesn't provide any information.

> 
> KVM keeps a vCPU fd alive when userspace hot-unplugs a vCPU. If the fd is
> later reused from a new vCPU thread, vcpu->arch.steal.last_steal still
> reflects the old task's run_delay, while current->sched_info.run_delay
> belongs to the new task.
> 
> Reset vcpu->arch.steal.last_steal from kvm_arch_vcpu_run_pid_change()
> unconditionally so the next stolen time update computes its delta against
> the new task's run_delay.
> 
> Assisted-by: Codex:GPT-5.5
> Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
> ---
>  arch/arm64/include/asm/kvm_host.h | 1 +
>  arch/arm64/kvm/arm.c              | 2 ++
>  arch/arm64/kvm/pvtime.c           | 5 +++++
>  3 files changed, 8 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index bae2c4f92ef5..4607f956e787 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -1339,6 +1339,7 @@ static inline bool kvm_arch_pmi_in_guest(struct kvm_vcpu *vcpu)
>  long kvm_hypercall_pv_features(struct kvm_vcpu *vcpu);
>  gpa_t kvm_init_stolen_time(struct kvm_vcpu *vcpu);
>  void kvm_update_stolen_time(struct kvm_vcpu *vcpu);
> +void kvm_reset_stolen_time(struct kvm_vcpu *vcpu);
>  
>  bool kvm_arm_pvtime_supported(void);
>  int kvm_arm_pvtime_set_attr(struct kvm_vcpu *vcpu,
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 9a6c72a18672..0f6e63eace21 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -929,6 +929,8 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
>  	if (!kvm_arm_vcpu_is_finalized(vcpu))
>  		return -EPERM;
>  
> +	kvm_reset_stolen_time(vcpu);
> +
>  	if (likely(vcpu_has_run_once(vcpu)))
>  		return 0;
>  
> diff --git a/arch/arm64/kvm/pvtime.c b/arch/arm64/kvm/pvtime.c
> index 4ceabaa4c30b..000bf49cc0fd 100644
> --- a/arch/arm64/kvm/pvtime.c
> +++ b/arch/arm64/kvm/pvtime.c
> @@ -32,6 +32,11 @@ void kvm_update_stolen_time(struct kvm_vcpu *vcpu)
>  	srcu_read_unlock(&kvm->srcu, idx);
>  }
>  
> +void kvm_reset_stolen_time(struct kvm_vcpu *vcpu)
> +{
> +	vcpu->arch.steal.last_steal = current->sched_info.run_delay;
> +}
> +
>  long kvm_hypercall_pv_features(struct kvm_vcpu *vcpu)
>  {
>  	u32 feature = smccc_get_arg1(vcpu);

Why isn't this common code? I really don't see the point in making
this arch-specific code. I'd expect something like this (untested):

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ace5801a592f..3fb77360af01 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -950,6 +950,8 @@ struct kvm_vcpu_arch {
 	pid_t pid;
 };
 
+#define kvm_arch_vcpu_last_steal(v)	(v)->arch.steal.last_steal
+
 /*
  * Each 'flag' is composed of a comma-separated triplet:
  *
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 45e784462ec6..117aeb49231a 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4459,6 +4459,9 @@ static long kvm_vcpu_ioctl(struct file *filp,
 			if (r)
 				break;
 
+			if (IS_ENABLED(CONFIG_HAVE_PV_STEAL_CLOCK_GEN))
+				kvm_arch_vcpu_last_steal(vcpu) = current->sched_info.run_delay;
+
 			newpid = get_task_pid(current, PIDTYPE_PID);
 			write_lock(&vcpu->pid_lock);
 			vcpu->pid = newpid;

where each architecture that implements steal time provides an
accessor, and the core code is in charge of the adjustment.

It also makes sure that we don't leave any architecture behind.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-08-17  8:42 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-16  5:33 [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64) Dongli Zhang
2026-08-16  5:33 ` [PATCH 1/4] KVM: x86: Reset last_steal on vCPU pid change Dongli Zhang
2026-08-16  5:33 ` [PATCH 2/4] KVM: arm64: " Dongli Zhang
2026-08-17  8:42   ` Marc Zyngier
2026-08-16  5:33 ` [PATCH 3/4] KVM: selftests: Test steal time across vCPU pid changes on x86 Dongli Zhang
2026-08-16  5:33 ` [PATCH 4/4] KVM: selftests: Add arm64 coverage for steal time pid changes Dongli Zhang
2026-08-17  8:15 ` [PATCH 0/4] KVM: Reset steal time accounting on vCPU pid change (x86 and arm64) Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox