File Index
Files and directories
Sign in
FILE

irqfd_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/kvm/irqfd_test.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2#include <errno.h>
  3#include <pthread.h>
  4#include <stdio.h>
  5#include <stdlib.h>
  6#include <string.h>
  7#include <signal.h>
  8#include <stdint.h>
  9#include <sys/sysinfo.h>
 10
 11#include "kvm_util.h"
 12
 13static struct kvm_vm *vm1;
 14static struct kvm_vm *vm2;
 15static int __eventfd;
 16static bool done;
 17
 18/*
 19 * KVM de-assigns based on eventfd *and* GSI, but requires unique eventfds when
 20 * assigning (the API isn't symmetrical).  Abuse the oddity and use a per-task
 21 * GSI base to avoid false failures due to cross-task de-assign, i.e. so that
 22 * the secondary doesn't de-assign the primary's eventfd and cause assign to
 23 * unexpectedly succeed on the primary.
 24 */
 25#define GSI_BASE_PRIMARY	0x20
 26#define GSI_BASE_SECONDARY	0x30
 27
 28static void juggle_eventfd_secondary(struct kvm_vm *vm, int eventfd)
 29{
 30	int r, i;
 31
 32	/*
 33	 * The secondary task can encounter EBADF since the primary can close
 34	 * the eventfd at any time.  And because the primary can recreate the
 35	 * eventfd, at the safe fd in the file table, the secondary can also
 36	 * encounter "unexpected" success, e.g. if the close+recreate happens
 37	 * between the first and second assignments.  The secondary's role is
 38	 * mostly to antagonize KVM, not to detect bugs.
 39	 */
 40	for (i = 0; i < 2; i++) {
 41		r = __kvm_irqfd(vm, GSI_BASE_SECONDARY, eventfd, 0);
 42		TEST_ASSERT(!r || errno == EBUSY || errno == EBADF,
 43			    "Wanted success, EBUSY, or EBADF, r = %d, errno = %d",
 44			    r, errno);
 45
 46		/* De-assign should succeed unless the eventfd was closed. */
 47		r = __kvm_irqfd(vm, GSI_BASE_SECONDARY + i, eventfd, KVM_IRQFD_FLAG_DEASSIGN);
 48		TEST_ASSERT(!r || errno == EBADF,
 49			    "De-assign should succeed unless the fd was closed");
 50	}
 51}
 52
 53static void *secondary_irqfd_juggler(void *ign)
 54{
 55	while (!READ_ONCE(done)) {
 56		juggle_eventfd_secondary(vm1, READ_ONCE(__eventfd));
 57		juggle_eventfd_secondary(vm2, READ_ONCE(__eventfd));
 58	}
 59
 60	return NULL;
 61}
 62
 63static void juggle_eventfd_primary(struct kvm_vm *vm, int eventfd)
 64{
 65	int r1, r2;
 66
 67	/*
 68	 * At least one of the assigns should fail.  KVM disallows assigning a
 69	 * single eventfd to multiple GSIs (or VMs), so it's possible that both
 70	 * assignments can fail, too.
 71	 */
 72	r1 = __kvm_irqfd(vm, GSI_BASE_PRIMARY, eventfd, 0);
 73	TEST_ASSERT(!r1 || errno == EBUSY,
 74		    "Wanted success or EBUSY, r = %d, errno = %d", r1, errno);
 75
 76	r2 = __kvm_irqfd(vm, GSI_BASE_PRIMARY + 1, eventfd, 0);
 77	TEST_ASSERT(r1 || (r2 && errno == EBUSY),
 78		    "Wanted failure (EBUSY), r1 = %d, r2 = %d, errno = %d",
 79		    r1, r2, errno);
 80
 81	/*
 82	 * De-assign should always succeed, even if the corresponding assign
 83	 * failed.
 84	 */
 85	kvm_irqfd(vm, GSI_BASE_PRIMARY, eventfd, KVM_IRQFD_FLAG_DEASSIGN);
 86	kvm_irqfd(vm, GSI_BASE_PRIMARY + 1, eventfd, KVM_IRQFD_FLAG_DEASSIGN);
 87}
 88
 89int main(int argc, char *argv[])
 90{
 91	pthread_t racing_thread;
 92	struct kvm_vcpu *unused;
 93	int r, i;
 94
 95	TEST_REQUIRE(kvm_arch_has_default_irqchip());
 96
 97	/*
 98	 * Create "full" VMs, as KVM_IRQFD requires an in-kernel IRQ chip. Also
 99	 * create an unused vCPU as certain architectures (like arm64) need to
100	 * complete IRQ chip initialization after all possible vCPUs for a VM
101	 * have been created.
102	 */
103	vm1 = vm_create_with_one_vcpu(&unused, NULL);
104	vm2 = vm_create_with_one_vcpu(&unused, NULL);
105
106	WRITE_ONCE(__eventfd, kvm_new_eventfd());
107
108	kvm_irqfd(vm1, 10, __eventfd, 0);
109
110	r = __kvm_irqfd(vm1, 11, __eventfd, 0);
111	TEST_ASSERT(r && errno == EBUSY,
112		    "Wanted EBUSY, r = %d, errno = %d", r, errno);
113
114	r = __kvm_irqfd(vm2, 12, __eventfd, 0);
115	TEST_ASSERT(r && errno == EBUSY,
116		    "Wanted EBUSY, r = %d, errno = %d", r, errno);
117
118	/*
119	 * De-assign all eventfds, along with multiple eventfds that were never
120	 * assigned.  KVM's ABI is that de-assign is allowed so long as the
121	 * eventfd itself is valid.
122	 */
123	kvm_irqfd(vm1, 11, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);
124	kvm_irqfd(vm1, 12, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);
125	kvm_irqfd(vm1, 13, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);
126	kvm_irqfd(vm1, 14, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);
127	kvm_irqfd(vm1, 10, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);
128
129	close(__eventfd);
130
131	pthread_create(&racing_thread, NULL, secondary_irqfd_juggler, vm2);
132
133	for (i = 0; i < 10000; i++) {
134		WRITE_ONCE(__eventfd, kvm_new_eventfd());
135
136		juggle_eventfd_primary(vm1, __eventfd);
137		juggle_eventfd_primary(vm2, __eventfd);
138		close(__eventfd);
139	}
140
141	WRITE_ONCE(done, true);
142	pthread_join(racing_thread, NULL);
143}
~/ Read-only file preview.