Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: Dongli Zhang <dongli.zhang@oracle.com>
To: kvm@vger.kernel.org, kvmarm@lists.linux.dev,
	loongarch@lists.linux.dev, kvm-riscv@lists.infradead.org,
	linux-kselftest@vger.kernel.org
Cc: maz@kernel.org, oupton@kernel.org, fuad.tabba@linux.dev,
	joey.gouly@arm.com, seiden@linux.ibm.com, suzuki.poulose@arm.com,
	yuzenghui@huawei.com, zhaotianrui@loongson.cn,
	maobibo@loongson.cn, chenhuacai@kernel.org, anup@brainfault.org,
	atish.patra@linux.dev, seanjc@google.com, pbonzini@redhat.com,
	shuah@kernel.org, dwmw2@infradead.org, joe.jin@oracle.com
Subject: [PATCH v2 3/4] KVM: selftests: Test steal time across vCPU pid changes on x86
Date: Fri,  4 Sep 2026 17:55:25 +0000	[thread overview]
Message-ID: <20260904175550.430266-4-dongli.zhang@oracle.com> (raw)
In-Reply-To: <20260904175550.430266-1-dongli.zhang@oracle.com>

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->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>
---
As I have access to only x86 and arm64 KVM hosts, I created and validated
the selftest on those two architectures only.

 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 96bab7002d39..036c28849f84 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -164,6 +164,7 @@ TEST_GEN_PROGS_x86 += irq_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.7


  parent reply	other threads:[~2026-09-04 17:56 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-04 17:55 [PATCH v2 0/4] KVM: Reset steal time accounting on vCPU pid change Dongli Zhang
2026-09-04 17:55 ` [PATCH v2 1/4] KVM: Move last_steal to common struct kvm_vcpu Dongli Zhang
2026-09-04 18:07   ` sashiko-bot
2026-09-04 20:22     ` Dongli Zhang
2026-09-04 17:55 ` [PATCH v2 2/4] KVM: Reset last_steal on vCPU pid change Dongli Zhang
2026-09-04 17:55 ` Dongli Zhang [this message]
2026-09-04 18:11   ` [PATCH v2 3/4] KVM: selftests: Test steal time across vCPU pid changes on x86 sashiko-bot
2026-09-04 20:27     ` Dongli Zhang
2026-09-04 17:55 ` [PATCH v2 4/4] KVM: selftests: Add arm64 coverage for steal time pid changes Dongli Zhang

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=20260904175550.430266-4-dongli.zhang@oracle.com \
    --to=dongli.zhang@oracle.com \
    --cc=anup@brainfault.org \
    --cc=atish.patra@linux.dev \
    --cc=chenhuacai@kernel.org \
    --cc=dwmw2@infradead.org \
    --cc=fuad.tabba@linux.dev \
    --cc=joe.jin@oracle.com \
    --cc=joey.gouly@arm.com \
    --cc=kvm-riscv@lists.infradead.org \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=loongarch@lists.linux.dev \
    --cc=maobibo@loongson.cn \
    --cc=maz@kernel.org \
    --cc=oupton@kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    --cc=seiden@linux.ibm.com \
    --cc=shuah@kernel.org \
    --cc=suzuki.poulose@arm.com \
    --cc=yuzenghui@huawei.com \
    --cc=zhaotianrui@loongson.cn \
    /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