All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts
@ 2026-06-04  2:01 Josh Hilke
  2026-06-04  2:01 ` [PATCH v5 01/21] KVM: selftests: Build and link selftests/vfio/lib into KVM selftests Josh Hilke
                   ` (21 more replies)
  0 siblings, 22 replies; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

This is v5 of a series which introduces tools/testing/selftests/kvm/irq_test.c
in KVM selftests. This test exercises the delivery of interrupts (both
emulated via eventfd and real from a VFIO device) to guest vCPUs. Beyond basic
injection, the series adds coverage for several complex scenarios, including:
- Dynamic updates to KVM's GSI routing table while interrupts are active.
- Waking up halted vCPUs via interrupts.
- Stressing interrupt delivery during random host IRQ affinity changes.
- Stressing interrupt delivery during random vCPU thread migration across
  physical CPUs.
- Testing non-postable interrupt remapping (using NMIs to force transitions).
- Supporting both xAPIC and x2APIC modes in the guest.

The series also links the VFIO selftests library into KVM selftests to enable
testing of VFIO-KVM interactions.

The test can optionally use a PCI device bound to vfio-pci to test physical
device interrupts. If using a device, it can be invoked by passing the BDF to
the VFIO selftests setup script, and then running the test with the device BDF
passed via the -d option:
$ ./tools/testing/selftests/vfio/scripts/setup.sh 0000:6a:01.0
$ tools/testing/selftests/kvm/irq_test -d 0000:6a:01.0

This test only supports x86. Testing physical device interrupts (-d argument)
requires a device with a supported VFIO selftest driver. Currently supported
devices include:
- Intel DSA (Data Streaming Accelerator), 8086:0b25
- Intel IOAT (I/O Acceleration Technology), 8086:2021

The test can be run with following command-line arguments allow for broad
coverage of the interrupt delivery path:
-a: Random IRQ Affinity. Randomly affinitizes the device IRQ to different host
    CPUs to verify stable delivery during interrupt steering changes.
-b: Block vCPUs. Causes vCPUs to HLT instead of spinning, verifying that
    Posted-interrupt wakeup (PIW) correctly kicks blocked vCPUs.
-c: Clear GSI Routes. Periodically destroys/recreates KVM's GSI routing table to
    verify handling of dynamic IRQ updates.
-d: Device MSI Triggers. Uses the physical device to trigger MSIs instead of
    eventfd emulation (requires a supported device driver).
-i: IRQ Count. Sets the number of interrupts to generate (default 1000).
-m: vCPU Migration. Migrates vCPUs to random physical CPUs to verify that
    posted interrupts follow the vCPU across host cores.
-n: NMI Delivery. Routes interrupts as NMIs into the guest to verify the
    VFIO-NMI delivery path.
-v: vCPU Count. Distributes interrupts across multiple vCPUs via round-robin
    routing.
-x: xAPIC Mode. Forces legacy xAPIC mode to verify compatibility.

---
Changelog

v4 -> v5
- Rename get_proc_vfio_irq_number() to vfio_msix_to_host_irq()
- Rename open_proc_irq_affinity() and write_proc_irq_affinity() to include "_smp_affinity_list"
- Print /proc/irq/<irq>/smp_affinity and effective_affinity on timeout failures
- Convert IRQ type from 'int' to 'unsigned int' across helpers and the test
- Fix compiler warnings for uninitialized variables in irq_test.c
- Remove rate-limiting on affinity changes

v4: https://lore.kernel.org/kvm/20260530002134.558837-1-jrhilke@google.com/

David Matlack (13):
  KVM: selftests: Build and link selftests/vfio/lib into KVM selftests
  KVM: selftests: Add guest read/write macros
  KVM: selftests: Add IRQ injection test
  KVM: selftests: Add helper to get host IRQ from device MSIX for IRQ
    bypass test
  KVM: selftests: Verify IRQ bypass works in IRQ test
  KVM: selftests: Verify interrupts are received when IRQ affinity
    changes in IRQ test
  KVM: selftests: Verify IRQs wake up halted vCPUs in IRQ test
  KVM: selftests: Verify interrupts are received after modifying IRQ
    routes in IRQ test
  KVM: selftests: Make number of IRQs configurable in IRQ test
  KVM: selftests: Verify non-postable IRQ remapping in IRQ test
  KVM: selftests: Verify vCPU migration during IRQ delivery in IRQ test
  KVM: selftests: Make number of vCPUs configurable in IRQ test
  KVM: selftests: Add xAPIC support in IRQ test

Josh Hilke (8):
  KVM: selftests: Rename guest_rng to kvm_rng
  KVM: selftests: Add helper to generate random u64 in range [min,max]
  KVM: selftests: Add helpers to write proc IRQ affinity for IRQ test
  KVM: selftests: Add helpers to print proc IRQ affinity for IRQ test
  KVM: selftests: Add kvm_gettid() wrapper and convert users
  KVM: selftests: Add kvm_sched_getaffinity() wrapper and convert users
  KVM: selftests: Add pin_task_to_random_cpu() helper function for IRQ
    test
  KVM: selftests: Print vCPU affinity on timeout during IRQ test

 tools/testing/selftests/kvm/Makefile.kvm      |   8 +-
 tools/testing/selftests/kvm/arch_timer.c      |   2 +-
 .../kvm/arm64/arch_timer_edge_cases.c         |   2 +-
 .../selftests/kvm/demand_paging_test.c        |   2 +-
 .../selftests/kvm/dirty_log_perf_test.c       |   4 +-
 tools/testing/selftests/kvm/dirty_log_test.c  |  11 +-
 .../selftests/kvm/include/kvm_syscalls.h      |   7 +
 .../testing/selftests/kvm/include/kvm_util.h  |  13 +
 .../testing/selftests/kvm/include/proc_util.h |  15 +
 .../testing/selftests/kvm/include/test_util.h |  25 +-
 .../selftests/kvm/include/x86/kvm_util_arch.h |   4 +-
 tools/testing/selftests/kvm/irq_test.c        | 380 ++++++++++++++++++
 tools/testing/selftests/kvm/lib/assert.c      |   8 +-
 tools/testing/selftests/kvm/lib/kvm_util.c    |  95 ++++-
 tools/testing/selftests/kvm/lib/memstress.c   |   8 +-
 tools/testing/selftests/kvm/lib/proc_util.c   |  90 +++++
 tools/testing/selftests/kvm/lib/test_util.c   |  27 +-
 tools/testing/selftests/kvm/mmu_stress_test.c |  15 +-
 tools/testing/selftests/kvm/rseq_test.c       |   6 +-
 tools/testing/selftests/kvm/steal_time.c      |  22 +-
 20 files changed, 662 insertions(+), 82 deletions(-)
 create mode 100644 tools/testing/selftests/kvm/include/proc_util.h
 create mode 100644 tools/testing/selftests/kvm/irq_test.c
 create mode 100644 tools/testing/selftests/kvm/lib/proc_util.c

-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 01/21] KVM: selftests: Build and link selftests/vfio/lib into KVM selftests
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:01 ` [PATCH v5 02/21] KVM: selftests: Add guest read/write macros Josh Hilke
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Include libvfio.mk into the KVM selftests Makefile and link it into all
KVM selftests by adding it to LIBKVM_OBJS.

This lays the groundwork for future changes to utilize VFIO devices to
verify IRQ bypass in KVM selftests.

Note that KVM selftests build their own copy of selftests/vfio/lib and
the resulting object files are placed in $(OUTPUT)/lib. This allows the
KVM and VFIO selftests to apply different CFLAGS when building without
conflicting with each other.

Signed-off-by: David Matlack <dmatlack@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 9118a5a51b89..2da11e1f3d9a 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -254,6 +254,7 @@ OVERRIDE_TARGETS = 1
 # which causes the environment variable to override the makefile).
 include ../lib.mk
 include ../cgroup/lib/libcgroup.mk
+include ../vfio/lib/libvfio.mk
 
 INSTALL_HDR_PATH = $(top_srcdir)/usr
 LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/
@@ -308,7 +309,9 @@ LIBKVM_S := $(filter %.S,$(LIBKVM))
 LIBKVM_C_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_C))
 LIBKVM_S_OBJ := $(patsubst %.S, $(OUTPUT)/%.o, $(LIBKVM_S))
 LIBKVM_STRING_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_STRING))
-LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ) $(LIBCGROUP_O)
+LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ)
+LIBKVM_OBJS += $(LIBCGROUP_O)
+LIBKVM_OBJS += $(LIBVFIO_O)
 SPLIT_TEST_GEN_PROGS := $(patsubst %, $(OUTPUT)/%, $(SPLIT_TESTS))
 SPLIT_TEST_GEN_OBJ := $(patsubst %, $(OUTPUT)/$(ARCH)/%.o, $(SPLIT_TESTS))
 
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 02/21] KVM: selftests: Add guest read/write macros
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
  2026-06-04  2:01 ` [PATCH v5 01/21] KVM: selftests: Build and link selftests/vfio/lib into KVM selftests Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:01 ` [PATCH v5 03/21] KVM: selftests: Rename guest_rng to kvm_rng Josh Hilke
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Add SYNC_FROM_GUEST_AND_READ(vm, variable), to read a variable value
from the guest. Add WRITE_AND_SYNC_TO_GUEST(vm, variable, value) to
write a value to a guest variable. These macros improve the readability
of code which reads and writes data between host and guest in tests.

Also update existing guest reads/writes to use these macros in the
following tests:
- tools/testing/selftests/kvm/dirty_log_test.c
- tools/testing/selftests/kvm/mmu_stress_test.c
- tools/testing/selftests/kvm/steal_time.c

No functional changes are intended.

Suggested-by: Sean Christopherson <seanjc@google.com>
Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/dirty_log_test.c  |  9 +++-----
 .../testing/selftests/kvm/include/kvm_util.h  | 10 +++++++++
 tools/testing/selftests/kvm/mmu_stress_test.c |  9 +++-----
 tools/testing/selftests/kvm/steal_time.c      | 22 +++++++------------
 4 files changed, 24 insertions(+), 26 deletions(-)

diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c
index 12446a4b6e8d..561b80064230 100644
--- a/tools/testing/selftests/kvm/dirty_log_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_test.c
@@ -698,8 +698,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
 
 		sync_global_to_guest(vm, iteration);
 
-		WRITE_ONCE(nr_writes, 0);
-		sync_global_to_guest(vm, nr_writes);
+		WRITE_AND_SYNC_TO_GUEST(vm, nr_writes, 0);
 
 		dirty_ring_prev_iteration_last_page = dirty_ring_last_page;
 		WRITE_ONCE(dirty_ring_vcpu_ring_full, false);
@@ -761,16 +760,14 @@ static void run_test(enum vm_guest_mode mode, void *arg)
 		 * writing memory during verification, pages that this thread
 		 * sees as clean may be written with this iteration's value.
 		 */
-		WRITE_ONCE(vcpu_stop, true);
-		sync_global_to_guest(vm, vcpu_stop);
+		WRITE_AND_SYNC_TO_GUEST(vm, vcpu_stop, true);
 		sem_wait(&sem_vcpu_stop);
 
 		/*
 		 * Clear vcpu_stop after the vCPU thread has acknowledge the
 		 * stop request and is waiting, i.e. is definitely not running!
 		 */
-		WRITE_ONCE(vcpu_stop, false);
-		sync_global_to_guest(vm, vcpu_stop);
+		WRITE_AND_SYNC_TO_GUEST(vm, vcpu_stop, false);
 
 		/*
 		 * Sync the number of writes performed before verification, the
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 2ecaaa0e9965..88211d696a11 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1138,6 +1138,16 @@ vm_adjust_num_guest_pages(enum vm_guest_mode mode, unsigned int num_guest_pages)
 	memcpy(&(g), _p, sizeof(g));				\
 })
 
+#define SYNC_FROM_GUEST_AND_READ(_vm, _variable) ({		\
+	sync_global_from_guest(_vm, _variable);			\
+	READ_ONCE(_variable);					\
+})
+
+#define WRITE_AND_SYNC_TO_GUEST(_vm, _variable, _value) do {	\
+	WRITE_ONCE(_variable, _value);				\
+	sync_global_to_guest(_vm, _variable);			\
+} while (0)
+
 /*
  * Write a global value, but only in the VM's (guest's) domain.  Primarily used
  * for "globals" that hold per-VM values (VMs always duplicate code and global
diff --git a/tools/testing/selftests/kvm/mmu_stress_test.c b/tools/testing/selftests/kvm/mmu_stress_test.c
index 54d281419d31..473ef4c0ea9f 100644
--- a/tools/testing/selftests/kvm/mmu_stress_test.c
+++ b/tools/testing/selftests/kvm/mmu_stress_test.c
@@ -155,10 +155,8 @@ static void *vcpu_worker(void *data)
 		    "Expected EFAULT on write to RO memory, got r = %d, errno = %d", r, errno);
 
 	atomic_inc(&nr_ro_faults);
-	if (atomic_read(&nr_ro_faults) == nr_vcpus) {
-		WRITE_ONCE(all_vcpus_hit_ro_fault, true);
-		sync_global_to_guest(vm, all_vcpus_hit_ro_fault);
-	}
+	if (atomic_read(&nr_ro_faults) == nr_vcpus)
+		WRITE_AND_SYNC_TO_GUEST(vm, all_vcpus_hit_ro_fault, true);
 
 #if defined(__x86_64__) || defined(__aarch64__)
 	/*
@@ -383,8 +381,7 @@ int main(int argc, char *argv[])
 	rendezvous_with_vcpus(&time_run2, "run 2");
 
 	mprotect(mem, slot_size, PROT_READ);
-	mprotect_ro_done = true;
-	sync_global_to_guest(vm, mprotect_ro_done);
+	WRITE_AND_SYNC_TO_GUEST(vm, mprotect_ro_done, true);
 
 	rendezvous_with_vcpus(&time_ro, "mprotect RO");
 	mprotect(mem, slot_size, PROT_READ | PROT_WRITE);
diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c
index 76fcdd1fd3cb..2de87549fcc0 100644
--- a/tools/testing/selftests/kvm/steal_time.c
+++ b/tools/testing/selftests/kvm/steal_time.c
@@ -70,8 +70,8 @@ static bool is_steal_time_supported(struct kvm_vcpu *vcpu)
 static void steal_time_init(struct kvm_vcpu *vcpu, u32 i)
 {
 	/* ST_GPA_BASE is identity mapped */
-	st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
-	sync_global_to_guest(vcpu->vm, st_gva[i]);
+	WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gva[i],
+				(void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE));
 
 	vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_MSR_ENABLED);
 }
@@ -187,8 +187,7 @@ static void steal_time_init(struct kvm_vcpu *vcpu, u32 i)
 	};
 
 	/* ST_GPA_BASE is identity mapped */
-	st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
-	sync_global_to_guest(vm, st_gva[i]);
+	WRITE_AND_SYNC_TO_GUEST(vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE));
 
 	st_ipa = (ulong)st_gva[i];
 	vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev);
@@ -310,10 +309,8 @@ static bool is_steal_time_supported(struct kvm_vcpu *vcpu)
 static void steal_time_init(struct kvm_vcpu *vcpu, u32 i)
 {
 	/* ST_GPA_BASE is identity mapped */
-	st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
-	st_gpa[i] = addr_gva2gpa(vcpu->vm, (gva_t)st_gva[i]);
-	sync_global_to_guest(vcpu->vm, st_gva[i]);
-	sync_global_to_guest(vcpu->vm, st_gpa[i]);
+	WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE));
+	WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gpa[i], addr_gva2gpa(vcpu->vm, (gva_t)st_gva[i]));
 }
 
 static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx)
@@ -442,8 +439,7 @@ static void steal_time_init(struct kvm_vcpu *vcpu, u32 i)
 	};
 
 	/* ST_GPA_BASE is identity mapped */
-	st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
-	sync_global_to_guest(vm, st_gva[i]);
+	WRITE_AND_SYNC_TO_GUEST(vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE));
 
 	err = __vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &attr);
 	TEST_ASSERT(err == 0, "No PV stealtime Feature");
@@ -549,8 +545,7 @@ int main(int ac, char **av)
 
 		/* Second VCPU run, expect guest stolen time to be <= run_delay */
 		run_vcpu(vcpus[i]);
-		sync_global_from_guest(vm, guest_stolen_time[i]);
-		stolen_time = guest_stolen_time[i];
+		stolen_time = SYNC_FROM_GUEST_AND_READ(vm, guest_stolen_time[i]);
 		run_delay = get_run_delay();
 		TEST_ASSERT(stolen_time <= run_delay,
 			    "Expected stolen time <= %ld, got %ld",
@@ -570,8 +565,7 @@ int main(int ac, char **av)
 
 		/* Run VCPU again to confirm stolen time is consistent with run_delay */
 		run_vcpu(vcpus[i]);
-		sync_global_from_guest(vm, guest_stolen_time[i]);
-		stolen_time = guest_stolen_time[i] - stolen_time;
+		stolen_time = SYNC_FROM_GUEST_AND_READ(vm, guest_stolen_time[i]) - stolen_time;
 		TEST_ASSERT(stolen_time >= run_delay,
 			    "Expected stolen time >= %ld, got %ld",
 			    run_delay, stolen_time);
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 03/21] KVM: selftests: Rename guest_rng to kvm_rng
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
  2026-06-04  2:01 ` [PATCH v5 01/21] KVM: selftests: Build and link selftests/vfio/lib into KVM selftests Josh Hilke
  2026-06-04  2:01 ` [PATCH v5 02/21] KVM: selftests: Add guest read/write macros Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:01 ` [PATCH v5 04/21] KVM: selftests: Add helper to generate random u64 in range [min,max] Josh Hilke
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

Rename functions prefixed with 'guest_random_' to 'kvm_random_' and the
global random state variable 'guest_rng' to 'kvm_rng'. This expands
their usage and reflects that the random number generator can be used by
both the host and the guest.

No functional changes are intended.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
---
 .../selftests/kvm/dirty_log_perf_test.c       |  4 ++--
 tools/testing/selftests/kvm/dirty_log_test.c  |  2 +-
 .../testing/selftests/kvm/include/test_util.h | 22 +++++++++----------
 .../selftests/kvm/include/x86/kvm_util_arch.h |  4 ++--
 tools/testing/selftests/kvm/lib/kvm_util.c    | 20 ++++++++---------
 tools/testing/selftests/kvm/lib/memstress.c   |  8 +++----
 tools/testing/selftests/kvm/lib/test_util.c   |  6 ++---
 7 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c
index ef779fa91827..7c5abe1ae9e0 100644
--- a/tools/testing/selftests/kvm/dirty_log_perf_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c
@@ -311,7 +311,7 @@ int main(int argc, char *argv[])
 	int opt;
 
 	/* Override the seed to be deterministic by default. */
