]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: selftests: Define wrappers for common syscalls to assert success
authorSean Christopherson <seanjc@google.com>
Thu, 16 Oct 2025 17:28:47 +0000 (10:28 -0700)
committerSean Christopherson <seanjc@google.com>
Mon, 20 Oct 2025 13:30:42 +0000 (06:30 -0700)
Add kvm_<sycall> wrappers for munmap(), close(), fallocate(), and
ftruncate() to cut down on boilerplate code when a sycall is expected
to succeed, and to make it easier for developers to remember to assert
success.

Implement and use a macro framework similar to the kernel's SYSCALL_DEFINE
infrastructure to further cut down on boilerplate code, and to drastically
reduce the probability of typos as the kernel's syscall definitions can be
copy+paste almost verbatim.

Provide macros to build the raw <sycall>() wrappers as well, e.g. to
replace hand-coded wrappers (NUMA) or pure open-coded calls.

Reviewed-by: Ackerley Tng <ackerleytng@google.com>
Tested-by: Ackerley Tng <ackerleytng@google.com>
Reviewed-by: Shivank Garg <shivankg@amd.com>
Tested-by: Shivank Garg <shivankg@amd.com>
Link: https://lore.kernel.org/r/20251016172853.52451-7-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
tools/testing/selftests/kvm/arm64/vgic_irq.c
tools/testing/selftests/kvm/include/kvm_syscalls.h [new file with mode: 0644]
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/kvm_binary_stats_test.c
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/x86/private_mem_conversions_test.c

index 6338f5bbdb705bb1c0c17d2f19b07702aa609a36..8d7758f12280fcf26712dc713d56c31fd4fe2d7e 100644 (file)
@@ -636,7 +636,7 @@ static void kvm_routing_and_irqfd_check(struct kvm_vm *vm,
        }
 
        for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++)
-               close(fd[f]);
+               kvm_close(fd[f]);
 }
 
 /* handles the valid case: intid=0xffffffff num=1 */
