summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2026-06-12 10:12:22 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2026-06-12 10:12:22 +0200
commitb02a4f8c4284e2cbbf539a95b27647687adae816 (patch)
treebc1e6af554ddcb65ef9ed15c21f65a5989267fc5
parent96124f964c23e79ca6532ac280a2594cad833b07 (diff)
parent5bd0387e3b56f7e0a81386f6d0a5fa2c3a92ad5d (diff)
downloadlinux-next-b02a4f8c4284e2cbbf539a95b27647687adae816.tar.gz
linux-next-b02a4f8c4284e2cbbf539a95b27647687adae816.zip
Merge tag 'kvm-x86-selftests-7.2' of https://github.com/kvm-x86/linux into HEAD
KVM selftests changes for 7.2 - Randomize the dirty log test's delay when reaping the bitmap on the first pass, as always waiting only 1ms hid a KVM RISC-V bug as the test reaped the bitmap before KVM could build up enough state to hit the bug. - A pile of one-off fixes and cleanups.
-rw-r--r--tools/testing/selftests/kvm/dirty_log_test.c26
-rw-r--r--tools/testing/selftests/kvm/include/kvm_syscalls.h6
-rw-r--r--tools/testing/selftests/kvm/include/kvm_util.h2
-rw-r--r--tools/testing/selftests/kvm/lib/kvm_util.c25
-rw-r--r--tools/testing/selftests/kvm/memslot_perf_test.c12
-rw-r--r--tools/testing/selftests/kvm/x86/hyperv_features.c21
-rw-r--r--tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c15
-rw-r--r--tools/testing/selftests/kvm/x86/sync_regs_test.c1
8 files changed, 63 insertions, 45 deletions
diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c
index 12446a4b6e8d..74ca096bf976 100644
--- a/tools/testing/selftests/kvm/dirty_log_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_test.c
@@ -694,7 +694,17 @@ static void run_test(enum vm_guest_mode mode, void *arg)
pthread_create(&vcpu_thread, NULL, vcpu_worker, vcpu);
for (iteration = 1; iteration <= p->iterations; iteration++) {
- unsigned long i;
+ unsigned long i, reap_i;
+
+ /*
+ * Select a random point in the time interval to reap the dirty
+ * bitmap/ring while the guest is running, i.e. randomize how
+ * long the guest gets to initially run and thus how many pages
+ * it can dirty, before collecting the dirty bitmap/ring. See
+ * the loop below for details.
+ */
+ reap_i = random() % p->interval;
+ printf("Reaping after a %lu ms delay\n", reap_i);
sync_global_to_guest(vm, iteration);
@@ -729,13 +739,17 @@ static void run_test(enum vm_guest_mode mode, void *arg)
* that's effectively blocked. Collecting while the
* guest is running also verifies KVM doesn't lose any
* state.
- *
+ */
+ if (i < reap_i)
+ continue;
+
+ /*
* For bitmap modes, KVM overwrites the entire bitmap,
* i.e. collecting the bitmaps is destructive. Collect
- * the bitmap only on the first pass, otherwise this
- * test would lose track of dirty pages.
+ * the bitmap while the guest is running only once,
+ * otherwise this test would lose track of dirty pages.
*/
- if (i && host_log_mode != LOG_MODE_DIRTY_RING)
+ if (i > reap_i && host_log_mode != LOG_MODE_DIRTY_RING)
continue;
/*
@@ -745,7 +759,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
* the ring on every pass would make it unlikely the
* vCPU would ever fill the fing).
*/
- if (i && !READ_ONCE(dirty_ring_vcpu_ring_full))
+ if (i > reap_i && !READ_ONCE(dirty_ring_vcpu_ring_full))
continue;
log_mode_collect_dirty_pages(vcpu, TEST_MEM_SLOT_INDEX,
diff --git a/tools/testing/selftests/kvm/include/kvm_syscalls.h b/tools/testing/selftests/kvm/include/kvm_syscalls.h
index 067a4c9cf452..6cb3bed29b81 100644
--- a/tools/testing/selftests/kvm/include/kvm_syscalls.h
+++ b/tools/testing/selftests/kvm/include/kvm_syscalls.h
@@ -89,4 +89,10 @@ __KVM_SYSCALL_DEFINE(fallocate, 4, int, fd, int, mode, loff_t, offset, loff_t, l
__KVM_SYSCALL_DEFINE(ftruncate, 2, unsigned int, fd, off_t, length);
__KVM_SYSCALL_DEFINE(madvise, 3, void *, addr, size_t, length, int, advice);
+#define kvm_free_fd(fd) \
+do { \
+ kvm_close(fd); \
+ (fd) = -1; \
+} while (0)
+
#endif /* SELFTEST_KVM_SYSCALLS_H */
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 2ecaaa0e9965..04a910164a29 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -876,7 +876,7 @@ static inline int vcpu_get_stats_fd(struct kvm_vcpu *vcpu)
{
int fd = __vcpu_ioctl(vcpu, KVM_GET_STATS_FD, NULL);
- TEST_ASSERT_VM_VCPU_IOCTL(fd >= 0, KVM_CHECK_EXTENSION, fd, vcpu->vm);
+ TEST_ASSERT_VM_VCPU_IOCTL(fd >= 0, KVM_GET_STATS_FD, fd, vcpu->vm);
return fd;
}
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index e08967ef7b7b..195f3fdae1e3 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -77,7 +77,8 @@ static ssize_t get_module_param(const char *module_name, const char *param,
int fd, r;
/* Verify KVM is loaded, to provide a more helpful SKIP message. */
- close(open_kvm_dev_path_or_exit());
+ fd = open_kvm_dev_path_or_exit();
+ kvm_free_fd(fd);
r = snprintf(path, path_size, "/sys/module/%s/parameters/%s",
module_name, param);
@@ -90,8 +91,7 @@ static ssize_t get_module_param(const char *module_name, const char *param,
TEST_ASSERT(bytes_read > 0, "read(%s) returned %ld, wanted %ld bytes",
path, bytes_read, buffer_size);
- r = close(fd);
- TEST_ASSERT(!r, "close(%s) failed", path);
+ kvm_free_fd(fd);
return bytes_read;
}
@@ -160,7 +160,7 @@ unsigned int kvm_check_cap(long cap)
ret = __kvm_ioctl(kvm_fd, KVM_CHECK_EXTENSION, (void *)cap);
TEST_ASSERT(ret >= 0, KVM_IOCTL_ERROR(KVM_CHECK_EXTENSION, ret));
- close(kvm_fd);
+ kvm_free_fd(kvm_fd);
return (unsigned int)ret;
}
@@ -747,8 +747,7 @@ static void kvm_stats_release(struct kvm_binary_stats *stats)
stats->desc = NULL;
}
- kvm_close(stats->fd);
- stats->fd = -1;
+ kvm_free_fd(stats->fd);
}
__weak void vcpu_arch_free(struct kvm_vcpu *vcpu)
@@ -777,7 +776,7 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
kvm_munmap(vcpu->run, vcpu_mmap_sz());
- kvm_close(vcpu->fd);
+ kvm_free_fd(vcpu->fd);
kvm_stats_release(&vcpu->stats);
list_del(&vcpu->list);
@@ -793,8 +792,8 @@ void kvm_vm_release(struct kvm_vm *vmp)
list_for_each_entry_safe(vcpu, tmp, &vmp->vcpus, list)
vm_vcpu_rm(vmp, vcpu);
- kvm_close(vmp->fd);
- kvm_close(vmp->kvm_fd);
+ kvm_free_fd(vmp->fd);
+ kvm_free_fd(vmp->kvm_fd);
/* Free cached stats metadata and close FD */
kvm_stats_release(&vmp->stats);
@@ -815,10 +814,10 @@ static void __vm_mem_region_delete(struct kvm_vm *vm,
if (region->fd >= 0) {
/* There's an extra map when using shared memory. */
kvm_munmap(region->mmap_alias, region->mmap_size);
- close(region->fd);
+ kvm_free_fd(region->fd);
}
- if (region->region.guest_memfd >= 0)
- close(region->region.guest_memfd);
+ if ((int)region->region.guest_memfd >= 0)
+ kvm_free_fd(region->region.guest_memfd);
free(region);
}
@@ -1311,7 +1310,7 @@ static size_t vcpu_mmap_sz(void)
TEST_ASSERT(ret >= 0 && ret >= sizeof(struct kvm_run),
KVM_IOCTL_ERROR(KVM_GET_VCPU_MMAP_SIZE, ret));
- close(dev_fd);
+ kvm_free_fd(dev_fd);
return ret;
}
diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c
index e977e979470f..4d9ad6104a6e 100644
--- a/tools/testing/selftests/kvm/memslot_perf_test.c
+++ b/tools/testing/selftests/kvm/memslot_perf_test.c
@@ -111,6 +111,7 @@ struct sync_area {
*/
static_assert(ATOMIC_BOOL_LOCK_FREE == 2, "atomic bool is not lockless");
+static int wait_timeout = 10;
static sem_t vcpu_ready;
static bool map_unmap_verify;
@@ -418,7 +419,7 @@ static bool _guest_should_exit(void)
*/
static noinline void host_perform_sync(struct sync_area *sync)
{
- alarm(10);
+ alarm(wait_timeout);
atomic_store_explicit(&sync->sync_flag, true, memory_order_release);
while (atomic_load_explicit(&sync->sync_flag, memory_order_acquire))
@@ -900,7 +901,7 @@ static void help(char *name, struct test_args *targs)
{
int ctr;
- pr_info("usage: %s [-h] [-v] [-d] [-s slots] [-f first_test] [-e last_test] [-l test_length] [-r run_count]\n",
+ pr_info("usage: %s [-h] [-v] [-d] [-s slots] [-f first_test] [-e last_test] [-l test_length] [-r run_count] [-t wait_timeout]\n",
name);
pr_info(" -h: print this help screen.\n");
pr_info(" -v: enable verbose mode (not for benchmarking).\n");
@@ -916,6 +917,8 @@ static void help(char *name, struct test_args *targs)
targs->seconds);
pr_info(" -r: specify the number of runs per test (currently: %i)\n",
targs->runs);
+ pr_info(" -t: specify the number of seconds for host wait timeout (currently: %i)\n",
+ wait_timeout);
pr_info("\nAvailable tests:\n");
for (ctr = 0; ctr < NTESTS; ctr++)
@@ -964,7 +967,7 @@ static bool parse_args(int argc, char *argv[],
u32 max_mem_slots;
int opt;
- while ((opt = getopt(argc, argv, "hvdqs:f:e:l:r:")) != -1) {
+ while ((opt = getopt(argc, argv, "hvdqs:f:e:l:r:t:")) != -1) {
switch (opt) {
case 'h':
default:
@@ -1007,6 +1010,9 @@ static bool parse_args(int argc, char *argv[],
case 'r':
targs->runs = atoi_positive("Runs per test", optarg);
break;
+ case 't':
+ wait_timeout = atoi_positive("Host wait timeout", optarg);
+ break;
}
}
diff --git a/tools/testing/selftests/kvm/x86/hyperv_features.c b/tools/testing/selftests/kvm/x86/hyperv_features.c
index 7347f1fe5157..2effde85c4c8 100644
--- a/tools/testing/selftests/kvm/x86/hyperv_features.c
+++ b/tools/testing/selftests/kvm/x86/hyperv_features.c
@@ -26,6 +26,7 @@ struct msr_data {
bool fault_expected;
bool write;
u64 write_val;
+ bool reset_expected;
};
struct hcall_data {
@@ -267,14 +268,9 @@ static void guest_test_msrs_access(void)
case 16:
msr->idx = HV_X64_MSR_RESET;
msr->write = true;
- /*
- * TODO: the test only writes '0' to HV_X64_MSR_RESET
- * at the moment, writing some other value there will
- * trigger real vCPU reset and the code is not prepared
- * to handle it yet.
- */
- msr->write_val = 0;
+ msr->write_val = 1;
msr->fault_expected = false;
+ msr->reset_expected = true;
break;
case 17:
@@ -457,7 +453,7 @@ static void guest_test_msrs_access(void)
msr->fault_expected = true;
break;
case 45:
- /* MSR is vailable when CPUID feature bit is set */
+ /* MSR is available when CPUID feature bit is set */
if (!has_invtsc)
goto next_stage;
vcpu_set_cpuid_feature(vcpu, HV_ACCESS_TSC_INVARIANT);
@@ -497,6 +493,15 @@ static void guest_test_msrs_access(void)
msr->idx, msr->write ? "write" : "read");
vcpu_run(vcpu);
+
+ if (msr->reset_expected) {
+ TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_SYSTEM_EVENT);
+ TEST_ASSERT(vcpu->run->system_event.type == KVM_SYSTEM_EVENT_RESET,
+ "Expected reset system event, got type %u",
+ vcpu->run->system_event.type);
+ goto next_stage;
+ }
+
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
switch (get_ucall(vcpu, &uc)) {
diff --git a/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c b/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c
index 15ee8b7bfc11..b4be9a175379 100644
--- a/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c
+++ b/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c
@@ -142,17 +142,6 @@ static void swap_two_test_pages(gpa_t pte_gva1, gpa_t pte_gva2)
}
/*
- * TODO: replace the silly NOP loop with a proper udelay() implementation.
- */
-static inline void do_delay(void)
-{
- int i;
-
- for (i = 0; i < 1000000; i++)
- asm volatile("nop");
-}
-
-/*
* Prepare to test: 'disable' workers by setting the expectation to '0',
* clear hypercall input page and then swap two test pages.
*/
@@ -169,7 +158,7 @@ static inline void prepare_to_test(struct test_data *data)
wmb();
/* Make sure workers have enough time to notice */
- do_delay();
+ udelay(100);
/* Swap test page mappings */
swap_two_test_pages(data->test_pages_pte[0], data->test_pages_pte[1]);
@@ -189,7 +178,7 @@ static inline void post_test(struct test_data *data, u64 exp1, u64 exp2)
set_expected_val((void *)data->test_pages, exp2, WORKER_VCPU_ID_2);
/* Make sure workers have enough time to test */
- do_delay();
+ udelay(100);
}
#define TESTVAL1 0x0101010101010101
diff --git a/tools/testing/selftests/kvm/x86/sync_regs_test.c b/tools/testing/selftests/kvm/x86/sync_regs_test.c
index e0c52321f87c..5b0c2359bbb4 100644
--- a/tools/testing/selftests/kvm/x86/sync_regs_test.c
+++ b/tools/testing/selftests/kvm/x86/sync_regs_test.c
@@ -255,7 +255,6 @@ KVM_ONE_VCPU_TEST(sync_regs_test, req_and_verify_all_valid, guest_code)
struct kvm_regs regs;
/* Request and verify all valid register sets. */
- /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */
run->kvm_valid_regs = TEST_SYNC_FIELDS;
vcpu_run(vcpu);
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);