[PATCH v2 05/14] KVM: selftests: Add support for random host IRQ affinity

Josh Hilke
2026-03-31T19:41:32Z

From: David Matlack <dmatlack@google.com>

Add the '-a' flag to vfio_pci_irq_test 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/.

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

diff --git a/tools/testing/selftests/kvm/vfio_pci_irq_test.c b/tools/testing/selftests/kvm/vfio_pci_irq_test.c
index 6f40b3c2b985..1957d1b7bbf2 100644
--- a/tools/testing/selftests/kvm/vfio_pci_irq_test.c
+++ b/tools/testing/selftests/kvm/vfio_pci_irq_test.c
@@ -88,9 +88,11 @@ static void send_msi(struct vfio_pci_device *device, int msi)

static void help(const char *name)
{
- printf("Usage: %s [-h] segment:bus:device.function\n",
+ printf("Usage: %s [-a] [-h] segment:bus:device.function\n",
name);
printf("\n");
+ printf(" -a: Randomly affinitize the device IRQ to different CPUs\n"
+ " throughout the test.\n");
printf("\n");
exit(KSFT_FAIL);
}
@@ -113,6 +115,7 @@ int main(int argc, char **argv)
u8 vector = 32 + rand() % (UINT8_MAX - 32);

/* Test configuration (overridable by command line flags). */
+ bool irq_affinity = false;
int nr_irqs = 1000;
int nr_vcpus = 1;

@@ -122,13 +125,19 @@ int main(int argc, char **argv)
struct vfio_pci_device *device;
struct iommu *iommu;
const char *device_bdf;
+ FILE *irq_affinity_fp;
int i, j, c, msi, irq;
struct kvm_vm *vm;
+ int irq_cpu;
+ int ret;

device_bdf = vfio_selftests_get_bdf(&argc, argv);

- while ((c = getopt(argc, argv, "h")) != -1) {
+ while ((c = getopt(argc, argv, "ah")) != -1) {
switch (c) {
+ case 'a':
+ irq_affinity = true;
+ break;
case 'h':
default:
help(argv[0]);
@@ -163,6 +172,14 @@ int main(int argc, char **argv)
continue;
}

+ if (irq_affinity) {
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "/proc/irq/%d/smp_affinity_list", irq);
+ irq_affinity_fp = fopen(path, "w");
+ TEST_ASSERT(irq_affinity_fp, "fopen(%s) failed", path);
+ }
+
/* Set a consistent seed so that test are repeatable. */
srand(0);

@@ -172,6 +189,13 @@ int main(int argc, char **argv)

kvm_route_msi(vm, gsi, vcpu, vector);

+ if (irq_affinity && vcpu->id == 0) {
+ irq_cpu = rand() % get_nprocs();
+
+ ret = fprintf(irq_affinity_fp, "%d\n", irq_cpu);
+ TEST_ASSERT(ret > 0, "Failed to affinitize IRQ-%d to CPU %d", irq, irq_cpu);
+ }
+
for (j = 0; j < nr_vcpus; j++) {
TEST_ASSERT(
!READ_FROM_GUEST(vm, guest_received_irq[vcpu->id]),
@@ -189,6 +213,8 @@ int main(int argc, char **argv)
if (timespec_to_ns(timespec_elapsed(start)) > TIMEOUT_NS) {
printf("Timeout waiting for interrupt!\n");
printf(" vCPU: %d\n", vcpu->id);
+ if (irq_affinity)
+ printf(" irq_cpu: %d\n", irq_cpu);

TEST_FAIL("vCPU never received IRQ!\n");
}
@@ -203,6 +229,9 @@ int main(int argc, char **argv)
pthread_join(vcpu_threads[i], NULL);
}

+ if (irq_affinity)
+ fclose(irq_affinity_fp);
+
printf("Host interrupts handled:\n");
printf(" IRQ-%d: %lu\n", irq, get_irq_count(irq) - irq_count);
printf(" Posted-interrupt notification events: %lu\n",
--
2.53.0.1118.gaef5881109-goog