diff --git a/tools/testing/selftests/kvm/include/kvm_syscalls.h b/tools/testing/selftests/kvm/include/kvm_syscalls.h
new file mode 100644 (file)
index 0000000..d4e6131
--- /dev/null
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTEST_KVM_SYSCALLS_H
+#define SELFTEST_KVM_SYSCALLS_H
+
+#include <sys/syscall.h>
+
+#define MAP_ARGS0(m,...)
+#define MAP_ARGS1(m,t,a,...) m(t,a)
+#define MAP_ARGS2(m,t,a,...) m(t,a), MAP_ARGS1(m,__VA_ARGS__)
+#define MAP_ARGS3(m,t,a,...) m(t,a), MAP_ARGS2(m,__VA_ARGS__)
+#define MAP_ARGS4(m,t,a,...) m(t,a), MAP_ARGS3(m,__VA_ARGS__)
+#define MAP_ARGS5(m,t,a,...) m(t,a), MAP_ARGS4(m,__VA_ARGS__)
+#define MAP_ARGS6(m,t,a,...) m(t,a), MAP_ARGS5(m,__VA_ARGS__)
+#define MAP_ARGS(n,...) MAP_ARGS##n(__VA_ARGS__)
+
+#define __DECLARE_ARGS(t, a)   t a
+#define __UNPACK_ARGS(t, a)    a
+
+#define DECLARE_ARGS(nr_args, args...) MAP_ARGS(nr_args, __DECLARE_ARGS, args)
+#define UNPACK_ARGS(nr_args, args...) MAP_ARGS(nr_args, __UNPACK_ARGS, args)
+
+#define __KVM_SYSCALL_ERROR(_name, _ret) \
+       "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno)
+
+/* Define a kvm_<syscall>() API to assert success. */
+#define __KVM_SYSCALL_DEFINE(name, nr_args, args...)                   \
+static inline void kvm_##name(DECLARE_ARGS(nr_args, args))             \
+{                                                                      \
+       int r;                                                          \
+                                                                       \
+       r = name(UNPACK_ARGS(nr_args, args));                           \
+       TEST_ASSERT(!r, __KVM_SYSCALL_ERROR(#name, r));                 \
+}
+
+/*
+ * Macro to define syscall APIs, either because KVM selftests doesn't link to
+ * the standard library, e.g. libnuma, or because there is no library that yet
+ * provides the syscall.  These
+ */
+#define KVM_SYSCALL_DEFINE(name, nr_args, args...)                     \
+static inline long name(DECLARE_ARGS(nr_args, args))                   \
+{                                                                      \
+       return syscall(__NR_##name, UNPACK_ARGS(nr_args, args));        \
+}                                                                      \
+__KVM_SYSCALL_DEFINE(name, nr_args, args)
+
+/*
+ * Special case mmap(), as KVM selftest rarely/never specific an address,
+ * rarely specify an offset, and because the unique return code requires
+ * special handling anyways.
+ */
+static inline void *__kvm_mmap(size_t size, int prot, int flags, int fd,
+                              off_t offset)
+{
+       void *mem;
+
+       mem = mmap(NULL, size, prot, flags, fd, offset);
+       TEST_ASSERT(mem != MAP_FAILED, __KVM_SYSCALL_ERROR("mmap()",
+                   (int)(unsigned long)MAP_FAILED));
+       return mem;
+}
+
+static inline void *kvm_mmap(size_t size, int prot, int flags, int fd)
+{
+       return __kvm_mmap(size, prot, flags, fd, 0);
+}
+
+static inline int kvm_dup(int fd)
+{
+       int new_fd = dup(fd);
+
+       TEST_ASSERT(new_fd >= 0, __KVM_SYSCALL_ERROR("dup()", new_fd));
+       return new_fd;
+}
+
+__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);
+__KVM_SYSCALL_DEFINE(ftruncate, 2, unsigned int, fd, off_t, length);
+
+#endif /* SELFTEST_KVM_SYSCALLS_H */
index d3f3e455c03103f6ff1ec5d35bb01679962baad2..af52cd938b500b22e05bd1f8d63d0feb57a6abd4 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <pthread.h>
 
+#include "kvm_syscalls.h"
 #include "kvm_util_arch.h"
 #include "kvm_util_types.h"
 #include "sparsebit.h"
@@ -283,34 +284,6 @@ static inline bool kvm_has_cap(long cap)
        return kvm_check_cap(cap);
 }
 
-#define __KVM_SYSCALL_ERROR(_name, _ret) \
-       "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno)
-
-static inline void *__kvm_mmap(size_t size, int prot, int flags, int fd,
-                              off_t offset)
-{
-       void *mem;
-
-       mem = mmap(NULL, size, prot, flags, fd, offset);
-       TEST_ASSERT(mem != MAP_FAILED, __KVM_SYSCALL_ERROR("mmap()",
-                   (int)(unsigned long)MAP_FAILED));
-
-       return mem;
-}
-
-static inline void *kvm_mmap(size_t size, int prot, int flags, int fd)
-{
-       return __kvm_mmap(size, prot, flags, fd, 0);
-}
-
-static inline void kvm_munmap(void *mem, size_t size)
-{
-       int ret;
-
-       ret = munmap(mem, size);
-       TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret));
-}
-
 /*
  * Use the "inner", double-underscore macro when reporting errors from within
  * other macros so that the name of ioctl() and not its literal numeric value
index f02355c3c4c2361275ae7f2e542abd93ff8a35ab..b7dbde9c084364fca6961be380d63f6c9280ca61 100644 (file)
@@ -239,14 +239,14 @@ int main(int argc, char *argv[])
                 * single stats file works and doesn't cause explosions.
                 */
                vm_stats_fds = vm_get_stats_fd(vms[i]);
-               stats_test(dup(vm_stats_fds));
+               stats_test(kvm_dup(vm_stats_fds));
 
                /* Verify userspace can instantiate multiple stats files. */
                stats_test(vm_get_stats_fd(vms[i]));
 
                for (j = 0; j < max_vcpu; ++j) {
                        vcpu_stats_fds[j] = vcpu_get_stats_fd(vcpus[i * max_vcpu + j]);
-                       stats_test(dup(vcpu_stats_fds[j]));
+                       stats_test(kvm_dup(vcpu_stats_fds[j]));
                        stats_test(vcpu_get_stats_fd(vcpus[i * max_vcpu + j]));
                }
 
index 1a93d636167146e3390bdccbda1150c404ef4e9e..203e33697492e3ec6f08e877628c4e279ddca95c 100644 (file)
@@ -704,8 +704,6 @@ userspace_mem_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end)
 
 static void kvm_stats_release(struct kvm_binary_stats *stats)
 {
-       int ret;
-
        if (stats->fd < 0)
                return;
 
@@ -714,8 +712,7 @@ static void kvm_stats_release(struct kvm_binary_stats *stats)
                stats->desc = NULL;
        }
 