-	guest_random_seed = 1;
+	kvm_random_seed = 1;
 
 	dirty_log_manual_caps =
 		kvm_check_cap(KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
@@ -357,7 +357,7 @@ int main(int argc, char *argv[])
 			p.phys_offset = strtoull(optarg, NULL, 0);
 			break;
 		case 'r':
-			guest_random_seed = atoi_positive("Random seed", optarg);
+			kvm_random_seed = atoi_positive("Random seed", optarg);
 			break;
 		case 's':
 			p.backing_src = parse_backing_src_type(optarg);
diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c
index 561b80064230..95d5f27a4093 100644
--- a/tools/testing/selftests/kvm/dirty_log_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_test.c
@@ -121,7 +121,7 @@ static void guest_code(void)
 	while (true) {
 		while (!READ_ONCE(vcpu_stop)) {
 			addr = guest_test_virt_mem;
-			addr += (guest_random_u64(&guest_rng) % guest_num_pages)
+			addr += (kvm_random_u64(&kvm_rng) % guest_num_pages)
 				* guest_page_size;
 			addr = align_down(addr, host_page_size);
 
diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h
index a56271c237ae..44c0104d60ac 100644
--- a/tools/testing/selftests/kvm/include/test_util.h
+++ b/tools/testing/selftests/kvm/include/test_util.h
@@ -108,30 +108,30 @@ struct timespec timespec_sub(struct timespec ts1, struct timespec ts2);
 struct timespec timespec_elapsed(struct timespec start);
 struct timespec timespec_div(struct timespec ts, int divisor);
 
-struct guest_random_state {
+struct kvm_random_state {
 	u32 seed;
 };
 
-extern u32 guest_random_seed;
-extern struct guest_random_state guest_rng;
+extern u32 kvm_random_seed;
+extern struct kvm_random_state kvm_rng;
 
-struct guest_random_state new_guest_random_state(u32 seed);
-u32 guest_random_u32(struct guest_random_state *state);
+struct kvm_random_state new_kvm_random_state(u32 seed);
+u32 kvm_random_u32(struct kvm_random_state *state);
 
-static inline bool __guest_random_bool(struct guest_random_state *state,
+static inline bool __kvm_random_bool(struct kvm_random_state *state,
 				       u8 percent)
 {
-	return (guest_random_u32(state) % 100) < percent;
+	return (kvm_random_u32(state) % 100) < percent;
 }
 
-static inline bool guest_random_bool(struct guest_random_state *state)
+static inline bool kvm_random_bool(struct kvm_random_state *state)
 {
-	return __guest_random_bool(state, 50);
+	return __kvm_random_bool(state, 50);
 }
 
-static inline u64 guest_random_u64(struct guest_random_state *state)
+static inline u64 kvm_random_u64(struct kvm_random_state *state)
 {
-	return ((u64)guest_random_u32(state) << 32) | guest_random_u32(state);
+	return ((u64)kvm_random_u32(state) << 32) | kvm_random_u32(state);
 }
 
 enum vm_mem_backing_src_type {
diff --git a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
index c33ab6e04171..6904dbda79f9 100644
--- a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
@@ -55,9 +55,9 @@ static inline bool __vm_arch_has_protected_memory(struct kvm_vm_arch *arch)
 do {											\
 	const typeof(mem) val = (__val);						\
 											\
-	if (!is_forced_emulation_enabled || guest_random_bool(&guest_rng)) {		\
+	if (!is_forced_emulation_enabled || kvm_random_bool(&kvm_rng)) {		\
 		(mem) = val;								\
-	} else if (guest_random_bool(&guest_rng)) {					\
+	} else if (kvm_random_bool(&kvm_rng)) {					\
 		__asm__ __volatile__(KVM_FEP "mov %1, %0"				\
 				     : "+m" (mem)					\
 				     : "r" (val) : "memory");				\
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index e08967ef7b7b..2d24d8db86b1 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -20,9 +20,9 @@
 
 #define KVM_UTIL_MIN_PFN	2
 
-u32 guest_random_seed;
-struct guest_random_state guest_rng;
-static u32 last_guest_seed;
+u32 kvm_random_seed;
+struct kvm_random_state kvm_rng;
+static u32 last_kvm_seed;
 
 static size_t vcpu_mmap_sz(void);
 
@@ -515,12 +515,12 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus,
 	slot0 = memslot2region(vm, 0);
 	ucall_init(vm, slot0->region.guest_phys_addr + slot0->region.memory_size);
 
-	if (guest_random_seed != last_guest_seed) {
-		pr_info("Random seed: 0x%x\n", guest_random_seed);
-		last_guest_seed = guest_random_seed;
+	if (kvm_random_seed != last_kvm_seed) {
+		pr_info("Random seed: 0x%x\n", kvm_random_seed);
+		last_kvm_seed = kvm_random_seed;
 	}
-	guest_rng = new_guest_random_state(guest_random_seed);
-	sync_global_to_guest(vm, guest_rng);
+	kvm_rng = new_kvm_random_state(kvm_random_seed);
+	sync_global_to_guest(vm, kvm_rng);
 
 	kvm_arch_vm_post_create(vm, nr_runnable_vcpus);
 
@@ -2280,8 +2280,8 @@ void __attribute((constructor)) kvm_selftest_init(void)
 	sigaction(SIGILL, &sig_sa, NULL);
 	sigaction(SIGFPE, &sig_sa, NULL);
 
-	guest_random_seed = last_guest_seed = random();
-	pr_info("Random seed: 0x%x\n", guest_random_seed);
+	kvm_random_seed = last_kvm_seed = random();
+	pr_info("Random seed: 0x%x\n", kvm_random_seed);
 
 	kvm_selftest_arch_init();
 }
diff --git a/tools/testing/selftests/kvm/lib/memstress.c b/tools/testing/selftests/kvm/lib/memstress.c
index 6dcd15910a06..3599b75d97c9 100644
--- a/tools/testing/selftests/kvm/lib/memstress.c
+++ b/tools/testing/selftests/kvm/lib/memstress.c
@@ -48,14 +48,14 @@ void memstress_guest_code(u32 vcpu_idx)
 {
 	struct memstress_args *args = &memstress_args;
 	struct memstress_vcpu_args *vcpu_args = &args->vcpu_args[vcpu_idx];
-	struct guest_random_state rand_state;
+	struct kvm_random_state rand_state;
 	gva_t gva;
 	u64 pages;
 	u64 addr;
 	u64 page;
 	int i;
 
-	rand_state = new_guest_random_state(guest_random_seed + vcpu_idx);
+	rand_state = new_kvm_random_state(kvm_random_seed + vcpu_idx);
 
 	gva = vcpu_args->gva;
 	pages = vcpu_args->pages;
@@ -69,13 +69,13 @@ void memstress_guest_code(u32 vcpu_idx)
 
 		for (i = 0; i < pages; i++) {
 			if (args->random_access)
-				page = guest_random_u32(&rand_state) % pages;
+				page = kvm_random_u32(&rand_state) % pages;
 			else
 				page = i;
 
 			addr = gva + (page * args->guest_page_size);
 
-			if (__guest_random_bool(&rand_state, args->write_percent))
+			if (__kvm_random_bool(&rand_state, args->write_percent))
 				*(u64 *)addr = 0x0123456789ABCDEF;
 			else
 				READ_ONCE(*(u64 *)addr);
diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c
index bab1bd2b775b..e98ca7ef439c 100644
--- a/tools/testing/selftests/kvm/lib/test_util.c
+++ b/tools/testing/selftests/kvm/lib/test_util.c
@@ -30,13 +30,13 @@ void __attribute__((used)) expect_sigbus_handler(int signum)
  * Park-Miller LCG using standard constants.
  */
 
-struct guest_random_state new_guest_random_state(u32 seed)
+struct kvm_random_state new_kvm_random_state(u32 seed)
 {
-	struct guest_random_state s = {.seed = seed};
+	struct kvm_random_state s = {.seed = seed};
 	return s;
 }
 
-u32 guest_random_u32(struct guest_random_state *state)
+u32 kvm_random_u32(struct kvm_random_state *state)
 {
 	state->seed = (u64)state->seed * 48271 % ((u32)(1 << 31) - 1);
 	return state->seed;
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 04/21] KVM: selftests: Add helper to generate random u64 in range [min,max]
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (2 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 03/21] KVM: selftests: Rename guest_rng to kvm_rng Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:12   ` sashiko-bot
  2026-06-04  2:01 ` [PATCH v5 05/21] KVM: selftests: Add IRQ injection test Josh Hilke
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

Introduce kvm_random_u64_in_range(state, min, max). This function
returns a random u64 in the inclusive range of [min, max] using a struct
kvm_random_state.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
---
 .../testing/selftests/kvm/include/test_util.h  |  3 +++
 tools/testing/selftests/kvm/lib/test_util.c    | 18 ++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h
index 44c0104d60ac..d64c8a228207 100644
--- a/tools/testing/selftests/kvm/include/test_util.h
+++ b/tools/testing/selftests/kvm/include/test_util.h
@@ -134,6 +134,9 @@ static inline u64 kvm_random_u64(struct kvm_random_state *state)
 	return ((u64)kvm_random_u32(state) << 32) | kvm_random_u32(state);
 }
 
+u64 kvm_random_u64_in_range(struct kvm_random_state *state, u64 min,
+			    u64 max);
+
 enum vm_mem_backing_src_type {
 	VM_MEM_SRC_ANONYMOUS,
 	VM_MEM_SRC_ANONYMOUS_THP,
diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c
index e98ca7ef439c..e208a57f190c 100644
--- a/tools/testing/selftests/kvm/lib/test_util.c
+++ b/tools/testing/selftests/kvm/lib/test_util.c
@@ -42,6 +42,24 @@ u32 kvm_random_u32(struct kvm_random_state *state)
 	return state->seed;
 }
 
+/* Returns a random u64 in the inclusive range [min, max] */
+u64 kvm_random_u64_in_range(struct kvm_random_state *state, u64 min,
+			    u64 max)
+{
+	u64 value;
+	u64 range;
+
+	TEST_ASSERT(min <= max, "PEBKAC, min = 0x%lx, max = 0x%lx", min, max);
+
+	value = kvm_random_u64(state);
+
+	range = max - min;
+	if (range == ULLONG_MAX)
+		return value;
+
+	return min + (value % (range + 1));
+}
+
 /*
  * Parses "[0-9]+[kmgt]?".
  */
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 05/21] KVM: selftests: Add IRQ injection test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (3 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 04/21] KVM: selftests: Add helper to generate random u64 in range [min,max] Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04 16:19   ` Sean Christopherson
  2026-06-04  2:01 ` [PATCH v5 06/21] KVM: selftests: Add helper to get host IRQ from device MSIX for IRQ bypass test Josh Hilke
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Add a new test, irq_test.c, which verifies that KVM correctly injects
interrupts into a running guest when triggered via an eventfd bound to a
GSI using the irqfd mechanism.

This test is intentionally simple. Support for IRQ bypass, receiving
interrupts from real devices, and other features will be added to this
test in future changes.

Suggested-by: Sean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/kvm/20250404193923.1413163-68-seanjc@google.com/
Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm |   2 +
 tools/testing/selftests/kvm/irq_test.c   | 174 +++++++++++++++++++++++
 2 files changed, 176 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/irq_test.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 2da11e1f3d9a..b859098121c7 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -153,12 +153,14 @@ TEST_GEN_PROGS_x86 += coalesced_io_test
 TEST_GEN_PROGS_x86 += dirty_log_perf_test
 TEST_GEN_PROGS_x86 += guest_memfd_test
 TEST_GEN_PROGS_x86 += hardware_disable_test
+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 += system_counter_offset_test
 TEST_GEN_PROGS_x86 += pre_fault_memory_test
 
+
 # Compiled outputs used by test targets
 TEST_GEN_PROGS_EXTENDED_x86 += x86/nx_huge_pages_test
 
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
new file mode 100644
index 000000000000..d3fee51cf451
--- /dev/null
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "kvm_util.h"
+#include "test_util.h"
+#include "apic.h"
+#include "processor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+
+static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
+static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
+static bool guest_received_irq[KVM_MAX_VCPUS];
+static bool done;
+
+#define GUEST_RECEIVED_IRQ(__vcpu)	\
+	SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_irq[(__vcpu)->id])
+
+static u32 guest_get_vcpu_id(void)
+{
+	return x2apic_read_reg(APIC_ID);
+}
+
+static void guest_irq_handler(struct ex_regs *regs)
+{
+	WRITE_ONCE(guest_received_irq[guest_get_vcpu_id()], true);
+
+	x2apic_write_reg(APIC_EOI, 0);
+}
+
+static void guest_code(void)
+{
+	x2apic_enable();
+
+	sti_nop();
+
+	WRITE_ONCE(guest_ready_for_irqs[guest_get_vcpu_id()], true);
+
+	while (!READ_ONCE(done))
+		cpu_relax();
+
+	GUEST_DONE();
+}
+
+static void *vcpu_thread_main(void *arg)
+{
+	struct kvm_vcpu *vcpu = arg;
+	struct ucall uc;
+
+	vcpu_run(vcpu);
+	TEST_ASSERT_EQ(UCALL_DONE, get_ucall(vcpu, &uc));
+
+	return NULL;
+}
+
+static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
+			  u8 vector)
+{
+	struct {
+		struct kvm_irq_routing head;
+		struct kvm_irq_routing_entry entry;
+	} routing_data = {};
+
+	struct kvm_irq_routing *routes = &routing_data.head;
+
+	routes->nr = 1;
+	routes->entries[0].gsi = gsi;
+	routes->entries[0].type = KVM_IRQ_ROUTING_MSI;
+	routes->entries[0].u.msi.address_lo = 0xFEE00000 | (vcpu->id << 12);
+	routes->entries[0].u.msi.data = vector;
+
+	vm_ioctl(vm, KVM_SET_GSI_ROUTING, routes);
+}
+
+static void help(const char *name)
+{
+	printf("Usage: %s [-h]\n", name);
+	printf("\n");
+	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
+	printf("\n");
+	exit(KSFT_FAIL);
+}
+
+int main(int argc, char **argv)
+{
+	/*
+	 * Pick a random vector and a random GSI to use for device IRQ.
+	 *
+	 * Pick an IRQ vector in range [32, UINT8_MAX]. Min value is 32 because
+	 * Linux/x86 reserves vectors 0-31 for exceptions and architecture
+	 * defined NMIs and interrupts.
+	 *
+	 * Pick a GSI in range [24, KVM_MAX_IRQ_ROUTES - 1]. The min value is 24
+	 * because KVM reserves GSIs 0-15 for legacy ISA IRQs and 16-23 only go
+	 * to the IOAPIC. The max is KVM_MAX_IRQ_ROUTES - 1, because
+	 * KVM_MAX_IRQ_ROUTES is exclusive.
+	 */
+	u32 gsi = kvm_random_u64_in_range(&kvm_rng, 24, KVM_MAX_IRQ_ROUTES - 1);
+	u8 vector = kvm_random_u64_in_range(&kvm_rng, 32, UINT8_MAX);
+
+	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+	pthread_t vcpu_threads[KVM_MAX_VCPUS];
+	int nr_irqs = 1000, nr_vcpus = 1;
+	int i, j, c, eventfd;
+	struct kvm_vm *vm;
+
+	while ((c = getopt(argc, argv, "h")) != -1) {
+		switch (c) {
+		case 'h':
+		default:
+			help(argv[0]);
+		}
+	}
+
+	TEST_REQUIRE(kvm_arch_has_default_irqchip());
+
+	vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
+	vm_install_exception_handler(vm, vector, guest_irq_handler);
+
+	eventfd = kvm_new_eventfd();
+
+	printf("Injecting interrupts for GSI %d (Vector 0x%x) %d times\n",
+	       gsi, vector, nr_irqs);
+
+	kvm_assign_irqfd(vm, gsi, eventfd);
+
+	for (i = 0; i < nr_vcpus; i++)
+		pthread_create(&vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);
+
+	for (i = 0; i < nr_vcpus; i++) {
+		struct kvm_vcpu *vcpu = vcpus[i];
+
+		while (!SYNC_FROM_GUEST_AND_READ(vm, guest_ready_for_irqs[vcpu->id]))
+			continue;
+	}
+
+	for (i = 0; i < nr_irqs; i++) {
+		struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
+		struct timespec start;
+
+		kvm_route_msi(vm, gsi, vcpu, vector);
+
+		for (j = 0; j < nr_vcpus; j++)
+			TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
+				    "IRQ flag for vCPU %d not clear prior to test",
+				    vcpus[j]->id);
+
+		/* Trigger interrupt */
+		eventfd_write(eventfd, 1);
+
+		clock_gettime(CLOCK_MONOTONIC, &start);
+		for (;;) {
+			if (GUEST_RECEIVED_IRQ(vcpu))
+				break;
+
+			if (timespec_to_ns(timespec_elapsed(start)) > timeout_ns)
+				TEST_FAIL("vCPU %d timed out waiting for IRQ from GSI %d (Vector 0x%x) !\n",
+					  vcpu->id, gsi, vector);
+		}
+
+		WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
+	}
+
+	WRITE_AND_SYNC_TO_GUEST(vm, done, true);
+
+	for (i = 0; i < nr_vcpus; i++)
+		pthread_join(vcpu_threads[i], NULL);
+
+	printf("Test passed!\n");
+
+	return 0;
+}
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 06/21] KVM: selftests: Add helper to get host IRQ from device MSIX for IRQ bypass test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (4 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 05/21] KVM: selftests: Add IRQ injection test Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:09   ` sashiko-bot
  2026-06-04  2:01 ` [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test Josh Hilke
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Introduce proc_util.c and proc_util.h to house utility functions for
interacting with the proc filesystem.

Add vfio_msix_to_host_irq(), which parses
/proc/interrupts to map a VFIO device BDF and MSI-X vector to its
corresponding host IRQ number.

This helper will be used in a subsequent patch for debugging when
implementing support for IRQ bypass in the KVM IRQ test.

Suggested-by: Sean Christopherson <seanjc@google.com>
Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |  1 +
 .../testing/selftests/kvm/include/proc_util.h |  9 +++++
 tools/testing/selftests/kvm/lib/proc_util.c   | 40 +++++++++++++++++++
 3 files changed, 50 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/include/proc_util.h
 create mode 100644 tools/testing/selftests/kvm/lib/proc_util.c

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index b859098121c7..63355b56c42f 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -11,6 +11,7 @@ LIBKVM += lib/kvm_util.c
 LIBKVM += lib/lru_gen_util.c
 LIBKVM += lib/memstress.c
 LIBKVM += lib/guest_sprintf.c
+LIBKVM += lib/proc_util.c
 LIBKVM += lib/rbtree.c
 LIBKVM += lib/sparsebit.c
 LIBKVM += lib/test_util.c
diff --git a/tools/testing/selftests/kvm/include/proc_util.h b/tools/testing/selftests/kvm/include/proc_util.h
new file mode 100644
index 000000000000..704839b6d7af
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/proc_util.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTEST_KVM_PROC_UTIL_H
+#define SELFTEST_KVM_PROC_UTIL_H
+
+#include <stdint.h>
+
+unsigned int vfio_msix_to_host_irq(const char *vfio_device_bdf, int msix);
+
+#endif /* SELFTEST_KVM_PROC_UTIL_H */
diff --git a/tools/testing/selftests/kvm/lib/proc_util.c b/tools/testing/selftests/kvm/lib/proc_util.c
new file mode 100644
index 000000000000..84d30f055a0a
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/proc_util.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "kvm_util.h"
+#include "test_util.h"
+#include "proc_util.h"
+
+static FILE *open_proc_interrupts(void)
+{
+	FILE *fp;
+
+	fp = fopen("/proc/interrupts", "r");
+	TEST_ASSERT(fp, "fopen(/proc/interrupts) failed");
+
+	return fp;
+}
+
+unsigned int vfio_msix_to_host_irq(const char *device_bdf, int msix)
+{
+	char search_string[64];
+	char line[4096];
+	int irq = -1;
+	FILE *fp;
+
+	fp = open_proc_interrupts();
+
+	snprintf(search_string, sizeof(search_string), "vfio-msix[%d]", msix);
+
+	while (fgets(line, sizeof(line), fp)) {
+		if (strstr(line, device_bdf) && strstr(line, search_string)) {
+			TEST_ASSERT_EQ(1, sscanf(line, "%d:", &irq));
+			break;
+		}
+	}
+
+	fclose(fp);
+
+	TEST_ASSERT(irq != -1, "Failed to locate IRQ for %s %s", device_bdf,
+		    search_string);
+	return (unsigned int)irq;
+}
+
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (5 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 06/21] KVM: selftests: Add helper to get host IRQ from device MSIX for IRQ bypass test Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04 16:22   ` Sean Christopherson
  2026-06-04 17:56   ` Sean Christopherson
  2026-06-04  2:01 ` [PATCH v5 08/21] KVM: selftests: Add helpers to write proc IRQ affinity for " Josh Hilke
                   ` (14 subsequent siblings)
  21 siblings, 2 replies; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Trigger interrupts from a VFIO device instead of emulating interrupts
using KVM eventfds. This verifies that guests receive interrupts via IRQ
bypass.

Add a '-d' argument to tools/testing/selftests/kvm/irq_test which
takes the segment:bus:device.function number of a PCI device bound to
VFIO which will trigger interrupts. The device must have a VFIO selftest
driver in order to work with the test.

Example:
$ ./tools/testing/selftests/kvm/irq_test -d 0000:06:0a.1

Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/irq_test.c | 64 +++++++++++++++++++++++---
 1 file changed, 57 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index d3fee51cf451..5b42d8abd1ea 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -1,14 +1,17 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "kvm_util.h"
 #include "test_util.h"
+#include <linux/sizes.h>
 #include "apic.h"
 #include "processor.h"
+#include "proc_util.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <pthread.h>
 #include <sys/eventfd.h>
+#include <libvfio.h>
 
 static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
 static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
@@ -55,6 +58,36 @@ static void *vcpu_thread_main(void *arg)
 	return NULL;
 }
 
+static int vfio_setup_msi(struct vfio_pci_device *device)
+{
+	const int flags = MAP_SHARED | MAP_ANONYMOUS;
+	const int prot = PROT_READ | PROT_WRITE;
+	struct dma_region *region;
+
+	/* A driver is required to generate an MSI. */
+	TEST_REQUIRE(device->driver.ops);
+
+	/* Set up a DMA-able region for the driver to use. */
+	region = &device->driver.region;
+	region->iova = 0;
+	region->size = SZ_2M;
+	region->vaddr = kvm_mmap(region->size, prot, flags, -1);
+	TEST_ASSERT(region->vaddr != MAP_FAILED, "mmap() failed\n");
+	iommu_map(device->iommu, region);
+
+	vfio_pci_driver_init(device);
+	return device->driver.msi;
+}
+
+static void trigger_interrupt(struct vfio_pci_device *device, int eventfd)
+{
+	if (device)
+		vfio_pci_driver_send_msi(device);
+	else
+		eventfd_write(eventfd, 1);
+}
+
+
 static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
 			  u8 vector)
 {
@@ -76,9 +109,10 @@ static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
 
 static void help(const char *name)
 {
-	printf("Usage: %s [-h]\n", name);
+	printf("Usage: %s [-d <segment:bus:device.function>] [-h]\n", name);
 	printf("\n");
 	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
+	printf("-d	Use a VFIO device to send MSI-X interrupts instead of using an emulated eventfd\n");
 	printf("\n");
 	exit(KSFT_FAIL);
 }
@@ -100,14 +134,21 @@ int main(int argc, char **argv)
 	u32 gsi = kvm_random_u64_in_range(&kvm_rng, 24, KVM_MAX_IRQ_ROUTES - 1);
 	u8 vector = kvm_random_u64_in_range(&kvm_rng, 32, UINT8_MAX);
 
-	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
 	pthread_t vcpu_threads[KVM_MAX_VCPUS];
+	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+	struct vfio_pci_device *device = NULL;
 	int nr_irqs = 1000, nr_vcpus = 1;
-	int i, j, c, eventfd;
+	const char *device_bdf = NULL;
+	int i, j, c, msix, eventfd;
+	struct iommu *iommu;
 	struct kvm_vm *vm;
+	unsigned int irq;
 
-	while ((c = getopt(argc, argv, "h")) != -1) {
+	while ((c = getopt(argc, argv, "d:h")) != -1) {
 		switch (c) {
+		case 'd':
+			device_bdf = optarg;
+			break;
 		case 'h':
 		default:
 			help(argv[0]);
@@ -119,7 +160,17 @@ int main(int argc, char **argv)
 	vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
 	vm_install_exception_handler(vm, vector, guest_irq_handler);
 
-	eventfd = kvm_new_eventfd();
+	if (device_bdf) {
+		iommu = iommu_init(default_iommu_mode);
+		device = vfio_pci_device_init(device_bdf, iommu);
+		msix = vfio_setup_msi(device);
+		irq = vfio_msix_to_host_irq(device_bdf, msix);
+		eventfd = device->msi_eventfds[msix];
+		printf("Using device %s MSI-X[%d] (IRQ-%u)\n", device_bdf, msix,
+		       irq);
+	} else {
+		eventfd = kvm_new_eventfd();
+	}
 
 	printf("Injecting interrupts for GSI %d (Vector 0x%x) %d times\n",
 	       gsi, vector, nr_irqs);
@@ -147,8 +198,7 @@ int main(int argc, char **argv)
 				    "IRQ flag for vCPU %d not clear prior to test",
 				    vcpus[j]->id);
 
-		/* Trigger interrupt */
-		eventfd_write(eventfd, 1);
+		trigger_interrupt(device, eventfd);
 
 		clock_gettime(CLOCK_MONOTONIC, &start);
 		for (;;) {
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 08/21] KVM: selftests: Add helpers to write proc IRQ affinity for IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (6 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:09   ` sashiko-bot
  2026-06-04 19:35   ` Sean Christopherson
  2026-06-04  2:01 ` [PATCH v5 09/21] KVM: selftests: Add helpers to print " Josh Hilke
                   ` (13 subsequent siblings)
  21 siblings, 2 replies; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

Introduce utility functions to open and write IRQ affinity settings
via the proc filesystem.

Specifically, add:
- open_proc_irq_smp_affinity_list() to open
  /proc/irq/<irq>/smp_affinity_list for writing.
- write_proc_irq_smp_affinity_list() to write a target CPU to the list.

These will be used a subsequent patch to set IRQ affinity in the KVM IRQ
test.

Signed-off-by: Josh Hilke <jrhilke@google.com>
---
 .../testing/selftests/kvm/include/proc_util.h |  2 ++
 tools/testing/selftests/kvm/lib/proc_util.c   | 20 +++++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/proc_util.h b/tools/testing/selftests/kvm/include/proc_util.h
index 704839b6d7af..e381c7818275 100644
--- a/tools/testing/selftests/kvm/include/proc_util.h
+++ b/tools/testing/selftests/kvm/include/proc_util.h
@@ -6,4 +6,6 @@
 
 unsigned int vfio_msix_to_host_irq(const char *vfio_device_bdf, int msix);
 
+FILE *open_proc_irq_smp_affinity_list(unsigned int irq);
+void write_proc_irq_smp_affinity_list(FILE *fp, unsigned int irq, int irq_cpu);
 #endif /* SELFTEST_KVM_PROC_UTIL_H */
diff --git a/tools/testing/selftests/kvm/lib/proc_util.c b/tools/testing/selftests/kvm/lib/proc_util.c
index 84d30f055a0a..938c90d94f4d 100644
--- a/tools/testing/selftests/kvm/lib/proc_util.c
+++ b/tools/testing/selftests/kvm/lib/proc_util.c
@@ -38,3 +38,23 @@ unsigned int vfio_msix_to_host_irq(const char *device_bdf, int msix)
 	return (unsigned int)irq;
 }
 
+FILE *open_proc_irq_smp_affinity_list(unsigned int irq)
+{
+	char path[PATH_MAX];
+	FILE *fp;
+
+	snprintf(path, sizeof(path), "/proc/irq/%u/smp_affinity_list", irq);
+	fp = fopen(path, "w");
+	TEST_ASSERT(fp, "fopen(%s) failed", path);
+
+	return fp;
+}
+
+void write_proc_irq_smp_affinity_list(FILE *fp, unsigned int irq, int irq_cpu)
+{
+	int ret;
+
+	ret = fprintf(fp, "%d\n", irq_cpu);
+	TEST_ASSERT(ret > 0, "Failed to affinitize IRQ-%u to CPU %d", irq, irq_cpu);
+	fflush(fp);
+}
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 09/21] KVM: selftests: Add helpers to print proc IRQ affinity for IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (7 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 08/21] KVM: selftests: Add helpers to write proc IRQ affinity for " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:09   ` sashiko-bot
  2026-06-04  2:01 ` [PATCH v5 10/21] KVM: selftests: Verify interrupts are received when IRQ affinity changes in " Josh Hilke
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

Introduce utility functions to print IRQ affinity settings (smp_affinity
and effective_affinity) via the proc filesystem.

Specifically, add:
- print_proc_irq_smp_affinity() and print_proc_irq_effective_affinity()
  to print the current affinity states.

These helpers will be used in subsequent patches to print affinity
settings for debugging in the KVM IRQ test when timeouts occur.

Signed-off-by: Josh Hilke <jrhilke@google.com>
---
 .../testing/selftests/kvm/include/proc_util.h |  4 +++
 tools/testing/selftests/kvm/lib/proc_util.c   | 30 +++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/proc_util.h b/tools/testing/selftests/kvm/include/proc_util.h
index e381c7818275..e0e8f29c570c 100644
--- a/tools/testing/selftests/kvm/include/proc_util.h
+++ b/tools/testing/selftests/kvm/include/proc_util.h
@@ -8,4 +8,8 @@ unsigned int vfio_msix_to_host_irq(const char *vfio_device_bdf, int msix);
 
 FILE *open_proc_irq_smp_affinity_list(unsigned int irq);
 void write_proc_irq_smp_affinity_list(FILE *fp, unsigned int irq, int irq_cpu);
+
+void print_proc_irq_smp_affinity(unsigned int irq);
+void print_proc_irq_effective_affinity(unsigned int irq);
+
 #endif /* SELFTEST_KVM_PROC_UTIL_H */
diff --git a/tools/testing/selftests/kvm/lib/proc_util.c b/tools/testing/selftests/kvm/lib/proc_util.c
index 938c90d94f4d..24a8de92e229 100644
--- a/tools/testing/selftests/kvm/lib/proc_util.c
+++ b/tools/testing/selftests/kvm/lib/proc_util.c
@@ -58,3 +58,33 @@ void write_proc_irq_smp_affinity_list(FILE *fp, unsigned int irq, int irq_cpu)
 	TEST_ASSERT(ret > 0, "Failed to affinitize IRQ-%u to CPU %d", irq, irq_cpu);
 	fflush(fp);
 }
+
+static void print_proc_irq_file(unsigned int irq, const char *file)
+{
+	char path[PATH_MAX];
+	char buf[256];
+	FILE *fp;
+
+	snprintf(path, sizeof(path), "/proc/irq/%u/%s", irq, file);
+	fp = fopen(path, "r");
+	if (!fp) {
+		printf("  Failed to open %s\n", path);
+		return;
+	}
+
+	if (fgets(buf, sizeof(buf), fp)) {
+		buf[strcspn(buf, "\n")] = 0;
+		printf("  %s: %s\n", path, buf);
+	}
+	fclose(fp);
+}
+
+void print_proc_irq_smp_affinity(unsigned int irq)
+{
+	print_proc_irq_file(irq, "smp_affinity");
+}
+
+void print_proc_irq_effective_affinity(unsigned int irq)
+{
+	print_proc_irq_file(irq, "effective_affinity");
+}
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 10/21] KVM: selftests: Verify interrupts are received when IRQ affinity changes in IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (8 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 09/21] KVM: selftests: Add helpers to print " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:13   ` sashiko-bot
  2026-06-04  2:01 ` [PATCH v5 11/21] KVM: selftests: Verify IRQs wake up halted vCPUs " Josh Hilke
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Add the '-a' flag to tools/testing/selftests/kvm/irq_test.c to randomly
affinitize the device's host IRQ to different physical CPUs throughout
the test. This stresses the kernel's ability to maintain correct
interrupt routing and delivery even as the underlying hardware IRQ
affinity is changed dynamically via /proc/irq/.

Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/irq_test.c | 41 ++++++++++++++++++++++++--
 1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index 5b42d8abd1ea..90cff165c351 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -11,11 +11,13 @@
 #include <unistd.h>
 #include <pthread.h>
 #include <sys/eventfd.h>
+#include <sys/sysinfo.h>
 #include <libvfio.h>
 
 static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
 static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
 static bool guest_received_irq[KVM_MAX_VCPUS];
+static bool irq_affinity;
 static bool done;
 
 #define GUEST_RECEIVED_IRQ(__vcpu)	\
@@ -109,9 +111,10 @@ static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
 
 static void help(const char *name)
 {
-	printf("Usage: %s [-d <segment:bus:device.function>] [-h]\n", name);
+	printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-h]\n", name);
 	printf("\n");
 	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
+	printf("-a	Randomly affinitize the device's host IRQ to different physical CPUs throughout the test\n");
 	printf("-d	Use a VFIO device to send MSI-X interrupts instead of using an emulated eventfd\n");
 	printf("\n");
 	exit(KSFT_FAIL);
@@ -139,13 +142,18 @@ int main(int argc, char **argv)
 	struct vfio_pci_device *device = NULL;
 	int nr_irqs = 1000, nr_vcpus = 1;
 	const char *device_bdf = NULL;
+	FILE *irq_affinity_fp = NULL;
 	int i, j, c, msix, eventfd;
 	struct iommu *iommu;
 	struct kvm_vm *vm;
 	unsigned int irq;
+	int irq_cpu;
 
-	while ((c = getopt(argc, argv, "d:h")) != -1) {
+	while ((c = getopt(argc, argv, "ad:h")) != -1) {
 		switch (c) {
+		case 'a':
+			irq_affinity = true;
+			break;
 		case 'd':
 			device_bdf = optarg;
 			break;
@@ -168,7 +176,11 @@ int main(int argc, char **argv)
 		eventfd = device->msi_eventfds[msix];
 		printf("Using device %s MSI-X[%d] (IRQ-%u)\n", device_bdf, msix,
 		       irq);
+		if (irq_affinity)
+			irq_affinity_fp = open_proc_irq_smp_affinity_list(irq);
 	} else {
+		TEST_ASSERT(!irq_affinity,
+			    "Setting IRQ affinity (-a) requires a backing device (-d)");
 		eventfd = kvm_new_eventfd();
 	}
 
@@ -187,12 +199,23 @@ int main(int argc, char **argv)
 			continue;
 	}
 
+	/*
+	 * Suppress a false positive maybe-uninitialized compiler warning due
+	 * to conditional changes in IRQ affinity.
+	 */
+	irq_cpu = -1;
+
 	for (i = 0; i < nr_irqs; i++) {
 		struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
 		struct timespec start;
 
 		kvm_route_msi(vm, gsi, vcpu, vector);
 
+		if (irq_affinity_fp) {
+			irq_cpu = kvm_random_u64(&kvm_rng) % get_nprocs();
+			write_proc_irq_smp_affinity_list(irq_affinity_fp, irq, irq_cpu);
+		}
+
 		for (j = 0; j < nr_vcpus; j++)
 			TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
 				    "IRQ flag for vCPU %d not clear prior to test",
@@ -205,9 +228,18 @@ int main(int argc, char **argv)
 			if (GUEST_RECEIVED_IRQ(vcpu))
 				break;
 
-			if (timespec_to_ns(timespec_elapsed(start)) > timeout_ns)
+			if (timespec_to_ns(timespec_elapsed(start)) > timeout_ns) {
+				printf("Timeout waiting for interrupt!\n");
+				printf("  vCPU: %d\n", vcpu->id);
+				if (irq_affinity_fp) {
+					printf("  irq_cpu: %d\n", irq_cpu);
+					print_proc_irq_smp_affinity(irq);
+					print_proc_irq_effective_affinity(irq);
+				}
+
 				TEST_FAIL("vCPU %d timed out waiting for IRQ from GSI %d (Vector 0x%x) !\n",
 					  vcpu->id, gsi, vector);
+			}
 		}
 
 		WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
@@ -218,6 +250,9 @@ int main(int argc, char **argv)
 	for (i = 0; i < nr_vcpus; i++)
 		pthread_join(vcpu_threads[i], NULL);
 
+	if (irq_affinity_fp)
+		fclose(irq_affinity_fp);
+
 	printf("Test passed!\n");
 
 	return 0;
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 11/21] KVM: selftests: Verify IRQs wake up halted vCPUs in IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (9 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 10/21] KVM: selftests: Verify interrupts are received when IRQ affinity changes in " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:15   ` sashiko-bot
  2026-06-04  2:01 ` [PATCH v5 12/21] KVM: selftests: Verify interrupts are received after modifying IRQ routes " Josh Hilke
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Add the '-b' flag to tools/testing/selftests/kvm/irq_test.c to verify
that interrupts successfully wake up vCPUs that are in a halted state.

By default, the guest code spins using cpu_relax() while waiting for
interrupts. With the '-b' flag, the guest executes the HLT instruction
instead. At the end of the test, the host explicitly routes and triggers
a final interrupt for each vCPU. If the interrupt fails to wake the
halted vCPU, the guest will never exit its loop, and the host's call to
pthread_join() will hang, causing the test to time out and fail.

Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/irq_test.c | 32 ++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index 90cff165c351..671338f0e612 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -18,6 +18,7 @@ static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
 static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
 static bool guest_received_irq[KVM_MAX_VCPUS];
 static bool irq_affinity;
+static bool block_vcpus;
 static bool done;
 
 #define GUEST_RECEIVED_IRQ(__vcpu)	\
@@ -43,8 +44,12 @@ static void guest_code(void)
 
 	WRITE_ONCE(guest_ready_for_irqs[guest_get_vcpu_id()], true);
 
-	while (!READ_ONCE(done))
-		cpu_relax();
+	while (!READ_ONCE(done)) {
+		if (block_vcpus)
+			hlt();
+		else
+			cpu_relax();
+	}
 
 	GUEST_DONE();
 }
@@ -111,10 +116,11 @@ static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
 
 static void help(const char *name)
 {
-	printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-h]\n", name);
+	printf("Usage: %s [-a] [-b] [-d <segment:bus:device.function>] [-h]\n", name);
 	printf("\n");
 	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
 	printf("-a	Randomly affinitize the device's host IRQ to different physical CPUs throughout the test\n");
+	printf("-b	Block vCPUs (e.g. HLT) instead of spinning in guest-mode\n");
 	printf("-d	Use a VFIO device to send MSI-X interrupts instead of using an emulated eventfd\n");
 	printf("\n");
 	exit(KSFT_FAIL);
@@ -149,11 +155,14 @@ int main(int argc, char **argv)
 	unsigned int irq;
 	int irq_cpu;
 
-	while ((c = getopt(argc, argv, "ad:h")) != -1) {
+	while ((c = getopt(argc, argv, "abd:h")) != -1) {
 		switch (c) {
 		case 'a':
 			irq_affinity = true;
 			break;
+		case 'b':
+			block_vcpus = true;
+			break;
 		case 'd':
 			device_bdf = optarg;
 			break;
@@ -189,6 +198,8 @@ int main(int argc, char **argv)
 
 	kvm_assign_irqfd(vm, gsi, eventfd);
 
+	sync_global_to_guest(vm, block_vcpus);
+
 	for (i = 0; i < nr_vcpus; i++)
 		pthread_create(&vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);
 
@@ -247,8 +258,19 @@ int main(int argc, char **argv)
 
 	WRITE_AND_SYNC_TO_GUEST(vm, done, true);
 
-	for (i = 0; i < nr_vcpus; i++)
+	for (i = 0; i < nr_vcpus; i++) {
+		/*
+		 * Verify that sending an interrupt to a halted vCPU wakes it
+		 * up. If the vCPU does not wake up, the call to pthread_join(),
+		 * below, will hang.
+		 */
+		if (block_vcpus) {
+			kvm_route_msi(vm, gsi, vcpus[i], vector);
+			trigger_interrupt(device, eventfd);
+		}
+
 		pthread_join(vcpu_threads[i], NULL);
+	}
 
 	if (irq_affinity_fp)
 		fclose(irq_affinity_fp);
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 12/21] KVM: selftests: Verify interrupts are received after modifying IRQ routes in IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (10 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 11/21] KVM: selftests: Verify IRQs wake up halted vCPUs " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04 17:22   ` Sean Christopherson
  2026-06-04  2:01 ` [PATCH v5 13/21] KVM: selftests: Make number of IRQs configurable " Josh Hilke
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Add the '-c' flag to tools/testing/selftests/kvm/irq_test.c to destroy
and recreate KVM's GSI routing table between interrupts. This ensures
that KVM correctly handles dynamic updates to the interrupt routing
table while interrupts are actively being signaled by assigned devices.

Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/irq_test.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index 671338f0e612..b0c4547a7f14 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -114,13 +114,21 @@ static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
 	vm_ioctl(vm, KVM_SET_GSI_ROUTING, routes);
 }
 
+static void kvm_clear_gsi_routes(struct kvm_vm *vm)
+{
+	struct kvm_irq_routing routes = {};
+
+	vm_ioctl(vm, KVM_SET_GSI_ROUTING, &routes);
+}
+
 static void help(const char *name)
 {
-	printf("Usage: %s [-a] [-b] [-d <segment:bus:device.function>] [-h]\n", name);
+	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h]\n", name);
 	printf("\n");
 	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
 	printf("-a	Randomly affinitize the device's host IRQ to different physical CPUs throughout the test\n");
 	printf("-b	Block vCPUs (e.g. HLT) instead of spinning in guest-mode\n");
+	printf("-c	Destroy and recreate KVM's GSI routing table in between some interrupts\n");
 	printf("-d	Use a VFIO device to send MSI-X interrupts instead of using an emulated eventfd\n");
 	printf("\n");
 	exit(KSFT_FAIL);
@@ -150,12 +158,13 @@ int main(int argc, char **argv)
 	const char *device_bdf = NULL;
 	FILE *irq_affinity_fp = NULL;
 	int i, j, c, msix, eventfd;
+	bool clear_routes = false;
 	struct iommu *iommu;
 	struct kvm_vm *vm;
 	unsigned int irq;
 	int irq_cpu;
 
-	while ((c = getopt(argc, argv, "abd:h")) != -1) {
+	while ((c = getopt(argc, argv, "abcd:h")) != -1) {
 		switch (c) {
 		case 'a':
 			irq_affinity = true;
@@ -166,6 +175,9 @@ int main(int argc, char **argv)
 		case 'd':
 			device_bdf = optarg;
 			break;
+		case 'c':
+			clear_routes = true;
+			break;
 		case 'h':
 		default:
 			help(argv[0]);
@@ -217,9 +229,13 @@ int main(int argc, char **argv)
 	irq_cpu = -1;
 
 	for (i = 0; i < nr_irqs; i++) {
+		const bool do_clear_routes = clear_routes && (i & BIT(3));
 		struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
 		struct timespec start;
 
+		if (do_clear_routes)
+			kvm_clear_gsi_routes(vm);
+
 		kvm_route_msi(vm, gsi, vcpu, vector);
 
 		if (irq_affinity_fp) {
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 13/21] KVM: selftests: Make number of IRQs configurable in IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (11 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 12/21] KVM: selftests: Verify interrupts are received after modifying IRQ routes " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04 17:35   ` Sean Christopherson
  2026-06-04  2:01 ` [PATCH v5 14/21] KVM: selftests: Verify non-postable IRQ remapping " Josh Hilke
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Add a '-i' flag to tools/testing/selftests/kvm/irq_test.c to allow users
to specify the number of IRQs generated during a test run.

Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/irq_test.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index b0c4547a7f14..de8c29baa2b0 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -123,13 +123,14 @@ static void kvm_clear_gsi_routes(struct kvm_vm *vm)
 
 static void help(const char *name)
 {
-	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h]\n", name);
+	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h] [-i nr_irqs]\n", name);
 	printf("\n");
 	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
 	printf("-a	Randomly affinitize the device's host IRQ to different physical CPUs throughout the test\n");
 	printf("-b	Block vCPUs (e.g. HLT) instead of spinning in guest-mode\n");
 	printf("-c	Destroy and recreate KVM's GSI routing table in between some interrupts\n");
 	printf("-d	Use a VFIO device to send MSI-X interrupts instead of using an emulated eventfd\n");
+	printf("-i	The number of IRQs to generate during the test\n");
 	printf("\n");
 	exit(KSFT_FAIL);
 }
@@ -164,7 +165,7 @@ int main(int argc, char **argv)
 	unsigned int irq;
 	int irq_cpu;
 
-	while ((c = getopt(argc, argv, "abcd:h")) != -1) {
+	while ((c = getopt(argc, argv, "abcd:hi:")) != -1) {
 		switch (c) {
 		case 'a':
 			irq_affinity = true;
@@ -178,6 +179,9 @@ int main(int argc, char **argv)
 		case 'c':
 			clear_routes = true;
 			break;
+		case 'i':
+			nr_irqs = atoi_positive("Number of IRQs", optarg);
+			break;
 		case 'h':
 		default:
 			help(argv[0]);
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 14/21] KVM: selftests: Verify non-postable IRQ remapping in IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (12 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 13/21] KVM: selftests: Make number of IRQs configurable " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04 17:22   ` Sean Christopherson
  2026-06-04  2:01 ` [PATCH v5 15/21] KVM: selftests: Add kvm_gettid() wrapper and convert users Josh Hilke
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Add the -n flag to tools/testing/selftests/kvm/irq_test.c to route a
portion of device interrupts as NMIs (Non-Maskable Interrupts) into the
guest using an alternating pattern of 4 NMIs followed by 4 regular
interrupts.

While this adds coverage for NMI injection, the primary goal is to
validate KVM's handling of non-postable interrupt delivery.
Specifically, the transitions between posted and remapped modes.  NMIs
are used for this purpose because they are a reliable, architectural way
to force these code paths.

Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/irq_test.c | 44 ++++++++++++++++++++------
 1 file changed, 35 insertions(+), 9 deletions(-)

diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index de8c29baa2b0..ed48562318bf 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -17,12 +17,15 @@
 static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
 static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
 static bool guest_received_irq[KVM_MAX_VCPUS];
+static bool guest_received_nmi[KVM_MAX_VCPUS];
 static bool irq_affinity;
 static bool block_vcpus;
 static bool done;
 
 #define GUEST_RECEIVED_IRQ(__vcpu)	\
 	SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_irq[(__vcpu)->id])
+#define GUEST_RECEIVED_NMI(__vcpu)	\
+	SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_nmi[(__vcpu)->id])
 
 static u32 guest_get_vcpu_id(void)
 {
@@ -36,6 +39,11 @@ static void guest_irq_handler(struct ex_regs *regs)
 	x2apic_write_reg(APIC_EOI, 0);
 }
 
+static void guest_nmi_handler(struct ex_regs *regs)
+{
+	WRITE_ONCE(guest_received_nmi[guest_get_vcpu_id()], true);
+}
+
 static void guest_code(void)
 {
 	x2apic_enable();
@@ -96,7 +104,7 @@ static void trigger_interrupt(struct vfio_pci_device *device, int eventfd)
 
 
 static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
-			  u8 vector)
+			  u8 vector, bool use_nmi)
 {
 	struct {
 		struct kvm_irq_routing head;
@@ -109,7 +117,7 @@ static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
 	routes->entries[0].gsi = gsi;
 	routes->entries[0].type = KVM_IRQ_ROUTING_MSI;
 	routes->entries[0].u.msi.address_lo = 0xFEE00000 | (vcpu->id << 12);
-	routes->entries[0].u.msi.data = vector;
+	routes->entries[0].u.msi.data = use_nmi ? NMI_VECTOR | (4 << 8) : vector;
 
 	vm_ioctl(vm, KVM_SET_GSI_ROUTING, routes);
 }
@@ -123,7 +131,7 @@ static void kvm_clear_gsi_routes(struct kvm_vm *vm)
 
 static void help(const char *name)
 {
-	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h] [-i nr_irqs]\n", name);
+	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h] [-i nr_irqs] [-n]\n", name);
 	printf("\n");
 	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
 	printf("-a	Randomly affinitize the device's host IRQ to different physical CPUs throughout the test\n");
@@ -131,6 +139,7 @@ static void help(const char *name)
 	printf("-c	Destroy and recreate KVM's GSI routing table in between some interrupts\n");
 	printf("-d	Use a VFIO device to send MSI-X interrupts instead of using an emulated eventfd\n");
 	printf("-i	The number of IRQs to generate during the test\n");
+	printf("-n	Deliver 50 percent of IRQs as non-maskable interrupts\n");
 	printf("\n");
 	exit(KSFT_FAIL);
 }
@@ -160,12 +169,13 @@ int main(int argc, char **argv)
 	FILE *irq_affinity_fp = NULL;
 	int i, j, c, msix, eventfd;
 	bool clear_routes = false;
+	bool use_nmi = false;
 	struct iommu *iommu;
 	struct kvm_vm *vm;
 	unsigned int irq;
 	int irq_cpu;
 
-	while ((c = getopt(argc, argv, "abcd:hi:")) != -1) {
+	while ((c = getopt(argc, argv, "abcd:hi:n")) != -1) {
 		switch (c) {
 		case 'a':
 			irq_affinity = true;
@@ -182,6 +192,9 @@ int main(int argc, char **argv)
 		case 'i':
 			nr_irqs = atoi_positive("Number of IRQs", optarg);
 			break;
+		case 'n':
+			use_nmi = true;
+			break;
 		case 'h':
 		default:
 			help(argv[0]);
@@ -192,6 +205,7 @@ int main(int argc, char **argv)
 
 	vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
 	vm_install_exception_handler(vm, vector, guest_irq_handler);
+	vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler);
 
 	if (device_bdf) {
 		iommu = iommu_init(default_iommu_mode);
@@ -234,34 +248,43 @@ int main(int argc, char **argv)
 
 	for (i = 0; i < nr_irqs; i++) {
 		const bool do_clear_routes = clear_routes && (i & BIT(3));
+		const bool do_use_nmi = use_nmi && (i & BIT(2));
 		struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
 		struct timespec start;
 
 		if (do_clear_routes)
 			kvm_clear_gsi_routes(vm);
 
-		kvm_route_msi(vm, gsi, vcpu, vector);
+		kvm_route_msi(vm, gsi, vcpu, vector, do_use_nmi);
 
 		if (irq_affinity_fp) {
 			irq_cpu = kvm_random_u64(&kvm_rng) % get_nprocs();
 			write_proc_irq_smp_affinity_list(irq_affinity_fp, irq, irq_cpu);
 		}
 
-		for (j = 0; j < nr_vcpus; j++)
+		for (j = 0; j < nr_vcpus; j++) {
 			TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
 				    "IRQ flag for vCPU %d not clear prior to test",
 				    vcpus[j]->id);
+			TEST_ASSERT(!GUEST_RECEIVED_NMI(vcpus[j]),
+				    "NMI flag for vCPU %d not clear prior to test",
+				    vcpus[j]->id);
+		}
 
 		trigger_interrupt(device, eventfd);
 
 		clock_gettime(CLOCK_MONOTONIC, &start);
 		for (;;) {
-			if (GUEST_RECEIVED_IRQ(vcpu))
+			if (!do_use_nmi && GUEST_RECEIVED_IRQ(vcpu))
+				break;
+
+			if (do_use_nmi && GUEST_RECEIVED_NMI(vcpu))
 				break;
 
 			if (timespec_to_ns(timespec_elapsed(start)) > timeout_ns) {
 				printf("Timeout waiting for interrupt!\n");
 				printf("  vCPU: %d\n", vcpu->id);
+				printf("  is interrupt NMI: %s\n", do_use_nmi ? "true" : "false");
 				if (irq_affinity_fp) {
 					printf("  irq_cpu: %d\n", irq_cpu);
 					print_proc_irq_smp_affinity(irq);
@@ -273,7 +296,10 @@ int main(int argc, char **argv)
 			}
 		}
 
-		WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
+		if (do_use_nmi)
+			WRITE_AND_SYNC_TO_GUEST(vm, guest_received_nmi[vcpu->id], false);
+		else
+			WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
 	}
 
 	WRITE_AND_SYNC_TO_GUEST(vm, done, true);
@@ -285,7 +311,7 @@ int main(int argc, char **argv)
 		 * below, will hang.
 		 */
 		if (block_vcpus) {
-			kvm_route_msi(vm, gsi, vcpus[i], vector);
+			kvm_route_msi(vm, gsi, vcpus[i], vector, false);
 			trigger_interrupt(device, eventfd);
 		}
 
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 15/21] KVM: selftests: Add kvm_gettid() wrapper and convert users
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (13 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 14/21] KVM: selftests: Verify non-postable IRQ remapping " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:01 ` [PATCH v5 16/21] KVM: selftests: Add kvm_sched_getaffinity() " Josh Hilke
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

Add a KVM wrapper for the gettid() syscall to avoid compilation errors
in versions of Glibc that don't contain gettid(). Convert existing users
of the syscall to use this new wrapper.

This helper will be used in a future change in the KVM IRQ test to
migrate vCPU threads.

No functional changes intended.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
---
 tools/testing/selftests/kvm/demand_paging_test.c   | 2 +-
 tools/testing/selftests/kvm/include/kvm_syscalls.h | 5 +++++
 tools/testing/selftests/kvm/lib/assert.c           | 8 ++------
 tools/testing/selftests/kvm/lib/test_util.c        | 3 ++-
 tools/testing/selftests/kvm/rseq_test.c            | 2 +-
 5 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c
index 302c4923d093..f8b3d0b68830 100644
--- a/tools/testing/selftests/kvm/demand_paging_test.c
+++ b/tools/testing/selftests/kvm/demand_paging_test.c
@@ -57,7 +57,7 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args)
 static int handle_uffd_page_request(int uffd_mode, int uffd,
 		struct uffd_msg *msg)
 {
-	pid_t tid = syscall(__NR_gettid);
+	pid_t tid = kvm_gettid();
 	u64 addr = msg->arg.pagefault.address;
 	struct timespec start;
 	struct timespec ts_diff;
diff --git a/tools/testing/selftests/kvm/include/kvm_syscalls.h b/tools/testing/selftests/kvm/include/kvm_syscalls.h
index 067a4c9cf452..e4731741373e 100644
--- a/tools/testing/selftests/kvm/include/kvm_syscalls.h
+++ b/tools/testing/selftests/kvm/include/kvm_syscalls.h
@@ -83,6 +83,11 @@ static inline int kvm_dup(int fd)
 	return new_fd;
 }
 
+static inline pid_t kvm_gettid(void)
+{
+	return syscall(__NR_gettid);
+}
+
 __KVM_SYSCALL_DEFINE(munmap, 2, void *, mem, size_t, size);
 __KVM_SYSCALL_DEFINE(close, 1, int, fd);
 __KVM_SYSCALL_DEFINE(fallocate, 4, int, fd, int, mode, loff_t, offset, loff_t, len);
diff --git a/tools/testing/selftests/kvm/lib/assert.c b/tools/testing/selftests/kvm/lib/assert.c
index 8be0d09ecf0f..1d72dcdfce3b 100644
--- a/tools/testing/selftests/kvm/lib/assert.c
+++ b/tools/testing/selftests/kvm/lib/assert.c
@@ -10,6 +10,7 @@
 #include <sys/syscall.h>
 
 #include "kselftest.h"
+#include "kvm_syscalls.h"
 
 #ifdef __GLIBC__
 #include <execinfo.h>
@@ -64,11 +65,6 @@ static void test_dump_stack(void)
 static void test_dump_stack(void) {}
 #endif
 
-static pid_t _gettid(void)
-{
-	return syscall(SYS_gettid);
-}
-
 void __attribute__((noinline))
 test_assert(bool exp, const char *exp_str,
 	const char *file, unsigned int line, const char *fmt, ...)
@@ -81,7 +77,7 @@ test_assert(bool exp, const char *exp_str,
 		fprintf(stderr, "==== Test Assertion Failure ====\n"
 			"  %s:%u: %s\n"
 			"  pid=%d tid=%d errno=%d - %s\n",
-			file, line, exp_str, getpid(), _gettid(),
+			file, line, exp_str, getpid(), kvm_gettid(),
 			errno, strerror(errno));
 		test_dump_stack();
 		if (fmt) {
diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c
index e208a57f190c..6b00ab11f3c0 100644
--- a/tools/testing/selftests/kvm/lib/test_util.c
+++ b/tools/testing/selftests/kvm/lib/test_util.c
@@ -17,6 +17,7 @@
 #include "linux/kernel.h"
 
 #include "test_util.h"
+#include "kvm_syscalls.h"
 
 sigjmp_buf expect_sigbus_jmpbuf;
 
@@ -395,7 +396,7 @@ long get_run_delay(void)
 	long val[2];
 	FILE *fp;
 
-	sprintf(path, "/proc/%ld/schedstat", syscall(SYS_gettid));
+	sprintf(path, "/proc/%ld/schedstat", (long)kvm_gettid());
 	fp = fopen(path, "r");
 	/* Return MIN_RUN_DELAY_NS upon failure just to be safe */
 	if (fscanf(fp, "%ld %ld ", &val[0], &val[1]) < 2)
diff --git a/tools/testing/selftests/kvm/rseq_test.c b/tools/testing/selftests/kvm/rseq_test.c
index f80ad6b47d16..6510fbfd64f1 100644
--- a/tools/testing/selftests/kvm/rseq_test.c
+++ b/tools/testing/selftests/kvm/rseq_test.c
@@ -244,7 +244,7 @@ int main(int argc, char *argv[])
 	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
 
 	pthread_create(&migration_thread, NULL, migration_worker,
-		       (void *)(unsigned long)syscall(SYS_gettid));
+		       (void *)(unsigned long)kvm_gettid());
 
 	if (latency >= 0) {
 		/*
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 16/21] KVM: selftests: Add kvm_sched_getaffinity() wrapper and convert users
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (14 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 15/21] KVM: selftests: Add kvm_gettid() wrapper and convert users Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04 17:23   ` Sean Christopherson
  2026-06-04  2:01 ` [PATCH v5 17/21] KVM: selftests: Add pin_task_to_random_cpu() helper function for IRQ test Josh Hilke
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

Add a KVM wrapper for the sched_getaffinity syscall named
kvm_sched_getaffinity(). Convert existing users of sched_getaffinity to
use the new wrapper.

This helper will be used in a future change in the KVM IRQ test to
migrate vCPU threads.

No functional changes intended.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
---
 tools/testing/selftests/kvm/arch_timer.c                  | 2 +-
 tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c | 2 +-
 tools/testing/selftests/kvm/include/kvm_syscalls.h        | 2 ++
 tools/testing/selftests/kvm/lib/kvm_util.c                | 5 ++---
 tools/testing/selftests/kvm/mmu_stress_test.c             | 6 +-----
 tools/testing/selftests/kvm/rseq_test.c                   | 4 +---
 6 files changed, 8 insertions(+), 13 deletions(-)

diff --git a/tools/testing/selftests/kvm/arch_timer.c b/tools/testing/selftests/kvm/arch_timer.c
index 90c475a61b22..f8b02597897b 100644
--- a/tools/testing/selftests/kvm/arch_timer.c
+++ b/tools/testing/selftests/kvm/arch_timer.c
@@ -85,7 +85,7 @@ static u32 test_get_pcpu(void)
 	cpu_set_t online_cpuset;
 
 	nproc_conf = get_nprocs_conf();
-	sched_getaffinity(0, sizeof(cpu_set_t), &online_cpuset);
+	kvm_sched_getaffinity(0, sizeof(cpu_set_t), &online_cpuset);
 
 	/* Randomly find an available pCPU to place a vCPU on */
 	do {
diff --git a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c
index f7625eb711d6..d9c9377a6325 100644
--- a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c
+++ b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c
@@ -1039,7 +1039,7 @@ int main(int argc, char *argv[])
 	if (!parse_args(argc, argv))
 		exit(KSFT_SKIP);
 
-	sched_getaffinity(0, sizeof(default_cpuset), &default_cpuset);
+	kvm_sched_getaffinity(0, sizeof(default_cpuset), &default_cpuset);
 	set_counter_defaults();
 
 	if (test_args.test_virtual) {
diff --git a/tools/testing/selftests/kvm/include/kvm_syscalls.h b/tools/testing/selftests/kvm/include/kvm_syscalls.h
index e4731741373e..b02a860b5680 100644
--- a/tools/testing/selftests/kvm/include/kvm_syscalls.h
+++ b/tools/testing/selftests/kvm/include/kvm_syscalls.h
@@ -10,6 +10,7 @@
 #include <linux/mman.h>
 
 #include <sys/mman.h>
+#include <sched.h>
 #include <sys/syscall.h>
 
 #include <test_util.h>
@@ -93,5 +94,6 @@ __KVM_SYSCALL_DEFINE(close, 1, int, fd);
 __KVM_SYSCALL_DEFINE(fallocate, 4, int, fd, int, mode, loff_t, offset, loff_t, len);
 __KVM_SYSCALL_DEFINE(ftruncate, 2, unsigned int, fd, off_t, length);
 __KVM_SYSCALL_DEFINE(madvise, 3, void *, addr, size_t, length, int, advice);
+__KVM_SYSCALL_DEFINE(sched_getaffinity, 3, pid_t, pid, size_t, cpusetsize, cpu_set_t *, mask);
 
 #endif /* SELFTEST_KVM_SYSCALLS_H */
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 2d24d8db86b1..0089d4543f5e 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -668,13 +668,12 @@ void kvm_parse_vcpu_pinning(const char *pcpus_string, u32 vcpu_to_pcpu[],
 	cpu_set_t allowed_mask;
 	char *cpu, *cpu_list;
 	char delim[2] = ",";
-	int i, r;
+	int i;
 
 	cpu_list = strdup(pcpus_string);
 	TEST_ASSERT(cpu_list, "strdup() allocation failed.");
 
-	r = sched_getaffinity(0, sizeof(allowed_mask), &allowed_mask);
-	TEST_ASSERT(!r, "sched_getaffinity() failed");
+	kvm_sched_getaffinity(0, sizeof(allowed_mask), &allowed_mask);
 
 	cpu = strtok(cpu_list, delim);
 
diff --git a/tools/testing/selftests/kvm/mmu_stress_test.c b/tools/testing/selftests/kvm/mmu_stress_test.c
index 473ef4c0ea9f..3d5f33a63b2b 100644
--- a/tools/testing/selftests/kvm/mmu_stress_test.c
+++ b/tools/testing/selftests/kvm/mmu_stress_test.c
@@ -255,11 +255,7 @@ static void rendezvous_with_vcpus(struct timespec *time, const char *name)
 static void calc_default_nr_vcpus(void)
 {
 	cpu_set_t possible_mask;
-	int r;
-
-	r = sched_getaffinity(0, sizeof(possible_mask), &possible_mask);
-	TEST_ASSERT(!r, "sched_getaffinity failed, errno = %d (%s)",
-		    errno, strerror(errno));
+	kvm_sched_getaffinity(0, sizeof(possible_mask), &possible_mask);
 
 	nr_vcpus = CPU_COUNT(&possible_mask);
 	TEST_ASSERT(nr_vcpus > 0, "Uh, no CPUs?");
diff --git a/tools/testing/selftests/kvm/rseq_test.c b/tools/testing/selftests/kvm/rseq_test.c
index 6510fbfd64f1..557e393c223b 100644
--- a/tools/testing/selftests/kvm/rseq_test.c
+++ b/tools/testing/selftests/kvm/rseq_test.c
@@ -226,9 +226,7 @@ int main(int argc, char *argv[])
 		}
 	}
 
-	r = sched_getaffinity(0, sizeof(possible_mask), &possible_mask);
-	TEST_ASSERT(!r, "sched_getaffinity failed, errno = %d (%s)", errno,
-		    strerror(errno));
+	kvm_sched_getaffinity(0, sizeof(possible_mask), &possible_mask);
 
 	calc_min_max_cpu();
 
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 17/21] KVM: selftests: Add pin_task_to_random_cpu() helper function for IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (15 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 16/21] KVM: selftests: Add kvm_sched_getaffinity() " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:01 ` [PATCH v5 18/21] KVM: selftests: Verify vCPU migration during IRQ delivery in " Josh Hilke
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

Add a helper function pin_task_to_random_cpu() to randomly select a CPU
from a given cpu_set_t and pin the specified task to it.

This helper will be used in a future change in the KVM IRQ test to
migrate vCPU threads.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
---
 .../testing/selftests/kvm/include/kvm_util.h  |  2 ++
 tools/testing/selftests/kvm/lib/kvm_util.c    | 21 +++++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 88211d696a11..5968d04a77ea 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1094,6 +1094,8 @@ static inline void pin_task_to_cpu(pthread_t task, int cpu)
 	TEST_ASSERT(!r, "Failed to set thread affinity to pCPU '%u'", cpu);
 }
 
+void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus);
+
 static inline int pin_task_to_any_cpu(pthread_t task)
 {
 	int cpu = sched_getcpu();
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 0089d4543f5e..e538e6147ec3 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -662,6 +662,27 @@ void kvm_print_vcpu_pinning_help(void)
 	       "     (default: no pinning)\n", name, name);
 }
 
+void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus)
+{
+	int target_idx;
+	int nr_cpus;
+	int cpu;
+
+	nr_cpus = CPU_COUNT(possible_cpus);
+	TEST_ASSERT(nr_cpus > 0, "No CPUs available in possible_cpus");
+
+	target_idx = kvm_random_u64(&kvm_rng) % nr_cpus;
+
+	for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
+		if (CPU_ISSET(cpu, possible_cpus) && target_idx-- == 0) {
+			pin_task_to_cpu(task, cpu);
+			return;
+		}
+	}
+
+	TEST_FAIL("Failed to find random CPU in possible_cpus");
+}
+
 void kvm_parse_vcpu_pinning(const char *pcpus_string, u32 vcpu_to_pcpu[],
 			    int nr_vcpus)
 {
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 18/21] KVM: selftests: Verify vCPU migration during IRQ delivery in IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (16 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 17/21] KVM: selftests: Add pin_task_to_random_cpu() helper function for IRQ test Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04 17:27   ` Sean Christopherson
  2026-06-04  2:01 ` [PATCH v5 19/21] KVM: selftests: Print vCPU affinity on timeout during " Josh Hilke
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Add the '-m' flag to tools/testing/selftests/kvm/irq_test.c to migrate
vCPU threads across random physical CPUs during the test. This validates
KVM's ability to handle vCPUs changing physical CPUs while interrupts
are actively being injected.

Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/irq_test.c | 33 ++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index ed48562318bf..5f7df76005ec 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -18,6 +18,8 @@ static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
 static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
 static bool guest_received_irq[KVM_MAX_VCPUS];
 static bool guest_received_nmi[KVM_MAX_VCPUS];
+static pid_t vcpu_tids[KVM_MAX_VCPUS];
+static bool migrate_vcpus;
 static bool irq_affinity;
 static bool block_vcpus;
 static bool done;
@@ -67,12 +69,23 @@ static void *vcpu_thread_main(void *arg)
 	struct kvm_vcpu *vcpu = arg;
 	struct ucall uc;
 
+	WRITE_ONCE(vcpu_tids[vcpu->id], kvm_gettid());
+
 	vcpu_run(vcpu);
 	TEST_ASSERT_EQ(UCALL_DONE, get_ucall(vcpu, &uc));
 
 	return NULL;
 }
 
+static void migrate_vcpu_threads(int nr_vcpus, pthread_t *vcpu_threads,
+				 cpu_set_t *available_cpus)
+{
+	int i;
+
+	for (i = 0; i < nr_vcpus; i++)
+		pin_task_to_random_cpu(vcpu_threads[i], available_cpus);
+}
+
 static int vfio_setup_msi(struct vfio_pci_device *device)
 {
 	const int flags = MAP_SHARED | MAP_ANONYMOUS;
@@ -131,7 +144,7 @@ static void kvm_clear_gsi_routes(struct kvm_vm *vm)
 
 static void help(const char *name)
 {
-	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h] [-i nr_irqs] [-n]\n", name);
+	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h] [-i nr_irqs] [-m] [-n]\n", name);
 	printf("\n");
 	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
 	printf("-a	Randomly affinitize the device's host IRQ to different physical CPUs throughout the test\n");
@@ -139,6 +152,7 @@ static void help(const char *name)
 	printf("-c	Destroy and recreate KVM's GSI routing table in between some interrupts\n");
 	printf("-d	Use a VFIO device to send MSI-X interrupts instead of using an emulated eventfd\n");
 	printf("-i	The number of IRQs to generate during the test\n");
+	printf("-m	Pin vCPU threads to random physical CPUs throughout the test\n");
 	printf("-n	Deliver 50 percent of IRQs as non-maskable interrupts\n");
 	printf("\n");
 	exit(KSFT_FAIL);
@@ -169,13 +183,14 @@ int main(int argc, char **argv)
 	FILE *irq_affinity_fp = NULL;
 	int i, j, c, msix, eventfd;
 	bool clear_routes = false;
+	cpu_set_t available_cpus;
 	bool use_nmi = false;
 	struct iommu *iommu;
 	struct kvm_vm *vm;
 	unsigned int irq;
 	int irq_cpu;
 
-	while ((c = getopt(argc, argv, "abcd:hi:n")) != -1) {
+	while ((c = getopt(argc, argv, "abcd:hi:mn")) != -1) {
 		switch (c) {
 		case 'a':
 			irq_affinity = true;
@@ -192,6 +207,9 @@ int main(int argc, char **argv)
 		case 'i':
 			nr_irqs = atoi_positive("Number of IRQs", optarg);
 			break;
+		case 'm':
+			migrate_vcpus = true;
+			break;
 		case 'n':
 			use_nmi = true;
 			break;
@@ -246,6 +264,14 @@ int main(int argc, char **argv)
 	 */
 	irq_cpu = -1;
 
+	if (migrate_vcpus) {
+		kvm_sched_getaffinity(vcpu_tids[0], sizeof(available_cpus), &available_cpus);
+
+		if (nr_vcpus > CPU_COUNT(&available_cpus)) {
+			printf("There are more vCPUs than pCPUs; refusing to migrate.\n");
+			migrate_vcpus = false;
+		}
+	}
 	for (i = 0; i < nr_irqs; i++) {
 		const bool do_clear_routes = clear_routes && (i & BIT(3));
 		const bool do_use_nmi = use_nmi && (i & BIT(2));
@@ -262,6 +288,9 @@ int main(int argc, char **argv)
 			write_proc_irq_smp_affinity_list(irq_affinity_fp, irq, irq_cpu);
 		}
 
+		if (migrate_vcpus && vcpu->id == 0)
+			migrate_vcpu_threads(nr_vcpus, vcpu_threads, &available_cpus);
+
 		for (j = 0; j < nr_vcpus; j++) {
 			TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
 				    "IRQ flag for vCPU %d not clear prior to test",
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 19/21] KVM: selftests: Print vCPU affinity on timeout during IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (17 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 18/21] KVM: selftests: Verify vCPU migration during IRQ delivery in " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:21   ` sashiko-bot
  2026-06-04  2:01 ` [PATCH v5 20/21] KVM: selftests: Make number of vCPUs configurable in " Josh Hilke
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

Add kvm_print_vcpu_affinity() to lib/kvm_util.c to print the physical
CPU affinity of a vCPU thread in a human-readable format.

Use this new helper in tools/testing/selftests/kvm/irq_test.c to print
the vCPU's affinity if it times out waiting for an interrupt while vCPU
migration (-m) is enabled.  This provides valuable context for debugging
IRQ delivery timeouts when vCPUs are being actively migrated across
physical CPUs.

Signed-off-by: Josh Hilke <jrhilke@google.com>
---
 .../testing/selftests/kvm/include/kvm_util.h  |  1 +
 tools/testing/selftests/kvm/irq_test.c        |  2 +
 tools/testing/selftests/kvm/lib/kvm_util.c    | 49 +++++++++++++++++++
 3 files changed, 52 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 5968d04a77ea..18b9e9713d78 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1117,6 +1117,7 @@ static inline int pin_self_to_any_cpu(void)
 void kvm_print_vcpu_pinning_help(void);
 void kvm_parse_vcpu_pinning(const char *pcpus_string, u32 vcpu_to_pcpu[],
 			    int nr_vcpus);
+void kvm_print_vcpu_affinity(struct kvm_vcpu *vcpu, pid_t tid);
 
 unsigned long vm_compute_max_gfn(struct kvm_vm *vm);
 unsigned int vm_calc_num_guest_pages(enum vm_guest_mode mode, size_t size);
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index 5f7df76005ec..1d66293b6d0b 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -319,6 +319,8 @@ int main(int argc, char **argv)
 					print_proc_irq_smp_affinity(irq);
 					print_proc_irq_effective_affinity(irq);
 				}
+				if (migrate_vcpus)
+					kvm_print_vcpu_affinity(vcpu, vcpu_tids[vcpu->id]);
 
 				TEST_FAIL("vCPU %d timed out waiting for IRQ from GSI %d (Vector 0x%x) !\n",
 					  vcpu->id, gsi, vector);
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index e538e6147ec3..7fc3aaf76379 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -15,6 +15,7 @@
 #include <sys/resource.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/sysinfo.h>
 #include <unistd.h>
 #include <linux/kernel.h>
 
@@ -662,6 +663,54 @@ void kvm_print_vcpu_pinning_help(void)
 	       "     (default: no pinning)\n", name, name);
 }
 
+void kvm_print_vcpu_affinity(struct kvm_vcpu *vcpu, pid_t tid)
+{
+	int nprocs = get_nprocs();
+	bool first_range = true;
+	int i, start = -1;
+	cpu_set_t cpus;
+
+	kvm_sched_getaffinity(tid, sizeof(cpus), &cpus);
+
+	/*
+	 * Output format examples:
+	 * - Single CPU:  "vCPU 0 (TID 1234) affined to pCPU(s): 2"
+	 * - List:        "vCPU 0 (TID 1234) affined to pCPU(s): 0,2,4"
+	 * - Range:       "vCPU 0 (TID 1234) affined to pCPU(s): 0-7"
+	 * - Mixed:       "vCPU 0 (TID 1234) affined to pCPU(s): 0-3,8,10-12"
+	 */
+	printf("vCPU %u (TID %d) affined to pCPU(s): ", vcpu->id, tid);
+
+	for (i = 0; i <= nprocs; i++) {
+		/*
+		 * Iterate to nprocs (inclusive) to ensure that if the last pCPU
+		 * is part of a range, the 'else' block triggers one final time
+		 * to flush that range to stdout.
+		 */
+		if (i < nprocs && CPU_ISSET(i, &cpus)) {
+			if (start == -1)
+				start = i;
+			continue;
+		}
+
+		if (start != -1) {
+			int end = i - 1;
+
+			if (!first_range)
+				printf(",");
+
+			if (start == end)
+				printf("%d", start);
+			else
+				printf("%d-%d", start, end);
+
+			start = -1;
+			first_range = false;
+		}
+	}
+	printf("\n");
+}
+
 void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus)
 {
 	int target_idx;
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 20/21] KVM: selftests: Make number of vCPUs configurable in IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (18 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 19/21] KVM: selftests: Print vCPU affinity on timeout during " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:20   ` sashiko-bot
  2026-06-04  2:01 ` [PATCH v5 21/21] KVM: selftests: Add xAPIC support " Josh Hilke
  2026-06-04 20:22 ` [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Sean Christopherson
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Add a '-v' flag to tools/testing/selftests/kvm/irq_test.c to allow users
to configure the number of vCPUs to run in the test.

Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/irq_test.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index 1d66293b6d0b..41c50caa928e 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -144,7 +144,7 @@ static void kvm_clear_gsi_routes(struct kvm_vm *vm)
 
 static void help(const char *name)
 {
-	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h] [-i nr_irqs] [-m] [-n]\n", name);
+	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h] [-i nr_irqs] [-m] [-n] [-v nr_vcpus]\n", name);
 	printf("\n");
 	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
 	printf("-a	Randomly affinitize the device's host IRQ to different physical CPUs throughout the test\n");
@@ -154,6 +154,7 @@ static void help(const char *name)
 	printf("-i	The number of IRQs to generate during the test\n");
 	printf("-m	Pin vCPU threads to random physical CPUs throughout the test\n");
 	printf("-n	Deliver 50 percent of IRQs as non-maskable interrupts\n");
+	printf("-v	Number of vCPUS to run\n");
 	printf("\n");
 	exit(KSFT_FAIL);
 }
@@ -190,7 +191,7 @@ int main(int argc, char **argv)
 	unsigned int irq;
 	int irq_cpu;
 
-	while ((c = getopt(argc, argv, "abcd:hi:mn")) != -1) {
+	while ((c = getopt(argc, argv, "abcd:hi:mnv:")) != -1) {
 		switch (c) {
 		case 'a':
 			irq_affinity = true;
@@ -213,6 +214,9 @@ int main(int argc, char **argv)
 		case 'n':
 			use_nmi = true;
 			break;
+		case 'v':
+			nr_vcpus = atoi_positive("Number of vCPUS", optarg);
+			break;
 		case 'h':
 		default:
 			help(argv[0]);
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* [PATCH v5 21/21] KVM: selftests: Add xAPIC support in IRQ test
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (19 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 20/21] KVM: selftests: Make number of vCPUs configurable in " Josh Hilke
@ 2026-06-04  2:01 ` Josh Hilke
  2026-06-04  2:22   ` sashiko-bot
  2026-06-04 20:22 ` [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Sean Christopherson
  21 siblings, 1 reply; 54+ messages in thread
From: Josh Hilke @ 2026-06-04  2:01 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson
  Cc: kvm, linux-kernel, David Matlack, Alex Williamson, Josh Hilke

From: David Matlack <dmatlack@google.com>

Add the '-x' flag to tools/testing/selftests/kvm/irq_test.c to configure
the guest to use xAPIC mode instead of the default x2APIC mode. This
expands test coverage to ensure that IRQ injection and routing work
correctly when the guest uses the older xAPIC interface.

Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 tools/testing/selftests/kvm/irq_test.c | 28 +++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index 41c50caa928e..7e421cb7bc69 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -20,6 +20,7 @@ static bool guest_received_irq[KVM_MAX_VCPUS];
 static bool guest_received_nmi[KVM_MAX_VCPUS];
 static pid_t vcpu_tids[KVM_MAX_VCPUS];
 static bool migrate_vcpus;
+static bool x2apic = true;
 static bool irq_affinity;
 static bool block_vcpus;
 static bool done;
@@ -31,14 +32,20 @@ static bool done;
 
 static u32 guest_get_vcpu_id(void)
 {
-	return x2apic_read_reg(APIC_ID);
+	if (x2apic)
+		return x2apic_read_reg(APIC_ID);
+	else
+		return xapic_read_reg(APIC_ID) >> 24;
 }
 
 static void guest_irq_handler(struct ex_regs *regs)
 {
 	WRITE_ONCE(guest_received_irq[guest_get_vcpu_id()], true);
 
-	x2apic_write_reg(APIC_EOI, 0);
+	if (x2apic)
+		x2apic_write_reg(APIC_EOI, 0);
+	else
+		xapic_write_reg(APIC_EOI, 0);
 }
 
 static void guest_nmi_handler(struct ex_regs *regs)
@@ -48,7 +55,10 @@ static void guest_nmi_handler(struct ex_regs *regs)
 
 static void guest_code(void)
 {
-	x2apic_enable();
+	if (x2apic)
+		x2apic_enable();
+	else
+		xapic_enable();
 
 	sti_nop();
 
@@ -144,7 +154,7 @@ static void kvm_clear_gsi_routes(struct kvm_vm *vm)
 
 static void help(const char *name)
 {
-	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h] [-i nr_irqs] [-m] [-n] [-v nr_vcpus]\n", name);
+	printf("Usage: %s [-a] [-b] [-c] [-d <segment:bus:device.function>] [-h] [-i nr_irqs] [-m] [-n] [-v nr_vcpus] [-x]\n", name);
 	printf("\n");
 	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
 	printf("-a	Randomly affinitize the device's host IRQ to different physical CPUs throughout the test\n");
@@ -155,6 +165,7 @@ static void help(const char *name)
 	printf("-m	Pin vCPU threads to random physical CPUs throughout the test\n");
 	printf("-n	Deliver 50 percent of IRQs as non-maskable interrupts\n");
 	printf("-v	Number of vCPUS to run\n");
+	printf("-x	Use xAPIC mode instead of x2APIC mode in the guest\n");
 	printf("\n");
 	exit(KSFT_FAIL);
 }
@@ -191,7 +202,7 @@ int main(int argc, char **argv)
 	unsigned int irq;
 	int irq_cpu;
 
-	while ((c = getopt(argc, argv, "abcd:hi:mnv:")) != -1) {
+	while ((c = getopt(argc, argv, "abcd:hi:mnv:x")) != -1) {
 		switch (c) {
 		case 'a':
 			irq_affinity = true;
@@ -217,6 +228,9 @@ int main(int argc, char **argv)
 		case 'v':
 			nr_vcpus = atoi_positive("Number of vCPUS", optarg);
 			break;
+		case 'x':
+			x2apic = false;
+			break;
 		case 'h':
 		default:
 			help(argv[0]);
@@ -229,6 +243,9 @@ int main(int argc, char **argv)
 	vm_install_exception_handler(vm, vector, guest_irq_handler);
 	vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler);
 
+	if (!x2apic)
+		virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA);
+
 	if (device_bdf) {
 		iommu = iommu_init(default_iommu_mode);
 		device = vfio_pci_device_init(device_bdf, iommu);
@@ -250,6 +267,7 @@ int main(int argc, char **argv)
 
 	kvm_assign_irqfd(vm, gsi, eventfd);
 
+	sync_global_to_guest(vm, x2apic);
 	sync_global_to_guest(vm, block_vcpus);
 
 	for (i = 0; i < nr_vcpus; i++)
-- 
2.54.0.1032.g2f8565e1d1-goog


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

* Re: [PATCH v5 08/21] KVM: selftests: Add helpers to write proc IRQ affinity for IRQ test
  2026-06-04  2:01 ` [PATCH v5 08/21] KVM: selftests: Add helpers to write proc IRQ affinity for " Josh Hilke
@ 2026-06-04  2:09   ` sashiko-bot
  2026-06-04 19:35   ` Sean Christopherson
  1 sibling, 0 replies; 54+ messages in thread
From: sashiko-bot @ 2026-06-04  2:09 UTC (permalink / raw)
  To: Josh Hilke; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Unchecked return value of `fflush(fp)` in `write_proc_irq_smp_affinity_list` masks kernel-level errors when setting IRQ affinity.
--

commit f8e5a1088978380d14d1dba883635775118bfd1b
Author: Josh Hilke <jrhilke@google.com>

KVM: selftests: Add helpers to write proc IRQ affinity for IRQ test

This commit introduces utility functions to open and write IRQ affinity
settings via the proc filesystem for use in a subsequent KVM IRQ test patch.

> diff --git a/tools/testing/selftests/kvm/lib/proc_util.c b/tools/testing/selftests/kvm/lib/proc_util.c
> index 84d30f055a0a9..938c90d94f4dc 100644
> --- a/tools/testing/selftests/kvm/lib/proc_util.c
> +++ b/tools/testing/selftests/kvm/lib/proc_util.c
[ ... ]
> @@ -38,3 +38,23 @@ unsigned int vfio_msix_to_host_irq(const char *device_bdf, int msix)
[ ... ]
> +void write_proc_irq_smp_affinity_list(FILE *fp, unsigned int irq, int irq_cpu)
> +{
> +	int ret;
> +
> +	ret = fprintf(fp, "%d\n", irq_cpu);
> +	TEST_ASSERT(ret > 0, "Failed to affinitize IRQ-%u to CPU %d", irq, irq_cpu);
> +	fflush(fp);

[Severity: Medium]
Since fprintf() only writes to the userspace standard library buffer,
wouldn't any kernel-level rejection (such as an offline or invalid CPU
being provided) only be reported during the actual write() syscall
triggered by fflush()?

Should this code check the return value of fflush() to ensure the kernel
actually accepted the affinity setting? Otherwise, couldn't a test
silently proceed with incorrect affinity and cause confusing failures?

> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604020143.748245-1-jrhilke@google.com?part=8

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

* Re: [PATCH v5 09/21] KVM: selftests: Add helpers to print proc IRQ affinity for IRQ test
  2026-06-04  2:01 ` [PATCH v5 09/21] KVM: selftests: Add helpers to print " Josh Hilke
@ 2026-06-04  2:09   ` sashiko-bot
  2026-06-04 17:17     ` Sean Christopherson
  0 siblings, 1 reply; 54+ messages in thread
From: sashiko-bot @ 2026-06-04  2:09 UTC (permalink / raw)
  To: Josh Hilke; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Silent buffer truncation of smp_affinity on systems with high CPU counts.
- [Medium] Bypassing selftest logging framework with direct `printf()` calls.
--

commit 5691e1b7c72b1da31e3e650e6d818488952fb296
Author: Josh Hilke <jrhilke@google.com>

KVM: selftests: Add helpers to print proc IRQ affinity for IRQ test

This commit introduces utility functions to print IRQ affinity settings
via the proc filesystem. These helpers will be used for debugging KVM IRQ
test timeouts.

> diff --git a/tools/testing/selftests/kvm/lib/proc_util.c b/tools/testing/selftests/kvm/lib/proc_util.c
> index 938c90d94f4dc..24a8de92e2290 100644
> --- a/tools/testing/selftests/kvm/lib/proc_util.c
> +++ b/tools/testing/selftests/kvm/lib/proc_util.c

[ ... ]

> +static void print_proc_irq_file(unsigned int irq, const char *file)
> +{
> +	char path[PATH_MAX];
> +	char buf[256];

[Severity: Medium]
Will fgets() silently truncate the smp_affinity masks on large systems when
reading into this buffer?

CPU affinity masks are formatted as comma-separated 32-bit hex words. A
256-byte buffer limits the output to roughly 910 CPUs. 

Because masks are printed from highest index to lowest, truncation would
drop the affinity data for lower CPU indices, which are typically where 
IRQs are pinned.

> +	FILE *fp;
> +
> +	snprintf(path, sizeof(path), "/proc/irq/%u/%s", irq, file);
> +	fp = fopen(path, "r");
> +	if (!fp) {
> +		printf("  Failed to open %s\n", path);

[Severity: Medium]
Does this bypass the selftest logging framework?

KVM selftests typically use pr_info() from test_util.h to allow standard
informational output to be suppressed when QUIET is defined. Using printf()
directly forces unconditional output and can cause log spam in CI
environments.

> +		return;
> +	}
> +
> +	if (fgets(buf, sizeof(buf), fp)) {
> +		buf[strcspn(buf, "\n")] = 0;
> +		printf("  %s: %s\n", path, buf);

[Severity: Medium]
Should this also be updated to use pr_info() instead of printf() to respect
the QUIET mode flag?

> +	}
> +	fclose(fp);
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604020143.748245-1-jrhilke@google.com?part=9

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

* Re: [PATCH v5 06/21] KVM: selftests: Add helper to get host IRQ from device MSIX for IRQ bypass test
  2026-06-04  2:01 ` [PATCH v5 06/21] KVM: selftests: Add helper to get host IRQ from device MSIX for IRQ bypass test Josh Hilke
@ 2026-06-04  2:09   ` sashiko-bot
  2026-06-04 20:01     ` Sean Christopherson
  0 siblings, 1 reply; 54+ messages in thread
From: sashiko-bot @ 2026-06-04  2:09 UTC (permalink / raw)
  To: Josh Hilke; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The fixed 4096-byte buffer for reading `/proc/interrupts` is insufficient on high-core-count systems, causing line truncation that leads to silent parsing errors or test crashes.
--

commit a5706dfe149c4f11538fb9fee08d9fb4a971e2d5
Author: David Matlack <dmatlack@google.com>

KVM: selftests: Add helper to get host IRQ from device MSIX for IRQ bypass test

This commit introduces proc_util.c and a helper function to parse
/proc/interrupts, mapping a VFIO device BDF and MSI-X vector to its
corresponding host IRQ number.

> diff --git a/tools/testing/selftests/kvm/lib/proc_util.c b/tools/testing/selftests/kvm/lib/proc_util.c
> new file mode 100644
> index 0000000000000..84d30f055a0a9
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/lib/proc_util.c

[ ... ]

> +unsigned int vfio_msix_to_host_irq(const char *device_bdf, int msix)
> +{
> +	char search_string[64];
> +	char line[4096];
> +	int irq = -1;
> +	FILE *fp;
> +
> +	fp = open_proc_interrupts();
> +
> +	snprintf(search_string, sizeof(search_string), "vfio-msix[%d]", msix);
> +
> +	while (fgets(line, sizeof(line), fp)) {
> +		if (strstr(line, device_bdf) && strstr(line, search_string)) {
> +			TEST_ASSERT_EQ(1, sscanf(line, "%d:", &irq));

[Severity: Medium]
Is the 4096-byte buffer large enough for systems with high core counts?

In /proc/interrupts, each online CPU gets its own column for interrupt counts.
On systems with many CPUs, a single line might exceed 4096 bytes. When
this happens, fgets() reads the line in multiple chunks.

If the line is chunked, the first chunk contains the IRQ number, and a
subsequent chunk contains the target device names. The strstr() condition
would match on the later chunk, but sscanf() would look for the IRQ number
format at the beginning of that same chunk.

Since the later chunk lacks the leading IRQ number, sscanf() would return 0,
which would then cause TEST_ASSERT_EQ to fail and crash the test.

> +			break;
> +		}
> +	}
> +
> +	fclose(fp);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604020143.748245-1-jrhilke@google.com?part=6

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

* Re: [PATCH v5 04/21] KVM: selftests: Add helper to generate random u64 in range [min,max]
  2026-06-04  2:01 ` [PATCH v5 04/21] KVM: selftests: Add helper to generate random u64 in range [min,max] Josh Hilke
@ 2026-06-04  2:12   ` sashiko-bot
  2026-06-04 16:12     ` Sean Christopherson
  0 siblings, 1 reply; 54+ messages in thread
From: sashiko-bot @ 2026-06-04  2:12 UTC (permalink / raw)
  To: Josh Hilke; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] kvm_random_u64_in_range() cannot generate values in the upper half of large ranges and introduces severe modulo bias due to underlying PRNG limitations.
--

commit f54822168923546305cbe06e95c821b08928d279
Author: Josh Hilke <jrhilke@google.com>

KVM: selftests: Add helper to generate random u64 in range [min,max]

This commit introduces kvm_random_u64_in_range() to generate a random 64-bit
integer within an inclusive range using a kvm_random_state structure.

> diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c
> index e98ca7ef439c4..e208a57f190cf 100644
> --- a/tools/testing/selftests/kvm/lib/test_util.c
> +++ b/tools/testing/selftests/kvm/lib/test_util.c

[ ... ]

> @@ -42,6 +42,24 @@ u32 kvm_random_u32(struct kvm_random_state *state)
>  	return state->seed;
>  }
>  
> +/* Returns a random u64 in the inclusive range [min, max] */
> +u64 kvm_random_u64_in_range(struct kvm_random_state *state, u64 min,
> +			    u64 max)
> +{
> +	u64 value;
> +	u64 range;
> +
> +	TEST_ASSERT(min <= max, "PEBKAC, min = 0x%lx, max = 0x%lx", min, max);
> +
> +	value = kvm_random_u64(state);
> +
> +	range = max - min;
> +	if (range == ULLONG_MAX)
> +		return value;
> +
> +	return min + (value % (range + 1));

[Severity: Medium]
Will this return values uniformly across the entire 64-bit range?

Because kvm_random_u32() uses a Lehmer PRNG with a modulus of 2^31 - 1, its
maximum return value is 0x7FFFFFFE. When kvm_random_u64() concatenates two
of these values, the maximum possible output is 0x7FFFFFFE7FFFFFFE, meaning
bits 31 and 63 are never set.

Due to this restricted PRNG space, using the modulo operator here means the
function cannot generate values in the upper half of large ranges (above
0x7FFFFFFE7FFFFFFE). It also introduces significant modulo bias for ranges
that don't evenly divide this artificial maximum, preventing uniform coverage
of the requested [min, max] range.

> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604020143.748245-1-jrhilke@google.com?part=4

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

* Re: [PATCH v5 10/21] KVM: selftests: Verify interrupts are received when IRQ affinity changes in IRQ test
  2026-06-04  2:01 ` [PATCH v5 10/21] KVM: selftests: Verify interrupts are received when IRQ affinity changes in " Josh Hilke
@ 2026-06-04  2:13   ` sashiko-bot
  0 siblings, 0 replies; 54+ messages in thread
From: sashiko-bot @ 2026-06-04  2:13 UTC (permalink / raw)
  To: Josh Hilke; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The test incorrectly assumes contiguous CPU topologies when generating random CPU IDs and ignores `fflush()` errors, leading to silent failures and buffered write accumulation.
--

commit a578bd3957ea3e342b8ed83cc29e669f1b6658b8
Author: David Matlack <dmatlack@google.com>

KVM: selftests: Verify interrupts are received when IRQ affinity changes in IRQ test

This commit adds the '-a' flag to tools/testing/selftests/kvm/irq_test.c to
randomly affinitize the device's host IRQ to different physical CPUs
throughout the test. This stresses the kernel's ability to maintain correct
interrupt routing and delivery.

> diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
> index 5b42d8abd1ea0..90cff165c3512 100644
> --- a/tools/testing/selftests/kvm/irq_test.c
> +++ b/tools/testing/selftests/kvm/irq_test.c
[ ... ]
> @@ -187,12 +199,23 @@ int main(int argc, char **argv)
[ ... ]
>  	for (i = 0; i < nr_irqs; i++) {
>  		struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
>  		struct timespec start;
>  
>  		kvm_route_msi(vm, gsi, vcpu, vector);
>  
> +		if (irq_affinity_fp) {
> +			irq_cpu = kvm_random_u64(&kvm_rng) % get_nprocs();
> +			write_proc_irq_smp_affinity_list(irq_affinity_fp, irq, irq_cpu);
> +		}

[Severity: Medium]
Will using get_nprocs() here generate invalid CPU IDs on systems with
sparse or non-contiguous CPU topologies?

For example, if only CPUs 0 and 2 are online, get_nprocs() returns 2,
which means the modulo operation could generate an irq_cpu of 1, targeting
an offline or invalid CPU.

Writing an invalid CPU ID fails with -EINVAL, but it looks like
write_proc_irq_smp_affinity_list() uses fprintf(), which only buffers the
data in userspace.

If fflush() returns an error that goes unchecked, could the glibc buffer
retain the unwritten malformed string? Since irq_affinity_fp is reused
across loop iterations, this might cause all subsequent affinity changes to
accumulate and silently fail.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604020143.748245-1-jrhilke@google.com?part=10

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

* Re: [PATCH v5 11/21] KVM: selftests: Verify IRQs wake up halted vCPUs in IRQ test
  2026-06-04  2:01 ` [PATCH v5 11/21] KVM: selftests: Verify IRQs wake up halted vCPUs " Josh Hilke
@ 2026-06-04  2:15   ` sashiko-bot
  2026-06-04 16:11     ` Sean Christopherson
  0 siblings, 1 reply; 54+ messages in thread
From: sashiko-bot @ 2026-06-04  2:15 UTC (permalink / raw)
  To: Josh Hilke; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The guest code introduces a missed wakeup (TOCTOU) race condition between checking the `done` flag and executing the `hlt` instruction. This can cause the guest vCPU to sleep indefinitely, leading to a test hang.
--

commit 9a28612ad82c9a519d18da6d85e17ef536f35e8d
Author: David Matlack <dmatlack@google.com>

KVM: selftests: Verify IRQs wake up halted vCPUs in IRQ test
    
This commit adds a '-b' flag to the KVM IRQ selftest to verify that
interrupts correctly wake up vCPUs from a halted state. If the flag
is provided, the guest uses the HLT instruction instead of spinning.

> diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
> index 90cff165c3512..671338f0e6122 100644
> --- a/tools/testing/selftests/kvm/irq_test.c
> +++ b/tools/testing/selftests/kvm/irq_test.c

[ ... ]

> @@ -43,8 +44,12 @@ static void guest_code(void)
>  
>  	WRITE_ONCE(guest_ready_for_irqs[guest_get_vcpu_id()], true);
>  
> -	while (!READ_ONCE(done))
> -		cpu_relax();
> +	while (!READ_ONCE(done)) {
> +		if (block_vcpus)
> +			hlt();

[Severity: Medium]
Is there a missed wakeup (TOCTOU) race condition between checking the done
flag and executing the hlt instruction?

If the host sets done to true and triggers the final wake-up interrupt
after the guest evaluates !READ_ONCE(done) but before it executes hlt(),
the interrupt handler will run immediately. Upon returning, the guest will
blindly execute hlt() and go to sleep. 

Since the host only sends one final interrupt per vCPU, does the guest
need to disable interrupts (e.g., using cli()) before checking the condition
and use safe_halt() to atomically re-enable interrupts and halt?

> +		else
> +			cpu_relax();
> +	}
>  
>  	GUEST_DONE();
>  }

[ ... ]

> @@ -247,8 +258,19 @@ int main(int argc, char **argv)
>  
>  	WRITE_AND_SYNC_TO_GUEST(vm, done, true);
>  
> -	for (i = 0; i < nr_vcpus; i++)
> +	for (i = 0; i < nr_vcpus; i++) {
> +		/*
> +		 * Verify that sending an interrupt to a halted vCPU wakes it
> +		 * up. If the vCPU does not wake up, the call to pthread_join(),
> +		 * below, will hang.
> +		 */
> +		if (block_vcpus) {
> +			kvm_route_msi(vm, gsi, vcpus[i], vector);
> +			trigger_interrupt(device, eventfd);
> +		}
> +
>  		pthread_join(vcpu_threads[i], NULL);

[Severity: Medium]
If the race condition described above in guest_code() occurs, the guest
could miss this wakeup interrupt and sleep forever. Will this cause
pthread_join() to hang indefinitely, resulting in a test timeout?

> +	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604020143.748245-1-jrhilke@google.com?part=11

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

* Re: [PATCH v5 20/21] KVM: selftests: Make number of vCPUs configurable in IRQ test
  2026-06-04  2:01 ` [PATCH v5 20/21] KVM: selftests: Make number of vCPUs configurable in " Josh Hilke
@ 2026-06-04  2:20   ` sashiko-bot
  2026-06-04 17:29     ` Sean Christopherson
  0 siblings, 1 reply; 54+ messages in thread
From: sashiko-bot @ 2026-06-04  2:20 UTC (permalink / raw)
  To: Josh Hilke; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missing bounds check on user-supplied `nr_vcpus` allows stack buffer overflows and out-of-bounds global array accesses.
--

commit 115e22303a8d11509c805d6bfdcdbd39b670c16d
Author: David Matlack <dmatlack@google.com>

KVM: selftests: Make number of vCPUs configurable in IRQ test

This commit adds a '-v' flag to tools/testing/selftests/kvm/irq_test.c,
allowing users to configure the number of vCPUs to run in the test.

> diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
> index 1d66293b6d0b8..41c50caa928e2 100644
> --- a/tools/testing/selftests/kvm/irq_test.c
> +++ b/tools/testing/selftests/kvm/irq_test.c
[ ... ]
> @@ -213,6 +214,9 @@ int main(int argc, char **argv)
>  		case 'n':
>  			use_nmi = true;
>  			break;
> +		case 'v':
> +			nr_vcpus = atoi_positive("Number of vCPUS", optarg);

[Severity: Medium]
Does this code need a bounds check for nr_vcpus against KVM_MAX_VCPUS?

Because vcpu_threads and vcpus are fixed-size stack arrays in main():

	pthread_t vcpu_threads[KVM_MAX_VCPUS];
	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];

if the user specifies a value larger than KVM_MAX_VCPUS, won't it cause a
stack buffer overflow when passing vcpus to vm_create_with_vcpus() or
subsequently populating the vcpu_threads array?

> +			break;
>  		case 'h':
>  		default:
>  			help(argv[0]);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604020143.748245-1-jrhilke@google.com?part=20

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

* Re: [PATCH v5 19/21] KVM: selftests: Print vCPU affinity on timeout during IRQ test
  2026-06-04  2:01 ` [PATCH v5 19/21] KVM: selftests: Print vCPU affinity on timeout during " Josh Hilke
@ 2026-06-04  2:21   ` sashiko-bot
  2026-06-04 17:28     ` Sean Christopherson
  0 siblings, 1 reply; 54+ messages in thread
From: sashiko-bot @ 2026-06-04  2:21 UTC (permalink / raw)
  To: Josh Hilke; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] kvm_print_vcpu_affinity() uses get_nprocs() as the loop boundary, which silently truncates CPUs with indices >= get_nprocs() on sparse topologies.
--

commit 9e2355f47489ee5cf4674888f5c4b7d1058bc869
Author: Josh Hilke <jrhilke@google.com>

KVM: selftests: Print vCPU affinity on timeout during IRQ test

Adds a helper function to print the physical CPU affinity of a vCPU thread 
in a human-readable format. Uses this new helper in the irq_test to provide 
context when a vCPU times out waiting for an interrupt during migration.

> diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> index e538e6147ec3f..7fc3aaf763797 100644
> --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> +++ b/tools/testing/selftests/kvm/lib/kvm_util.c

[ ... ]

> @@ -662,6 +663,54 @@ void kvm_print_vcpu_pinning_help(void)
>  	       "     (default: no pinning)\n", name, name);
>  }
>  
> +void kvm_print_vcpu_affinity(struct kvm_vcpu *vcpu, pid_t tid)
> +{
> +	int nprocs = get_nprocs();
> +	bool first_range = true;
> +	int i, start = -1;
> +	cpu_set_t cpus;
> +
> +	kvm_sched_getaffinity(tid, sizeof(cpus), &cpus);
> +
> +	/*
> +	 * Output format examples:
> +	 * - Single CPU:  "vCPU 0 (TID 1234) affined to pCPU(s): 2"
> +	 * - List:        "vCPU 0 (TID 1234) affined to pCPU(s): 0,2,4"
> +	 * - Range:       "vCPU 0 (TID 1234) affined to pCPU(s): 0-7"
> +	 * - Mixed:       "vCPU 0 (TID 1234) affined to pCPU(s): 0-3,8,10-12"
> +	 */
> +	printf("vCPU %u (TID %d) affined to pCPU(s): ", vcpu->id, tid);
> +
> +	for (i = 0; i <= nprocs; i++) {
> +		/*
> +		 * Iterate to nprocs (inclusive) to ensure that if the last pCPU
> +		 * is part of a range, the 'else' block triggers one final time
> +		 * to flush that range to stdout.
> +		 */
> +		if (i < nprocs && CPU_ISSET(i, &cpus)) {

[Severity: Medium]
Does using get_nprocs() as the loop boundary risk silently truncating CPUs 
on sparse topologies?

get_nprocs() returns the count of currently online CPUs, not the maximum 
CPU ID. If a system has 4 online CPUs but their IDs are 0, 1, 2, and 7, 
get_nprocs() will return 4.

This would cause the loop to terminate prematurely, completely ignoring 
valid but higher-numbered CPU indices (like CPU 7) in the cpu_set_t mask.

Should this iterate up to CPU_SETSIZE instead to encompass the entire mask 
capacity, similar to other helper functions like pin_task_to_random_cpu()?

> +			if (start == -1)
> +				start = i;
> +			continue;
> +		}
> +
> +		if (start != -1) {
> +			int end = i - 1;
> +
> +			if (!first_range)
> +				printf(",");
> +
> +			if (start == end)
> +				printf("%d", start);
> +			else
> +				printf("%d-%d", start, end);
> +
> +			start = -1;
> +			first_range = false;
> +		}
> +	}
> +	printf("\n");
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604020143.748245-1-jrhilke@google.com?part=19

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

* Re: [PATCH v5 21/21] KVM: selftests: Add xAPIC support in IRQ test
  2026-06-04  2:01 ` [PATCH v5 21/21] KVM: selftests: Add xAPIC support " Josh Hilke
@ 2026-06-04  2:22   ` sashiko-bot
  2026-06-04 17:34     ` Sean Christopherson
  0 siblings, 1 reply; 54+ messages in thread
From: sashiko-bot @ 2026-06-04  2:22 UTC (permalink / raw)
  To: Josh Hilke; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The test will silently hang when run with `-x` (xAPIC mode) and `-v` configured with 256 or more vCPUs due to 8-bit APIC ID truncation.
--

commit 5d7e9bc4aa987e66842949c22b1af4bb4e8fff94
Author: David Matlack <dmatlack@google.com>

KVM: selftests: Add xAPIC support in IRQ test

This commit adds the -x flag to the irq_test to configure the guest to use
xAPIC mode instead of the default x2APIC mode. This expands test coverage
to ensure that IRQ injection and routing work correctly when the guest uses
the older xAPIC interface.

> diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
> index 41c50caa928e2..7e421cb7bc69b 100644
> --- a/tools/testing/selftests/kvm/irq_test.c
> +++ b/tools/testing/selftests/kvm/irq_test.c
[ ... ]
> @@ -31,14 +32,20 @@ static bool done;
>  
>  static u32 guest_get_vcpu_id(void)
>  {
> -	return x2apic_read_reg(APIC_ID);
> +	if (x2apic)
> +		return x2apic_read_reg(APIC_ID);
> +	else
> +		return xapic_read_reg(APIC_ID) >> 24;
>  }

[Severity: Medium]
Does this truncation to 8 bits cause the test to silently hang if run with
256 or more vCPUs in xAPIC mode?

For vCPU IDs 256 and above, the 8-bit xAPIC ID will wrap around. When the
guest signals readiness:

guest_code()
    WRITE_ONCE(guest_ready_for_irqs[guest_get_vcpu_id()], true);

it would update the flag for an aliased ID (like 0) instead of its own index.

The host would then spin indefinitely waiting for the actual ID to become
ready:

main()
    while (!SYNC_FROM_GUEST_AND_READ(vm, guest_ready_for_irqs[vcpu->id]))
        continue;

Should a bounds check be added in main() to ensure the number of vCPUs is
not greater than 255 when the xAPIC mode flag is provided?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604020143.748245-1-jrhilke@google.com?part=21

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

* Re: [PATCH v5 11/21] KVM: selftests: Verify IRQs wake up halted vCPUs in IRQ test
  2026-06-04  2:15   ` sashiko-bot
@ 2026-06-04 16:11     ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 16:11 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Josh Hilke, kvm

On Thu, Jun 04, 2026, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] The guest code introduces a missed wakeup (TOCTOU) race condition between checking the `done` flag and executing the `hlt` instruction. This can cause the guest vCPU to sleep indefinitely, leading to a test hang.
> --
> 
> commit 9a28612ad82c9a519d18da6d85e17ef536f35e8d
> Author: David Matlack <dmatlack@google.com>
> 
> KVM: selftests: Verify IRQs wake up halted vCPUs in IRQ test
>     
> This commit adds a '-b' flag to the KVM IRQ selftest to verify that
> interrupts correctly wake up vCPUs from a halted state.

s/halted/blocking, to connect '-b' to "blocking".

> If the flag is provided, the guest uses the HLT instruction instead of
> spinning.

Describe the *change* as a command, don't describe the effect of the code.  E.g.

  If blocking mode is enabled, execute HLT in the guest (for x86) instead of
  simply doing cpu_relax(), blah blah blah.

> > diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
> > index 90cff165c3512..671338f0e6122 100644
> > --- a/tools/testing/selftests/kvm/irq_test.c
> > +++ b/tools/testing/selftests/kvm/irq_test.c
> 
> [ ... ]
> 
> > @@ -43,8 +44,12 @@ static void guest_code(void)
> >  
> >  	WRITE_ONCE(guest_ready_for_irqs[guest_get_vcpu_id()], true);
> >  
> > -	while (!READ_ONCE(done))
> > -		cpu_relax();
> > +	while (!READ_ONCE(done)) {
> > +		if (block_vcpus)
> > +			hlt();
> 
> [Severity: Medium]
> Is there a missed wakeup (TOCTOU) race condition between checking the done
> flag and executing the hlt instruction?
> 
> If the host sets done to true and triggers the final wake-up interrupt
> after the guest evaluates !READ_ONCE(done) but before it executes hlt(),
> the interrupt handler will run immediately. Upon returning, the guest will
> blindly execute hlt() and go to sleep. 
> 
> Since the host only sends one final interrupt per vCPU, does the guest
> need to disable interrupts (e.g., using cli()) before checking the condition
> and use safe_halt() to atomically re-enable interrupts and halt?

Yeah, this is all kinds of broken.  Even if the test passes (I haven't actually
tried this version), there's zero chance it's actually providing the coverage I
want it to provide.

In the interest of landing this test sooner than later, as I *really* want this
coverage, I'll skip this patch and punt on getting a functionally correct version
to the future.

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

* Re: [PATCH v5 04/21] KVM: selftests: Add helper to generate random u64 in range [min,max]
  2026-06-04  2:12   ` sashiko-bot
@ 2026-06-04 16:12     ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 16:12 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Josh Hilke, kvm

On Thu, Jun 04, 2026, sashiko-bot@kernel.org wrote:
> > @@ -42,6 +42,24 @@ u32 kvm_random_u32(struct kvm_random_state *state)
> >  	return state->seed;
> >  }
> >  
> > +/* Returns a random u64 in the inclusive range [min, max] */
> > +u64 kvm_random_u64_in_range(struct kvm_random_state *state, u64 min,
> > +			    u64 max)
> > +{
> > +	u64 value;
> > +	u64 range;
> > +
> > +	TEST_ASSERT(min <= max, "PEBKAC, min = 0x%lx, max = 0x%lx", min, max);
> > +
> > +	value = kvm_random_u64(state);
> > +
> > +	range = max - min;
> > +	if (range == ULLONG_MAX)
> > +		return value;
> > +
> > +	return min + (value % (range + 1));
> 
> [Severity: Medium]
> Will this return values uniformly across the entire 64-bit range?
> 
> Because kvm_random_u32() uses a Lehmer PRNG with a modulus of 2^31 - 1, its
> maximum return value is 0x7FFFFFFE. When kvm_random_u64() concatenates two
> of these values, the maximum possible output is 0x7FFFFFFE7FFFFFFE, meaning
> bits 31 and 63 are never set.
> 
> Due to this restricted PRNG space, using the modulo operator here means the
> function cannot generate values in the upper half of large ranges (above
> 0x7FFFFFFE7FFFFFFE). It also introduces significant modulo bias for ranges
> that don't evenly divide this artificial maximum, preventing uniform coverage
> of the requested [min, max] range.

Not sure how much I trust AI's ability to reason about math, given past "bug"
reports.  Regardless, this is a problem to solve in the future.

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

* Re: [PATCH v5 05/21] KVM: selftests: Add IRQ injection test
  2026-06-04  2:01 ` [PATCH v5 05/21] KVM: selftests: Add IRQ injection test Josh Hilke
@ 2026-06-04 16:19   ` Sean Christopherson
  2026-06-04 16:26     ` Sean Christopherson
  0 siblings, 1 reply; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 16:19 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Josh Hilke wrote:
> +static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
> +			  u8 vector)
> +{
> +	struct {
> +		struct kvm_irq_routing head;

s/head/header, because I read this as "head entry", not "header of the struct".

> +		struct kvm_irq_routing_entry entry;
> +	} routing_data = {};
> +
> +	struct kvm_irq_routing *routes = &routing_data.head;
> +
> +	routes->nr = 1;
> +	routes->entries[0].gsi = gsi;

This is silly (and confusing), just initialize the information in the struct
declaration:

	struct {
		struct kvm_irq_routing header;
		struct kvm_irq_routing_entry entry;
	} routing = {
		.header.nr = 1,
		.entry = {
			.gsi = gsi,
			.type = KVM_IRQ_ROUTING_MSI,
			.u.msi.address_lo = 0xFEE00000 | (vcpu->id << 12),
			.u.msi.data = use_nmi ? NMI_VECTOR | (4 << 8) : vector,
		},
	};

	vm_ioctl(vm, KVM_SET_GSI_ROUTING, &routing.header);

> +	routes->entries[0].type = KVM_IRQ_ROUTING_MSI;
> +	routes->entries[0].u.msi.address_lo = 0xFEE00000 | (vcpu->id << 12);
> +	routes->entries[0].u.msi.data = vector;
> +
> +	vm_ioctl(vm, KVM_SET_GSI_ROUTING, routes);
> +}
> +
> +static void help(const char *name)
> +{
> +	printf("Usage: %s [-h]\n", name);
> +	printf("\n");
> +	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");

This is all kinds of misleading and wrong.  IRQ *injection* is not guaranteed.
KVM will use CPU-to-CPU posted interrupts to deliver the interrupt, if supported.
And it's not an "emulated eventfd"; the test isn't emulated anything.  It's
manually *signaling* the eventfd but there's no emulation of any kind.  And that
becomes stale when the test adds support for VFIO devices.

	Tests KVM interrupt routing and delivery via irqfd.

> +	for (i = 0; i < nr_irqs; i++) {
> +		struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
> +		struct timespec start;
> +
> +		kvm_route_msi(vm, gsi, vcpu, vector);
> +
> +		for (j = 0; j < nr_vcpus; j++)
> +			TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
> +				    "IRQ flag for vCPU %d not clear prior to test",
> +				    vcpus[j]->id);
> +
> +		/* Trigger interrupt */

Meh, not helpful.  And it goes away in a few patches.

> +		eventfd_write(eventfd, 1);
> +
> +		clock_gettime(CLOCK_MONOTONIC, &start);
> +		for (;;) {
> +			if (GUEST_RECEIVED_IRQ(vcpu))
> +				break;

This is a kludgy and confusing way of writing:

		clock_gettime(CLOCK_MONOTONIC, &start);
		while (GUEST_RECEIVED_INTERRUPT(vcpu, do_use_nmi) &&
		       timespec_to_ns(timespec_elapsed(start)) <= timeout_ns)
			cpu_relax();

> +
> +			if (timespec_to_ns(timespec_elapsed(start)) > timeout_ns)
> +				TEST_FAIL("vCPU %d timed out waiting for IRQ from GSI %d (Vector 0x%x) !\n",
> +					  vcpu->id, gsi, vector);

Don't do an if-statement and then TEST_FAIL(), just TEST_ASSERT().  And with the
above, hoist this out of the loop:

		TEST_ASSERT(GUEST_RECEIVED_INTERRUPT(vcpu, do_use_nmi),
			    "vCPU %d timed out waiting for %s (vector 0x%x) from GSI %d (via CPU %d)\n",
			    vcpu->id, do_use_nmi ? "NMI" : "IRQ",
			    do_use_nmi ? NMI_VECTOR : vector, gsi, irq_cpu);

And as above, this should cpu_relax().

> +		}
> +
> +		WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
> +	}
> +
> +	WRITE_AND_SYNC_TO_GUEST(vm, done, true);
> +
> +	for (i = 0; i < nr_vcpus; i++)
> +		pthread_join(vcpu_threads[i], NULL);
> +
> +	printf("Test passed!\n");

This is redundant, the return code provides this information.

> +
> +	return 0;
> +}
> -- 
> 2.54.0.1032.g2f8565e1d1-goog
> 

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

* Re: [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test
  2026-06-04  2:01 ` [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test Josh Hilke
@ 2026-06-04 16:22   ` Sean Christopherson
  2026-06-04 17:56   ` Sean Christopherson
  1 sibling, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 16:22 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Josh Hilke wrote:
> @@ -76,9 +109,10 @@ static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
>  
>  static void help(const char *name)
>  {
> -	printf("Usage: %s [-h]\n", name);
> +	printf("Usage: %s [-d <segment:bus:device.function>] [-h]\n", name);
>  	printf("\n");
>  	printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
> +	printf("-d	Use a VFIO device to send MSI-X interrupts instead of using an emulated eventfd\n");


	printf("-d	Use a VFIO device to send MSI-X interrupts instead of manually signaling the eventfd\n");

>  	printf("\n");
>  	exit(KSFT_FAIL);
>  }
> @@ -100,14 +134,21 @@ int main(int argc, char **argv)
>  	u32 gsi = kvm_random_u64_in_range(&kvm_rng, 24, KVM_MAX_IRQ_ROUTES - 1);
>  	u8 vector = kvm_random_u64_in_range(&kvm_rng, 32, UINT8_MAX);
>  
> -	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
>  	pthread_t vcpu_threads[KVM_MAX_VCPUS];
> +	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
> +	struct vfio_pci_device *device = NULL;
>  	int nr_irqs = 1000, nr_vcpus = 1;
> -	int i, j, c, eventfd;
> +	const char *device_bdf = NULL;
> +	int i, j, c, msix, eventfd;
> +	struct iommu *iommu;
>  	struct kvm_vm *vm;
> +	unsigned int irq;

I think it makes sense to track "irq" as a signed int, so that the !device path
can set it to -1.  Then it can be printed somewhat blindly without being outright
wrong.

> -	while ((c = getopt(argc, argv, "h")) != -1) {
> +	while ((c = getopt(argc, argv, "d:h")) != -1) {
>  		switch (c) {
> +		case 'd':
> +			device_bdf = optarg;
> +			break;
>  		case 'h':
>  		default:
>  			help(argv[0]);
> @@ -119,7 +160,17 @@ int main(int argc, char **argv)
>  	vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
>  	vm_install_exception_handler(vm, vector, guest_irq_handler);
>  
> -	eventfd = kvm_new_eventfd();
> +	if (device_bdf) {
> +		iommu = iommu_init(default_iommu_mode);
> +		device = vfio_pci_device_init(device_bdf, iommu);
> +		msix = vfio_setup_msi(device);
> +		irq = vfio_msix_to_host_irq(device_bdf, msix);
> +		eventfd = device->msi_eventfds[msix];
> +		printf("Using device %s MSI-X[%d] (IRQ-%u)\n", device_bdf, msix,
> +		       irq);
> +	} else {
> +		eventfd = kvm_new_eventfd();
> +	}
>  
>  	printf("Injecting interrupts for GSI %d (Vector 0x%x) %d times\n",
>  	       gsi, vector, nr_irqs);
> @@ -147,8 +198,7 @@ int main(int argc, char **argv)
>  				    "IRQ flag for vCPU %d not clear prior to test",
>  				    vcpus[j]->id);

Print the IRQ in the assert.  Ditto for the pCPU in the future.  Providing more
debug information is nice, but it should *always* be secondary to providing info
in the assert/error itself.

		TEST_ASSERT(GUEST_RECEIVED_INTERRUPT(vcpu, do_use_nmi),
			    "vCPU %d timed out waiting for %s (vector 0x%x) from GSI %d (via CPU %d)\n",
			    vcpu->id, do_use_nmi ? "NMI" : "IRQ",
			    do_use_nmi ? NMI_VECTOR : vector, gsi, irq_cpu);


>  
> -		/* Trigger interrupt */
> -		eventfd_write(eventfd, 1);
> +		trigger_interrupt(device, eventfd);
>  
>  		clock_gettime(CLOCK_MONOTONIC, &start);
>  		for (;;) {
> -- 
> 2.54.0.1032.g2f8565e1d1-goog
> 

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

* Re: [PATCH v5 05/21] KVM: selftests: Add IRQ injection test
  2026-06-04 16:19   ` Sean Christopherson
@ 2026-06-04 16:26     ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 16:26 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Sean Christopherson wrote:
> On Thu, Jun 04, 2026, Josh Hilke wrote:
> > +		eventfd_write(eventfd, 1);
> > +
> > +		clock_gettime(CLOCK_MONOTONIC, &start);
> > +		for (;;) {
> > +			if (GUEST_RECEIVED_IRQ(vcpu))
> > +				break;
> 
> This is a kludgy and confusing way of writing:
> 
> 		clock_gettime(CLOCK_MONOTONIC, &start);
> 		while (GUEST_RECEIVED_INTERRUPT(vcpu, do_use_nmi) &&

Heh, "minor" detail:

		clock_gettime(CLOCK_MONOTONIC, &start);
		while (!GUEST_RECEIVED_INTERRUPT(vcpu, do_use_nmi) &&
		       timespec_to_ns(timespec_elapsed(start)) <= timeout_ns)
			cpu_relax();

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

* Re: [PATCH v5 09/21] KVM: selftests: Add helpers to print proc IRQ affinity for IRQ test
  2026-06-04  2:09   ` sashiko-bot
@ 2026-06-04 17:17     ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:17 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Josh Hilke, kvm

On Thu, Jun 04, 2026, sashiko-bot@kernel.org wrote:
> > +static void print_proc_irq_file(unsigned int irq, const char *file)
> > +{
> > +	char path[PATH_MAX];
> > +	char buf[256];
> 
> [Severity: Medium]
> Will fgets() silently truncate the smp_affinity masks on large systems when
> reading into this buffer?
> 
> CPU affinity masks are formatted as comma-separated 32-bit hex words. A
> 256-byte buffer limits the output to roughly 910 CPUs. 
> 
> Because masks are printed from highest index to lowest, truncation would
> drop the affinity data for lower CPU indices, which are typically where 
> IRQs are pinned.
> 
> > +	FILE *fp;
> > +
> > +	snprintf(path, sizeof(path), "/proc/irq/%u/%s", irq, file);
> > +	fp = fopen(path, "r");
> > +	if (!fp) {
> > +		printf("  Failed to open %s\n", path);
> 
> [Severity: Medium]
> Does this bypass the selftest logging framework?
> 
> KVM selftests typically use pr_info() from test_util.h to allow standard
> informational output to be suppressed when QUIET is defined. Using printf()
> directly forces unconditional output and can cause log spam in CI
> environments.
> 
> > +		return;
> > +	}
> > +
> > +	if (fgets(buf, sizeof(buf), fp)) {
> > +		buf[strcspn(buf, "\n")] = 0;
> > +		printf("  %s: %s\n", path, buf);
> 
> [Severity: Medium]
> Should this also be updated to use pr_info() instead of printf() to respect
> the QUIET mode flag?

I think for the initial landing, it makes sense to skip this and the usage in
irq_test.  Printing the affinity information definitely qualifies as "nice to
have", i.e. it can wait.

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

* Re: [PATCH v5 12/21] KVM: selftests: Verify interrupts are received after modifying IRQ routes in IRQ test
  2026-06-04  2:01 ` [PATCH v5 12/21] KVM: selftests: Verify interrupts are received after modifying IRQ routes " Josh Hilke
@ 2026-06-04 17:22   ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:22 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

This is _very_ misleading.  The test _already_ verifies routing changes.  This
is specifically setting empty routing, to validate that KVM doesn't barf on a
complete teardown of routing.

On Thu, Jun 04, 2026, Josh Hilke wrote:
> From: David Matlack <dmatlack@google.com>
> 
> Add the '-c' flag to tools/testing/selftests/kvm/irq_test.c to destroy

I feel quite strong that this need to be -e for "empty", not -c for "clear".
Because there are many different ways the test could "clear" routing, e.g. it
could nullify just the target IRQ's entry, set the entry to a suppress the IRQ,
etc.

> and recreate KVM's GSI routing table between interrupts. This ensures
> that KVM correctly handles dynamic updates to the interrupt routing
> table while interrupts are actively being signaled by assigned devices.
> 
> Co-developed-by: Josh Hilke <jrhilke@google.com>
> Signed-off-by: Josh Hilke <jrhilke@google.com>
> Signed-off-by: David Matlack <dmatlack@google.com>

SoB order is wrong (here and in several other patches).  It needs to be:

    Signed-off-by: David Matlack <dmatlack@google.com>
    Co-developed-by: Josh Hilke <jrhilke@google.com>
    Signed-off-by: Josh Hilke <jrhilke@google.com>

Please read Documentation/process/5.Posting.rst and
Documentation/process/submitting-patches.rst.

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

* Re: [PATCH v5 14/21] KVM: selftests: Verify non-postable IRQ remapping in IRQ test
  2026-06-04  2:01 ` [PATCH v5 14/21] KVM: selftests: Verify non-postable IRQ remapping " Josh Hilke
@ 2026-06-04 17:22   ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:22 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Josh Hilke wrote:
> From: David Matlack <dmatlack@google.com>
> 
> Add the -n flag to tools/testing/selftests/kvm/irq_test.c to route a
> portion of device interrupts as NMIs (Non-Maskable Interrupts) into the
> guest using an alternating pattern of 4 NMIs followed by 4 regular
> interrupts.
> 
> While this adds coverage for NMI injection, the primary goal is to
> validate KVM's handling of non-postable interrupt delivery.
> Specifically, the transitions between posted and remapped modes.  NMIs
> are used for this purpose because they are a reliable, architectural way
> to force these code paths.
> 
> Co-developed-by: Josh Hilke <jrhilke@google.com>
> Signed-off-by: Josh Hilke <jrhilke@google.com>
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
>  tools/testing/selftests/kvm/irq_test.c | 44 ++++++++++++++++++++------
>  1 file changed, 35 insertions(+), 9 deletions(-)
> 
> diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
> index de8c29baa2b0..ed48562318bf 100644
> --- a/tools/testing/selftests/kvm/irq_test.c
> +++ b/tools/testing/selftests/kvm/irq_test.c
> @@ -17,12 +17,15 @@
>  static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
>  static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
>  static bool guest_received_irq[KVM_MAX_VCPUS];
> +static bool guest_received_nmi[KVM_MAX_VCPUS];
>  static bool irq_affinity;
>  static bool block_vcpus;
>  static bool done;
>  
>  #define GUEST_RECEIVED_IRQ(__vcpu)	\
>  	SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_irq[(__vcpu)->id])
> +#define GUEST_RECEIVED_NMI(__vcpu)	\
> +	SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_nmi[(__vcpu)->id])

Add a wrapper macro to simplify/consolidate the core logic:

#define GUEST_RECEIVED_INTERRUPT(__vcpu, __nmi)	\
	((__nmi) ? GUEST_RECEIVED_NMI(__vcpu) : GUEST_RECEIVED_IRQ(__vcpu))

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

* Re: [PATCH v5 16/21] KVM: selftests: Add kvm_sched_getaffinity() wrapper and convert users
  2026-06-04  2:01 ` [PATCH v5 16/21] KVM: selftests: Add kvm_sched_getaffinity() " Josh Hilke
@ 2026-06-04 17:23   ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:23 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Josh Hilke wrote:
> Add a KVM wrapper for the sched_getaffinity syscall named
> kvm_sched_getaffinity(). Convert existing users of sched_getaffinity to
> use the new wrapper.
> 
> This helper will be used in a future change in the KVM IRQ test to
> migrate vCPU threads.
> 
> No functional changes intended.

There are most definitely functional changes, because not all existing callers
assert success.  They obviously require success, but adding the assert *is* a
functional change.

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

* Re: [PATCH v5 18/21] KVM: selftests: Verify vCPU migration during IRQ delivery in IRQ test
  2026-06-04  2:01 ` [PATCH v5 18/21] KVM: selftests: Verify vCPU migration during IRQ delivery in " Josh Hilke
@ 2026-06-04 17:27   ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:27 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Josh Hilke wrote:
> From: David Matlack <dmatlack@google.com>
> 
> Add the '-m' flag to tools/testing/selftests/kvm/irq_test.c to migrate
> vCPU threads across random physical CPUs during the test. This validates
> KVM's ability to handle vCPUs changing physical CPUs while interrupts
> are actively being injected.
> 
> Co-developed-by: Josh Hilke <jrhilke@google.com>
> Signed-off-by: Josh Hilke <jrhilke@google.com>
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
>  tools/testing/selftests/kvm/irq_test.c | 33 ++++++++++++++++++++++++--
>  1 file changed, 31 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
> index ed48562318bf..5f7df76005ec 100644
> --- a/tools/testing/selftests/kvm/irq_test.c
> +++ b/tools/testing/selftests/kvm/irq_test.c
> @@ -18,6 +18,8 @@ static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
>  static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
>  static bool guest_received_irq[KVM_MAX_VCPUS];
>  static bool guest_received_nmi[KVM_MAX_VCPUS];
> +static pid_t vcpu_tids[KVM_MAX_VCPUS];

This doesn't need to exist.

> +static bool migrate_vcpus;

This doesn't need to be globally visible.

>  static bool irq_affinity;
>  static bool block_vcpus;
>  static bool done;
> @@ -67,12 +69,23 @@ static void *vcpu_thread_main(void *arg)
>  	struct kvm_vcpu *vcpu = arg;
>  	struct ucall uc;
>  
> +	WRITE_ONCE(vcpu_tids[vcpu->id], kvm_gettid());

...

> @@ -246,6 +264,14 @@ int main(int argc, char **argv)
>  	 */
>  	irq_cpu = -1;
>  
> +	if (migrate_vcpus) {
> +		kvm_sched_getaffinity(vcpu_tids[0], sizeof(available_cpus), &available_cpus);

This is silly, just use the affinity of the main task.  There's no reason to go
look at a child task's affinity.

> +
> +		if (nr_vcpus > CPU_COUNT(&available_cpus)) {
> +			printf("There are more vCPUs than pCPUs; refusing to migrate.\n");

Why?  Overcommitting vCPUs:pCPUs is quite common, and arguably more interesting
for this test.  And it's not like the test prevents overlap anyways (it is random
after all).

> +			migrate_vcpus = false;
> +		}
> +	}
>  	for (i = 0; i < nr_irqs; i++) {
>  		const bool do_clear_routes = clear_routes && (i & BIT(3));
>  		const bool do_use_nmi = use_nmi && (i & BIT(2));
> @@ -262,6 +288,9 @@ int main(int argc, char **argv)
>  			write_proc_irq_smp_affinity_list(irq_affinity_fp, irq, irq_cpu);
>  		}
>  
> +		if (migrate_vcpus && vcpu->id == 0)
> +			migrate_vcpu_threads(nr_vcpus, vcpu_threads, &available_cpus);

Meh, rather than shuffle everything in a batch, just change the affinity for the
target vCPU.  That makes the code easier to read, and is arguably more interesting
because there's at least some chance the task will be migrated while the interrupt
is being delivered, whereas migrating everything up front means the migrations will
have completed before the interrupt is sent the vast majority of the time.

> +
>  		for (j = 0; j < nr_vcpus; j++) {
>  			TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
>  				    "IRQ flag for vCPU %d not clear prior to test",
> -- 
> 2.54.0.1032.g2f8565e1d1-goog
> 

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

* Re: [PATCH v5 19/21] KVM: selftests: Print vCPU affinity on timeout during IRQ test
  2026-06-04  2:21   ` sashiko-bot
@ 2026-06-04 17:28     ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:28 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Josh Hilke, kvm

On Thu, Jun 04, 2026, sashiko-bot@kernel.org wrote:
> > +void kvm_print_vcpu_affinity(struct kvm_vcpu *vcpu, pid_t tid)
> > +{
> > +	int nprocs = get_nprocs();
> > +	bool first_range = true;
> > +	int i, start = -1;
> > +	cpu_set_t cpus;
> > +
> > +	kvm_sched_getaffinity(tid, sizeof(cpus), &cpus);
> > +
> > +	/*
> > +	 * Output format examples:
> > +	 * - Single CPU:  "vCPU 0 (TID 1234) affined to pCPU(s): 2"
> > +	 * - List:        "vCPU 0 (TID 1234) affined to pCPU(s): 0,2,4"
> > +	 * - Range:       "vCPU 0 (TID 1234) affined to pCPU(s): 0-7"
> > +	 * - Mixed:       "vCPU 0 (TID 1234) affined to pCPU(s): 0-3,8,10-12"
> > +	 */
> > +	printf("vCPU %u (TID %d) affined to pCPU(s): ", vcpu->id, tid);
> > +
> > +	for (i = 0; i <= nprocs; i++) {
> > +		/*
> > +		 * Iterate to nprocs (inclusive) to ensure that if the last pCPU
> > +		 * is part of a range, the 'else' block triggers one final time
> > +		 * to flush that range to stdout.
> > +		 */
> > +		if (i < nprocs && CPU_ISSET(i, &cpus)) {
> 
> [Severity: Medium]
> Does using get_nprocs() as the loop boundary risk silently truncating CPUs 
> on sparse topologies?
> 
> get_nprocs() returns the count of currently online CPUs, not the maximum 
> CPU ID. If a system has 4 online CPUs but their IDs are 0, 1, 2, and 7, 
> get_nprocs() will return 4.
> 
> This would cause the loop to terminate prematurely, completely ignoring 
> valid but higher-numbered CPU indices (like CPU 7) in the cpu_set_t mask.
> 
> Should this iterate up to CPU_SETSIZE instead to encompass the entire mask 
> capacity, similar to other helper functions like pin_task_to_random_cpu()?

I'm going to skip this one for now, too.

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

* Re: [PATCH v5 20/21] KVM: selftests: Make number of vCPUs configurable in IRQ test
  2026-06-04  2:20   ` sashiko-bot
@ 2026-06-04 17:29     ` Sean Christopherson
  2026-06-04 17:41       ` Sean Christopherson
  0 siblings, 1 reply; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:29 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Josh Hilke, kvm

On Thu, Jun 04, 2026, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] Missing bounds check on user-supplied `nr_vcpus` allows stack buffer overflows and out-of-bounds global array accesses.
> --
> 
> commit 115e22303a8d11509c805d6bfdcdbd39b670c16d
> Author: David Matlack <dmatlack@google.com>
> 
> KVM: selftests: Make number of vCPUs configurable in IRQ test
> 
> This commit adds a '-v' flag to tools/testing/selftests/kvm/irq_test.c,
> allowing users to configure the number of vCPUs to run in the test.
> 
> > diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
> > index 1d66293b6d0b8..41c50caa928e2 100644
> > --- a/tools/testing/selftests/kvm/irq_test.c
> > +++ b/tools/testing/selftests/kvm/irq_test.c
> [ ... ]
> > @@ -213,6 +214,9 @@ int main(int argc, char **argv)
> >  		case 'n':
> >  			use_nmi = true;
> >  			break;
> > +		case 'v':
> > +			nr_vcpus = atoi_positive("Number of vCPUS", optarg);
> 
> [Severity: Medium]
> Does this code need a bounds check for nr_vcpus against KVM_MAX_VCPUS?

Yep.  It also needs to configure the test to enable x2APIC format and disable
KVM's broadcast quirk, otherwise running with 255+ vCPUs will fail due to KVM
blasting an IRQ to all vCPUs when trying to target vCPU 255.

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

* Re: [PATCH v5 21/21] KVM: selftests: Add xAPIC support in IRQ test
  2026-06-04  2:22   ` sashiko-bot
@ 2026-06-04 17:34     ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:34 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Josh Hilke, kvm

On Thu, Jun 04, 2026, sashiko-bot@kernel.org wrote:
> > diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
> > index 41c50caa928e2..7e421cb7bc69b 100644
> > --- a/tools/testing/selftests/kvm/irq_test.c
> > +++ b/tools/testing/selftests/kvm/irq_test.c
> [ ... ]
> > @@ -31,14 +32,20 @@ static bool done;
> >  
> >  static u32 guest_get_vcpu_id(void)
> >  {
> > -	return x2apic_read_reg(APIC_ID);
> > +	if (x2apic)
> > +		return x2apic_read_reg(APIC_ID);
> > +	else
> > +		return xapic_read_reg(APIC_ID) >> 24;
> >  }
> 
> [Severity: Medium]
> Does this truncation to 8 bits cause the test to silently hang if run with
> 256 or more vCPUs in xAPIC mode?

Yep.

> For vCPU IDs 256 and above, the 8-bit xAPIC ID will wrap around.

But not because of wraparound (it's amusing how bad AI is at basic math, when
it's so good with advanced stuff).  The test will use IDs [0-255], not [1-256].
The limit with xAPIC is specifically 255 vCPUs, not 256, because 0xff (i.e. ID
255) is a special broadcast value.

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

* Re: [PATCH v5 13/21] KVM: selftests: Make number of IRQs configurable in IRQ test
  2026-06-04  2:01 ` [PATCH v5 13/21] KVM: selftests: Make number of IRQs configurable " Josh Hilke
@ 2026-06-04 17:35   ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:35 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Josh Hilke wrote:
> From: David Matlack <dmatlack@google.com>
> 
> Add a '-i' flag to tools/testing/selftests/kvm/irq_test.c to allow users

Don't spell out the path in the changelog, I can see that from the diff.  Write
changelogs using conversational language.  E.g. most people won't describe a
change like this as "modify tools slash testing slash selftests slash KVM
slash IRQ test dot C", they'd say something like "modify the IRQ test".

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

* Re: [PATCH v5 20/21] KVM: selftests: Make number of vCPUs configurable in IRQ test
  2026-06-04 17:29     ` Sean Christopherson
@ 2026-06-04 17:41       ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:41 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Josh Hilke, kvm

On Thu, Jun 04, 2026, Sean Christopherson wrote:
> On Thu, Jun 04, 2026, sashiko-bot@kernel.org wrote:
> > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> > - [Medium] Missing bounds check on user-supplied `nr_vcpus` allows stack buffer overflows and out-of-bounds global array accesses.
> > --
> > 
> > commit 115e22303a8d11509c805d6bfdcdbd39b670c16d
> > Author: David Matlack <dmatlack@google.com>
> > 
> > KVM: selftests: Make number of vCPUs configurable in IRQ test
> > 
> > This commit adds a '-v' flag to tools/testing/selftests/kvm/irq_test.c,
> > allowing users to configure the number of vCPUs to run in the test.
> > 
> > > diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
> > > index 1d66293b6d0b8..41c50caa928e2 100644
> > > --- a/tools/testing/selftests/kvm/irq_test.c
> > > +++ b/tools/testing/selftests/kvm/irq_test.c
> > [ ... ]
> > > @@ -213,6 +214,9 @@ int main(int argc, char **argv)
> > >  		case 'n':
> > >  			use_nmi = true;
> > >  			break;
> > > +		case 'v':
> > > +			nr_vcpus = atoi_positive("Number of vCPUS", optarg);
> > 
> > [Severity: Medium]
> > Does this code need a bounds check for nr_vcpus against KVM_MAX_VCPUS?
> 
> Yep.  It also needs to configure the test to enable x2APIC format and disable
> KVM's broadcast quirk, otherwise running with 255+ vCPUs will fail due to KVM
> blasting an IRQ to all vCPUs when trying to target vCPU 255.

Oh, and the routing logic needs to be updated to actually shove ID[31:8] into the
correct field.

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

* Re: [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test
  2026-06-04  2:01 ` [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test Josh Hilke
  2026-06-04 16:22   ` Sean Christopherson
@ 2026-06-04 17:56   ` Sean Christopherson
  2026-06-04 19:25     ` Sean Christopherson
  1 sibling, 1 reply; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 17:56 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

The shortlog is at best misleading.  There are zero guarantees that IRQ bypass
is supported and enabled.

On Thu, Jun 04, 2026, Josh Hilke wrote:
> From: David Matlack <dmatlack@google.com>
> 
> Trigger interrupts from a VFIO device instead of emulating interrupts

It's not emulating, it's synthesizing.  Emulating implies there's a device of
some kind that the test is mimicking.

> using KVM eventfds. This verifies that guests receive interrupts via IRQ
> bypass.

No, it verifies that delivery of a VFIO MSI-X through VFIO=>KVM works, and *may*
verify IRQ bypass.  And all of that very much relies on the eventfds to be in
place.

> @@ -119,7 +160,17 @@ int main(int argc, char **argv)
>  	vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
>  	vm_install_exception_handler(vm, vector, guest_irq_handler);
>  
> -	eventfd = kvm_new_eventfd();
> +	if (device_bdf) {
> +		iommu = iommu_init(default_iommu_mode);

This needs:

diff --git tools/testing/selftests/kvm/irq_test.c tools/testing/selftests/kvm/irq_test.c
index cf4568718cee..2e7e100d4815 100644
--- tools/testing/selftests/kvm/irq_test.c
+++ tools/testing/selftests/kvm/irq_test.c
@@ -235,6 +235,8 @@ int main(int argc, char **argv)
        }
 
        if (device_bdf) {
+               __open_path_or_exit("/dev/iommu", O_RDONLY, "Is IOMMUFD available?");
+
                iommu = iommu_init(default_iommu_mode);
                device = vfio_pci_device_init(device_bdf, iommu);
                msix = vfio_setup_msi(device);

So that the test skips instead of failing, and to provide a helpful message:

  1..0 # SKIP - Cannot open '/dev/iommu': No such file or directory.  Is IOMMUFD available?

Because bluntly, the assert from the VFIO infrastructure is awful:

  tools/testing/selftests/vfio/lib/iommu.c:448: Assertion Failure

  Expression: iommu->iommufd > 0
  Observed: 0xffffffffffffffff > 0
  [errno: 2 - No such file or directory]

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

* Re: [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test
  2026-06-04 17:56   ` Sean Christopherson
@ 2026-06-04 19:25     ` Sean Christopherson
  2026-06-04 19:52       ` Sean Christopherson
  2026-06-04 23:14       ` Sean Christopherson
  0 siblings, 2 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 19:25 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Sean Christopherson wrote:
> The shortlog is at best misleading.  There are zero guarantees that IRQ bypass
> is supported and enabled.
> 
> On Thu, Jun 04, 2026, Josh Hilke wrote:
> > From: David Matlack <dmatlack@google.com>
> > 
> > Trigger interrupts from a VFIO device instead of emulating interrupts
> 
> It's not emulating, it's synthesizing.  Emulating implies there's a device of
> some kind that the test is mimicking.
> 
> > using KVM eventfds. This verifies that guests receive interrupts via IRQ
> > bypass.
> 
> No, it verifies that delivery of a VFIO MSI-X through VFIO=>KVM works, and *may*
> verify IRQ bypass.  And all of that very much relies on the eventfds to be in
> place.
> 
> > @@ -119,7 +160,17 @@ int main(int argc, char **argv)
> >  	vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
> >  	vm_install_exception_handler(vm, vector, guest_irq_handler);
> >  
> > -	eventfd = kvm_new_eventfd();
> > +	if (device_bdf) {
> > +		iommu = iommu_init(default_iommu_mode);
> 
> This needs:
> 
> diff --git tools/testing/selftests/kvm/irq_test.c tools/testing/selftests/kvm/irq_test.c
> index cf4568718cee..2e7e100d4815 100644
> --- tools/testing/selftests/kvm/irq_test.c
> +++ tools/testing/selftests/kvm/irq_test.c
> @@ -235,6 +235,8 @@ int main(int argc, char **argv)
>         }
>  
>         if (device_bdf) {
> +               __open_path_or_exit("/dev/iommu", O_RDONLY, "Is IOMMUFD available?");
> +
>                 iommu = iommu_init(default_iommu_mode);

*sigh* 

<rant>
This is beyond frustating.  I have A PERFECTLY FUNCTIONAL KERNEL, but this test
VERY SUBTLY "defaults" to IOMMUFD.  ARGH!!!!!

And to make matters worse, if I enable CONFIG_IOMMUFD, but don't enable
CONFIG_VFIO_DEVICE_CDEV, then AFAICT, I can't do a damn thing with VFIO.  I dunno,
I can't get IOMMUFD to work even with that.

Worst of all, the changelog SAYS BLOODY NOTHING ABOUT THIS.
</rant>

Please, for the love of all that is holy, when sending stuff upstream, think about
how your code will impact people and environments outside the world of Google.
And more importantly, *test* your code beyond Google's highly curated environment.

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

* Re: [PATCH v5 08/21] KVM: selftests: Add helpers to write proc IRQ affinity for IRQ test
  2026-06-04  2:01 ` [PATCH v5 08/21] KVM: selftests: Add helpers to write proc IRQ affinity for " Josh Hilke
  2026-06-04  2:09   ` sashiko-bot
@ 2026-06-04 19:35   ` Sean Christopherson
  1 sibling, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 19:35 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Josh Hilke wrote:
> diff --git a/tools/testing/selftests/kvm/lib/proc_util.c b/tools/testing/selftests/kvm/lib/proc_util.c
> index 84d30f055a0a..938c90d94f4d 100644
> --- a/tools/testing/selftests/kvm/lib/proc_util.c
> +++ b/tools/testing/selftests/kvm/lib/proc_util.c
> @@ -38,3 +38,23 @@ unsigned int vfio_msix_to_host_irq(const char *device_bdf, int msix)
>  	return (unsigned int)irq;
>  }
>  
> +FILE *open_proc_irq_smp_affinity_list(unsigned int irq)
> +{
> +	char path[PATH_MAX];
> +	FILE *fp;
> +
> +	snprintf(path, sizeof(path), "/proc/irq/%u/smp_affinity_list", irq);
> +	fp = fopen(path, "w");
> +	TEST_ASSERT(fp, "fopen(%s) failed", path);
> +
> +	return fp;
> +}
> +
> +void write_proc_irq_smp_affinity_list(FILE *fp, unsigned int irq, int irq_cpu)
> +{
> +	int ret;
> +
> +	ret = fprintf(fp, "%d\n", irq_cpu);
> +	TEST_ASSERT(ret > 0, "Failed to affinitize IRQ-%u to CPU %d", irq, irq_cpu);
> +	fflush(fp);

As Sashiko points out, this is prone to failing silently.  But rather than just
"fix" that issue, this can be simplified to avoid the complexity of flushing
buffers in the first place.

That will also allow fixing another flaw: if the caller passes in the wrong,
file, debugging the resulting failure will be annoying.  I see no reason to
risk that, it's not like opening a single file is going to meaningfully impact
overall runtime.

All in all, just this?

void proc_irq_set_smp_affinity(unsigned int irq, int cpu)
{
	char path[PATH_MAX];
	int r, fd;

	snprintf(path, sizeof(path), "/proc/irq/%u/smp_affinity_list", irq);
	fd = open(path, O_RDWR);
	TEST_ASSERT(fd >= 0, "Failed to open %s", path);

	r = dprintf(fd, "%d\n", cpu);
	TEST_ASSERT(r > 0, "Failed to affinitize IRQ-%u to CPU %d", irq, cpu);

	kvm_close(fd);
}

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

* Re: [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test
  2026-06-04 19:25     ` Sean Christopherson
@ 2026-06-04 19:52       ` Sean Christopherson
  2026-06-04 23:14       ` Sean Christopherson
  1 sibling, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 19:52 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Sean Christopherson wrote:
> On Thu, Jun 04, 2026, Sean Christopherson wrote:
> > diff --git tools/testing/selftests/kvm/irq_test.c tools/testing/selftests/kvm/irq_test.c
> > index cf4568718cee..2e7e100d4815 100644
> > --- tools/testing/selftests/kvm/irq_test.c
> > +++ tools/testing/selftests/kvm/irq_test.c
> > @@ -235,6 +235,8 @@ int main(int argc, char **argv)
> >         }
> >  
> >         if (device_bdf) {
> > +               __open_path_or_exit("/dev/iommu", O_RDONLY, "Is IOMMUFD available?");
> > +
> >                 iommu = iommu_init(default_iommu_mode);
> 
> *sigh* 
> 
> <rant>
> This is beyond frustating.  I have A PERFECTLY FUNCTIONAL KERNEL, but this test
> VERY SUBTLY "defaults" to IOMMUFD.  ARGH!!!!!
> 
> And to make matters worse, if I enable CONFIG_IOMMUFD, but don't enable
> CONFIG_VFIO_DEVICE_CDEV, then AFAICT, I can't do a damn thing with VFIO.  I dunno,
> I can't get IOMMUFD to work even with that.
> 
> Worst of all, the changelog SAYS BLOODY NOTHING ABOUT THIS.
> </rant>

Turns out the DSA SPR device is on VFIO's naughty list:

  vfio-pci 0000:6a:01.0: 8086:0b25 exists in vfio-pci device denylist, driver probing disallowed.
  vfio-pci 0000:6a:01.0: probe with driver vfio-pci failed with error -22

Reloading vfio-pci with disable_denylist=1 got things working.

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

* Re: [PATCH v5 06/21] KVM: selftests: Add helper to get host IRQ from device MSIX for IRQ bypass test
  2026-06-04  2:09   ` sashiko-bot
@ 2026-06-04 20:01     ` Sean Christopherson
  0 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 20:01 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Josh Hilke, kvm

On Thu, Jun 04, 2026, sashiko-bot@kernel.org wrote:
> > +unsigned int vfio_msix_to_host_irq(const char *device_bdf, int msix)
> > +{
> > +	char search_string[64];
> > +	char line[4096];
> > +	int irq = -1;
> > +	FILE *fp;
> > +
> > +	fp = open_proc_interrupts();
> > +
> > +	snprintf(search_string, sizeof(search_string), "vfio-msix[%d]", msix);
> > +
> > +	while (fgets(line, sizeof(line), fp)) {
> > +		if (strstr(line, device_bdf) && strstr(line, search_string)) {
> > +			TEST_ASSERT_EQ(1, sscanf(line, "%d:", &irq));
> 
> [Severity: Medium]
> Is the 4096-byte buffer large enough for systems with high core counts?
> 
> In /proc/interrupts, each online CPU gets its own column for interrupt counts.
> On systems with many CPUs, a single line might exceed 4096 bytes. When
> this happens, fgets() reads the line in multiple chunks.
> 
> If the line is chunked, the first chunk contains the IRQ number, and a
> subsequent chunk contains the target device names. The strstr() condition
> would match on the later chunk, but sscanf() would look for the IRQ number
> format at the beginning of that same chunk.
> 
> Since the later chunk lacks the leading IRQ number, sscanf() would return 0,
> which would then cause TEST_ASSERT_EQ to fail and crash the test.

I'm fine punting on this for now.  Crashing is unfortunate, but easy enough to
workaround if someone with a massive system wants to run the test, and more
importantly shouldn't mislead the user.

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

* Re: [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts
  2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
                   ` (20 preceding siblings ...)
  2026-06-04  2:01 ` [PATCH v5 21/21] KVM: selftests: Add xAPIC support " Josh Hilke
@ 2026-06-04 20:22 ` Sean Christopherson
  21 siblings, 0 replies; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 20:22 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Josh Hilke wrote:
> This is v5 of a series which introduces tools/testing/selftests/kvm/irq_test.c
> in KVM selftests. This test exercises the delivery of interrupts (both
> emulated via eventfd and real from a VFIO device) to guest vCPUs. Beyond basic
> injection, the series adds coverage for several complex scenarios, including:
> - Dynamic updates to KVM's GSI routing table while interrupts are active.
> - Waking up halted vCPUs via interrupts.
> - Stressing interrupt delivery during random host IRQ affinity changes.
> - Stressing interrupt delivery during random vCPU thread migration across
>   physical CPUs.
> - Testing non-postable interrupt remapping (using NMIs to force transitions).
> - Supporting both xAPIC and x2APIC modes in the guest.
> 
> The series also links the VFIO selftests library into KVM selftests to enable
> testing of VFIO-KVM interactions.

Lots of comments and changes.  I'll send a v6 (maybe later today, but probably
tomorrow).  I have all the changes made locally, and the test is passing for me.

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

* Re: [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test
  2026-06-04 19:25     ` Sean Christopherson
  2026-06-04 19:52       ` Sean Christopherson
@ 2026-06-04 23:14       ` Sean Christopherson
  2026-06-04 23:35         ` David Matlack
  1 sibling, 1 reply; 54+ messages in thread
From: Sean Christopherson @ 2026-06-04 23:14 UTC (permalink / raw)
  To: Josh Hilke
  Cc: Paolo Bonzini, kvm, linux-kernel, David Matlack, Alex Williamson

On Thu, Jun 04, 2026, Sean Christopherson wrote:
> On Thu, Jun 04, 2026, Sean Christopherson wrote:
> > The shortlog is at best misleading.  There are zero guarantees that IRQ bypass
> > is supported and enabled.
> > 
> > On Thu, Jun 04, 2026, Josh Hilke wrote:
> > > From: David Matlack <dmatlack@google.com>
> > > 
> > > Trigger interrupts from a VFIO device instead of emulating interrupts
> > 
> > It's not emulating, it's synthesizing.  Emulating implies there's a device of
> > some kind that the test is mimicking.
> > 
> > > using KVM eventfds. This verifies that guests receive interrupts via IRQ
> > > bypass.
> > 
> > No, it verifies that delivery of a VFIO MSI-X through VFIO=>KVM works, and *may*
> > verify IRQ bypass.  And all of that very much relies on the eventfds to be in
> > place.
> > 
> > > @@ -119,7 +160,17 @@ int main(int argc, char **argv)
> > >  	vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
> > >  	vm_install_exception_handler(vm, vector, guest_irq_handler);
> > >  
> > > -	eventfd = kvm_new_eventfd();
> > > +	if (device_bdf) {
> > > +		iommu = iommu_init(default_iommu_mode);
> > 
> > This needs:
> > 
> > diff --git tools/testing/selftests/kvm/irq_test.c tools/testing/selftests/kvm/irq_test.c
> > index cf4568718cee..2e7e100d4815 100644
> > --- tools/testing/selftests/kvm/irq_test.c
> > +++ tools/testing/selftests/kvm/irq_test.c
> > @@ -235,6 +235,8 @@ int main(int argc, char **argv)
> >         }
> >  
> >         if (device_bdf) {
> > +               __open_path_or_exit("/dev/iommu", O_RDONLY, "Is IOMMUFD available?");
> > +
> >                 iommu = iommu_init(default_iommu_mode);
> 
> *sigh* 
> 
> <rant>
> This is beyond frustating.  I have A PERFECTLY FUNCTIONAL KERNEL, but this test
> VERY SUBTLY "defaults" to IOMMUFD.  ARGH!!!!!

Ok, here's what I ended up with.  A param to let the user force a specific type:

	printf("-t	Override the IOMMU type to use (vfio_type1_iommu or iommufd)\n");


And then auto-probe logic to make a halfway decent guess as to which type/mode
to use.

  static const char *probe_iommu_type(void)
  {
	int io_fd;

	io_fd = open("/dev/iommu", O_RDONLY);
	if (io_fd >= 0) {
		close(io_fd);
		return MODE_IOMMUFD;
	}

	io_fd = __open_path_or_exit("/dev/vfio", O_RDONLY,
				    "Is VFIO (or IOMMUFD) loaded and enabled?");
	close(io_fd);
	return MODE_VFIO_TYPE1_IOMMU;
  }

...

		if (!iommu_type)
			iommu_type = probe_iommu_type();

I'll probably throw a TODO in there, because the VFIO/IOMMU infrastructure really
needs to handle this, *especially* since "default_iommu_mode" is globally visible.
Hardcoding a "default" to an entirely optional thing is just evil.

E.g. instead of iommu_init() => lookup_iommu_mode() using default_iommu_mode when
passed a NULL pointer, have it choose the type that's most likely to work.  Then
the IRQ test can drop its probing logic.

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

* Re: [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test
  2026-06-04 23:14       ` Sean Christopherson
@ 2026-06-04 23:35         ` David Matlack
  0 siblings, 0 replies; 54+ messages in thread
From: David Matlack @ 2026-06-04 23:35 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Josh Hilke, Paolo Bonzini, kvm, linux-kernel, Alex Williamson

On Thu, Jun 4, 2026 at 4:14 PM Sean Christopherson <seanjc@google.com> wrote:
>
> On Thu, Jun 04, 2026, Sean Christopherson wrote:
> > On Thu, Jun 04, 2026, Sean Christopherson wrote:
> > > The shortlog is at best misleading.  There are zero guarantees that IRQ bypass
> > > is supported and enabled.
> > >
> > > On Thu, Jun 04, 2026, Josh Hilke wrote:
> > > > From: David Matlack <dmatlack@google.com>
> > > >
> > > > Trigger interrupts from a VFIO device instead of emulating interrupts
> > >
> > > It's not emulating, it's synthesizing.  Emulating implies there's a device of
> > > some kind that the test is mimicking.
> > >
> > > > using KVM eventfds. This verifies that guests receive interrupts via IRQ
> > > > bypass.
> > >
> > > No, it verifies that delivery of a VFIO MSI-X through VFIO=>KVM works, and *may*
> > > verify IRQ bypass.  And all of that very much relies on the eventfds to be in
> > > place.
> > >
> > > > @@ -119,7 +160,17 @@ int main(int argc, char **argv)
> > > >   vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
> > > >   vm_install_exception_handler(vm, vector, guest_irq_handler);
> > > >
> > > > - eventfd = kvm_new_eventfd();
> > > > + if (device_bdf) {
> > > > +         iommu = iommu_init(default_iommu_mode);
> > >
> > > This needs:
> > >
> > > diff --git tools/testing/selftests/kvm/irq_test.c tools/testing/selftests/kvm/irq_test.c
> > > index cf4568718cee..2e7e100d4815 100644
> > > --- tools/testing/selftests/kvm/irq_test.c
> > > +++ tools/testing/selftests/kvm/irq_test.c
> > > @@ -235,6 +235,8 @@ int main(int argc, char **argv)
> > >         }
> > >
> > >         if (device_bdf) {
> > > +               __open_path_or_exit("/dev/iommu", O_RDONLY, "Is IOMMUFD available?");
> > > +
> > >                 iommu = iommu_init(default_iommu_mode);
> >
> > *sigh*
> >
> > <rant>
> > This is beyond frustating.  I have A PERFECTLY FUNCTIONAL KERNEL, but this test
> > VERY SUBTLY "defaults" to IOMMUFD.  ARGH!!!!!
>
> Ok, here's what I ended up with.  A param to let the user force a specific type:
>
>         printf("-t      Override the IOMMU type to use (vfio_type1_iommu or iommufd)\n");
>
>
> And then auto-probe logic to make a halfway decent guess as to which type/mode
> to use.
>
>   static const char *probe_iommu_type(void)
>   {
>         int io_fd;
>
>         io_fd = open("/dev/iommu", O_RDONLY);
>         if (io_fd >= 0) {
>                 close(io_fd);
>                 return MODE_IOMMUFD;
>         }
>
>         io_fd = __open_path_or_exit("/dev/vfio", O_RDONLY,
>                                     "Is VFIO (or IOMMUFD) loaded and enabled?");
>         close(io_fd);
>         return MODE_VFIO_TYPE1_IOMMU;
>   }
>
> ...
>
>                 if (!iommu_type)
>                         iommu_type = probe_iommu_type();
>
> I'll probably throw a TODO in there, because the VFIO/IOMMU infrastructure really
> needs to handle this, *especially* since "default_iommu_mode" is globally visible.
> Hardcoding a "default" to an entirely optional thing is just evil.
>
> E.g. instead of iommu_init() => lookup_iommu_mode() using default_iommu_mode when
> passed a NULL pointer, have it choose the type that's most likely to work.  Then
> the IRQ test can drop its probing logic.

Yeah, choosing the default IOMMU type is something the VFIO selftests
library can provide better helpers for. Feel free to leave a TODO to
replace this.

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

end of thread, other threads:[~2026-06-04 23:36 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-04  2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
2026-06-04  2:01 ` [PATCH v5 01/21] KVM: selftests: Build and link selftests/vfio/lib into KVM selftests Josh Hilke
2026-06-04  2:01 ` [PATCH v5 02/21] KVM: selftests: Add guest read/write macros Josh Hilke
2026-06-04  2:01 ` [PATCH v5 03/21] KVM: selftests: Rename guest_rng to kvm_rng Josh Hilke
2026-06-04  2:01 ` [PATCH v5 04/21] KVM: selftests: Add helper to generate random u64 in range [min,max] Josh Hilke
2026-06-04  2:12   ` sashiko-bot
2026-06-04 16:12     ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 05/21] KVM: selftests: Add IRQ injection test Josh Hilke
2026-06-04 16:19   ` Sean Christopherson
2026-06-04 16:26     ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 06/21] KVM: selftests: Add helper to get host IRQ from device MSIX for IRQ bypass test Josh Hilke
2026-06-04  2:09   ` sashiko-bot
2026-06-04 20:01     ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test Josh Hilke
2026-06-04 16:22   ` Sean Christopherson
2026-06-04 17:56   ` Sean Christopherson
2026-06-04 19:25     ` Sean Christopherson
2026-06-04 19:52       ` Sean Christopherson
2026-06-04 23:14       ` Sean Christopherson
2026-06-04 23:35         ` David Matlack
2026-06-04  2:01 ` [PATCH v5 08/21] KVM: selftests: Add helpers to write proc IRQ affinity for " Josh Hilke
2026-06-04  2:09   ` sashiko-bot
2026-06-04 19:35   ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 09/21] KVM: selftests: Add helpers to print " Josh Hilke
2026-06-04  2:09   ` sashiko-bot
2026-06-04 17:17     ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 10/21] KVM: selftests: Verify interrupts are received when IRQ affinity changes in " Josh Hilke
2026-06-04  2:13   ` sashiko-bot
2026-06-04  2:01 ` [PATCH v5 11/21] KVM: selftests: Verify IRQs wake up halted vCPUs " Josh Hilke
2026-06-04  2:15   ` sashiko-bot
2026-06-04 16:11     ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 12/21] KVM: selftests: Verify interrupts are received after modifying IRQ routes " Josh Hilke
2026-06-04 17:22   ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 13/21] KVM: selftests: Make number of IRQs configurable " Josh Hilke
2026-06-04 17:35   ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 14/21] KVM: selftests: Verify non-postable IRQ remapping " Josh Hilke
2026-06-04 17:22   ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 15/21] KVM: selftests: Add kvm_gettid() wrapper and convert users Josh Hilke
2026-06-04  2:01 ` [PATCH v5 16/21] KVM: selftests: Add kvm_sched_getaffinity() " Josh Hilke
2026-06-04 17:23   ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 17/21] KVM: selftests: Add pin_task_to_random_cpu() helper function for IRQ test Josh Hilke
2026-06-04  2:01 ` [PATCH v5 18/21] KVM: selftests: Verify vCPU migration during IRQ delivery in " Josh Hilke
2026-06-04 17:27   ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 19/21] KVM: selftests: Print vCPU affinity on timeout during " Josh Hilke
2026-06-04  2:21   ` sashiko-bot
2026-06-04 17:28     ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 20/21] KVM: selftests: Make number of vCPUs configurable in " Josh Hilke
2026-06-04  2:20   ` sashiko-bot
2026-06-04 17:29     ` Sean Christopherson
2026-06-04 17:41       ` Sean Christopherson
2026-06-04  2:01 ` [PATCH v5 21/21] KVM: selftests: Add xAPIC support " Josh Hilke
2026-06-04  2:22   ` sashiko-bot
2026-06-04 17:34     ` Sean Christopherson
2026-06-04 20:22 ` [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Sean Christopherson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.