Path: blob/master/tools/testing/selftests/kvm/irqfd_test.c
38189 views
// SPDX-License-Identifier: GPL-2.0-only1#include <errno.h>2#include <pthread.h>3#include <stdio.h>4#include <stdlib.h>5#include <string.h>6#include <signal.h>7#include <stdint.h>8#include <sys/sysinfo.h>910#include "kvm_util.h"1112static struct kvm_vm *vm1;13static struct kvm_vm *vm2;14static int __eventfd;15static bool done;1617/*18* KVM de-assigns based on eventfd *and* GSI, but requires unique eventfds when19* assigning (the API isn't symmetrical). Abuse the oddity and use a per-task20* GSI base to avoid false failures due to cross-task de-assign, i.e. so that21* the secondary doesn't de-assign the primary's eventfd and cause assign to22* unexpectedly succeed on the primary.23*/24#define GSI_BASE_PRIMARY 0x2025#define GSI_BASE_SECONDARY 0x302627static void juggle_eventfd_secondary(struct kvm_vm *vm, int eventfd)28{29int r, i;3031/*32* The secondary task can encounter EBADF since the primary can close33* the eventfd at any time. And because the primary can recreate the34* eventfd, at the safe fd in the file table, the secondary can also35* encounter "unexpected" success, e.g. if the close+recreate happens36* between the first and second assignments. The secondary's role is37* mostly to antagonize KVM, not to detect bugs.38*/39for (i = 0; i < 2; i++) {40r = __kvm_irqfd(vm, GSI_BASE_SECONDARY, eventfd, 0);41TEST_ASSERT(!r || errno == EBUSY || errno == EBADF,42"Wanted success, EBUSY, or EBADF, r = %d, errno = %d",43r, errno);4445/* De-assign should succeed unless the eventfd was closed. */46r = __kvm_irqfd(vm, GSI_BASE_SECONDARY + i, eventfd, KVM_IRQFD_FLAG_DEASSIGN);47TEST_ASSERT(!r || errno == EBADF,48"De-assign should succeed unless the fd was closed");49}50}5152static void *secondary_irqfd_juggler(void *ign)53{54while (!READ_ONCE(done)) {55juggle_eventfd_secondary(vm1, READ_ONCE(__eventfd));56juggle_eventfd_secondary(vm2, READ_ONCE(__eventfd));57}5859return NULL;60}6162static void juggle_eventfd_primary(struct kvm_vm *vm, int eventfd)63{64int r1, r2;6566/*67* At least one of the assigns should fail. KVM disallows assigning a68* single eventfd to multiple GSIs (or VMs), so it's possible that both69* assignments can fail, too.70*/71r1 = __kvm_irqfd(vm, GSI_BASE_PRIMARY, eventfd, 0);72TEST_ASSERT(!r1 || errno == EBUSY,73"Wanted success or EBUSY, r = %d, errno = %d", r1, errno);7475r2 = __kvm_irqfd(vm, GSI_BASE_PRIMARY + 1, eventfd, 0);76TEST_ASSERT(r1 || (r2 && errno == EBUSY),77"Wanted failure (EBUSY), r1 = %d, r2 = %d, errno = %d",78r1, r2, errno);7980/*81* De-assign should always succeed, even if the corresponding assign82* failed.83*/84kvm_irqfd(vm, GSI_BASE_PRIMARY, eventfd, KVM_IRQFD_FLAG_DEASSIGN);85kvm_irqfd(vm, GSI_BASE_PRIMARY + 1, eventfd, KVM_IRQFD_FLAG_DEASSIGN);86}8788int main(int argc, char *argv[])89{90pthread_t racing_thread;91struct kvm_vcpu *unused;92int r, i;9394TEST_REQUIRE(kvm_arch_has_default_irqchip());9596/*97* Create "full" VMs, as KVM_IRQFD requires an in-kernel IRQ chip. Also98* create an unused vCPU as certain architectures (like arm64) need to99* complete IRQ chip initialization after all possible vCPUs for a VM100* have been created.101*/102vm1 = vm_create_with_one_vcpu(&unused, NULL);103vm2 = vm_create_with_one_vcpu(&unused, NULL);104105WRITE_ONCE(__eventfd, kvm_new_eventfd());106107kvm_irqfd(vm1, 10, __eventfd, 0);108109r = __kvm_irqfd(vm1, 11, __eventfd, 0);110TEST_ASSERT(r && errno == EBUSY,111"Wanted EBUSY, r = %d, errno = %d", r, errno);112113r = __kvm_irqfd(vm2, 12, __eventfd, 0);114TEST_ASSERT(r && errno == EBUSY,115"Wanted EBUSY, r = %d, errno = %d", r, errno);116117/*118* De-assign all eventfds, along with multiple eventfds that were never119* assigned. KVM's ABI is that de-assign is allowed so long as the120* eventfd itself is valid.121*/122kvm_irqfd(vm1, 11, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);123kvm_irqfd(vm1, 12, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);124kvm_irqfd(vm1, 13, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);125kvm_irqfd(vm1, 14, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);126kvm_irqfd(vm1, 10, READ_ONCE(__eventfd), KVM_IRQFD_FLAG_DEASSIGN);127128close(__eventfd);129130pthread_create(&racing_thread, NULL, secondary_irqfd_juggler, vm2);131132for (i = 0; i < 10000; i++) {133WRITE_ONCE(__eventfd, kvm_new_eventfd());134135juggle_eventfd_primary(vm1, __eventfd);136juggle_eventfd_primary(vm2, __eventfd);137close(__eventfd);138}139140WRITE_ONCE(done, true);141pthread_join(racing_thread, NULL);142}143144145