-       ret = close(stats->fd);
-       TEST_ASSERT(!ret,  __KVM_SYSCALL_ERROR("close()", ret));
+       kvm_close(stats->fd);
        stats->fd = -1;
 }
 
@@ -738,8 +735,6 @@ __weak void vcpu_arch_free(struct kvm_vcpu *vcpu)
  */
 static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
 {
-       int ret;
-
        if (vcpu->dirty_gfns) {
                kvm_munmap(vcpu->dirty_gfns, vm->dirty_ring_size);
                vcpu->dirty_gfns = NULL;
@@ -747,9 +742,7 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
 
        kvm_munmap(vcpu->run, vcpu_mmap_sz());
 
-       ret = close(vcpu->fd);
-       TEST_ASSERT(!ret,  __KVM_SYSCALL_ERROR("close()", ret));
-
+       kvm_close(vcpu->fd);
        kvm_stats_release(&vcpu->stats);
 
        list_del(&vcpu->list);
@@ -761,16 +754,12 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
 void kvm_vm_release(struct kvm_vm *vmp)
 {
        struct kvm_vcpu *vcpu, *tmp;
-       int ret;
 
        list_for_each_entry_safe(vcpu, tmp, &vmp->vcpus, list)
                vm_vcpu_rm(vmp, vcpu);
 
-       ret = close(vmp->fd);
-       TEST_ASSERT(!ret,  __KVM_SYSCALL_ERROR("close()", ret));
-
-       ret = close(vmp->kvm_fd);
-       TEST_ASSERT(!ret,  __KVM_SYSCALL_ERROR("close()", ret));
+       kvm_close(vmp->fd);
+       kvm_close(vmp->kvm_fd);
 
        /* Free cached stats metadata and close FD */
        kvm_stats_release(&vmp->stats);
@@ -828,7 +817,7 @@ void kvm_vm_free(struct kvm_vm *vmp)
 int kvm_memfd_alloc(size_t size, bool hugepages)
 {
        int memfd_flags = MFD_CLOEXEC;
-       int fd, r;
+       int fd;
 
        if (hugepages)
                memfd_flags |= MFD_HUGETLB;
@@ -836,11 +825,8 @@ int kvm_memfd_alloc(size_t size, bool hugepages)
        fd = memfd_create("kvm_selftest", memfd_flags);
        TEST_ASSERT(fd != -1, __KVM_SYSCALL_ERROR("memfd_create()", fd));
 
-       r = ftruncate(fd, size);
-       TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("ftruncate()", r));
-
-       r = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, size);
-       TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("fallocate()", r));
+       kvm_ftruncate(fd, size);
+       kvm_fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, size);
 
        return fd;
 }
@@ -1084,8 +1070,7 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
                         * needing to track if the fd is owned by the framework
                         * or by the caller.
                         */
-                       guest_memfd = dup(guest_memfd);
-                       TEST_ASSERT(guest_memfd >= 0, __KVM_SYSCALL_ERROR("dup()", guest_memfd));
+                       guest_memfd = kvm_dup(guest_memfd);
                }
 
                region->region.guest_memfd = guest_memfd;
index 82a8d88b5338e3aca9902fa4faaaaa970faeb51d..1969f4ab9b280d76b3f403f5486570accb8b486d 100644 (file)
@@ -380,7 +380,7 @@ static void test_mem_conversions(enum vm_mem_backing_src_type src_type, uint32_t
        struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
        pthread_t threads[KVM_MAX_VCPUS];
        struct kvm_vm *vm;
-       int memfd, i, r;
+       int memfd, i;
 
        const struct vm_shape shape = {
                .mode = VM_MODE_DEFAULT,
@@ -428,11 +428,8 @@ static void test_mem_conversions(enum vm_mem_backing_src_type src_type, uint32_t
         * should prevent the VM from being fully destroyed until the last
         * reference to the guest_memfd is also put.
         */
-       r = fallocate(memfd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, memfd_size);
-       TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("fallocate()", r));
-
-       r = fallocate(memfd, FALLOC_FL_KEEP_SIZE, 0, memfd_size);
-       TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("fallocate()", r));
+       kvm_fallocate(memfd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, memfd_size);
+       kvm_fallocate(memfd, FALLOC_FL_KEEP_SIZE, 0, memfd_size);
 
        close(memfd);
 }