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 
13 static struct kvm_vm *vm1;
14 static struct kvm_vm *vm2;
15 static int __eventfd;
16 static 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 
juggle_eventfd_secondary(struct kvm_vm * vm,int eventfd)28 static 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 
secondary_irqfd_juggler(void * ign)53 static 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 
juggle_eventfd_primary(struct kvm_vm * vm,int eventfd)63 static 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 
main(int argc,char * argv[])89 int main(int argc, char *argv[])
90 {
91 	pthread_t racing_thread;
92 	int r, i;
93 
94 	/* Create "full" VMs, as KVM_IRQFD requires an in-kernel IRQ chip. */
95 	vm1 = vm_create(1);
96 	vm2 = vm_create(1);
97 
98 	WRITE_ONCE(__eventfd, kvm_new_eventfd());
99 
100 	kvm_irqfd(vm1, 10, __eventfd, 0);
101 
102 	r = __kvm_irqfd(vm1, 11, __eventfd, 0);
103 	TEST_ASSERT(r && errno == EBUSY,
104 		    "Wanted EBUSY, r = %d, errno = %d", r, errno);
105 
106 	r = __kvm_irqfd(vm2, 12, __eventfd, 0);
107 	TEST_ASSERT(r && errno == EBUSY,
108 		    "Wanted EBUSY, r = %d, errno = %d", r, errno);
109 
110 	/*
111 	 * De-assign all eventfds, along with multiple eventfds that were never
112 	 * assigned.  KVM's ABI is that de-assign is allowed so long as the
113 	 * eventfd itself is valid.
114 	 */
115 	kvm_irqfd(vm1, 11, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);
116 	kvm_irqfd(vm1, 12, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);
117 	kvm_irqfd(vm1, 13, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);
118 	kvm_irqfd(vm1, 14, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);
119 	kvm_irqfd(vm1, 10, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);
120 
121 	close(__eventfd);
122 
123 	pthread_create(&racing_thread, NULL, secondary_irqfd_juggler, vm2);
124 
125 	for (i = 0; i < 10000; i++) {
126 		WRITE_ONCE(__eventfd, kvm_new_eventfd());
127 
128 		juggle_eventfd_primary(vm1, __eventfd);
129 		juggle_eventfd_primary(vm2, __eventfd);
130 		close(__eventfd);
131 	}
132 
133 	WRITE_ONCE(done, true);
134 	pthread_join(racing_thread, NULL);
135 }
136