Re: [PATCH v12 13/16] KVM: selftests: Add guest_memfd based vm_mem_backing_src_types

From: Brendan Jackman

Date: Fri Jun 26 2026 - 10:23:08 EST


On Fri Apr 10, 2026 at 3:20 PM UTC, Nikita Kalyazin wrote:
> From: Patrick Roy <patrick.roy@xxxxxxxxx>
>
> Allow selftests to configure their memslots such that userspace_addr is
> set to a MAP_SHARED mapping of the guest_memfd that's associated with
> the memslot. This setup is the configuration for non-CoCo VMs, where all
> guest memory is backed by a guest_memfd whose folios are all marked
> shared, but KVM is still able to access guest memory to provide
> functionality such as MMIO emulation on x86.
>
> Add backing types for normal guest_memfd, as well as direct map removed
> guest_memfd.
>
> Signed-off-by: Patrick Roy <patrick.roy@xxxxxxxxx>
> Signed-off-by: Nikita Kalyazin <nikita.kalyazin@xxxxxxxxx>
> ---
> .../testing/selftests/kvm/include/kvm_util.h | 18 ++++++
> .../testing/selftests/kvm/include/test_util.h | 7 +++
> tools/testing/selftests/kvm/lib/kvm_util.c | 61 ++++++++++---------
> tools/testing/selftests/kvm/lib/test_util.c | 8 +++
> 4 files changed, 65 insertions(+), 29 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
> index 8b39cb919f4f..056a003a63c0 100644
> --- a/tools/testing/selftests/kvm/include/kvm_util.h
> +++ b/tools/testing/selftests/kvm/include/kvm_util.h
> @@ -664,6 +664,24 @@ static inline bool is_smt_on(void)
>
> void vm_create_irqchip(struct kvm_vm *vm);
>
> +static inline uint32_t backing_src_guest_memfd_flags(enum vm_mem_backing_src_type t)
> +{
> + uint32_t flags = 0;
> +
> + switch (t) {
> + case VM_MEM_SRC_GUEST_MEMFD_NO_DIRECT_MAP:
> + flags |= GUEST_MEMFD_FLAG_NO_DIRECT_MAP;
> + fallthrough;
> + case VM_MEM_SRC_GUEST_MEMFD:
> + flags |= GUEST_MEMFD_FLAG_MMAP | GUEST_MEMFD_FLAG_INIT_SHARED;
> + break;
> + default:
> + break;
> + }
> +
> + return flags;
> +}
> +
> static inline int __vm_create_guest_memfd(struct kvm_vm *vm, uint64_t size,
> uint64_t flags)
> {
> diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h
> index 8140e59b59e5..ea6de20ce8ef 100644
> --- a/tools/testing/selftests/kvm/include/test_util.h
> +++ b/tools/testing/selftests/kvm/include/test_util.h
> @@ -152,6 +152,8 @@ enum vm_mem_backing_src_type {
> VM_MEM_SRC_ANONYMOUS_HUGETLB_16GB,
> VM_MEM_SRC_SHMEM,
> VM_MEM_SRC_SHARED_HUGETLB,
> + VM_MEM_SRC_GUEST_MEMFD,
> + VM_MEM_SRC_GUEST_MEMFD_NO_DIRECT_MAP,
> NUM_SRC_TYPES,
> };
>
> @@ -184,6 +186,11 @@ static inline bool backing_src_is_shared(enum vm_mem_backing_src_type t)
> return vm_mem_backing_src_alias(t)->flag & MAP_SHARED;
> }
>
> +static inline bool backing_src_is_guest_memfd(enum vm_mem_backing_src_type t)
> +{
> + return t == VM_MEM_SRC_GUEST_MEMFD || t == VM_MEM_SRC_GUEST_MEMFD_NO_DIRECT_MAP;
> +}
> +
> static inline bool backing_src_can_be_huge(enum vm_mem_backing_src_type t)
> {
> return t != VM_MEM_SRC_ANONYMOUS && t != VM_MEM_SRC_SHMEM;
> diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> index 5b0865683047..fa4a2fc236fe 100644
> --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> @@ -1046,6 +1046,33 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
> alignment = 1;
> #endif
>
> + if (guest_memfd < 0) {
> + if ((flags & KVM_MEM_GUEST_MEMFD) || backing_src_is_guest_memfd(src_type)) {
> + uint32_t guest_memfd_flags = backing_src_guest_memfd_flags(src_type);
> +
> + TEST_ASSERT(!guest_memfd_offset,
> + "Offset must be zero when creating new guest_memfd");
> + guest_memfd = vm_create_guest_memfd(vm, mem_size, guest_memfd_flags);
> + }
> + } else {
> + /*
> + * Install a unique fd for each memslot so that the fd
> + * can be closed when the region is deleted without
> + * needing to track if the fd is owned by the framework
> + * or by the caller.
> + */
> + guest_memfd = kvm_dup(guest_memfd);
> + }
> +
> + if (guest_memfd >= 0) {
> + flags |= KVM_MEM_GUEST_MEMFD;
> +
> + region->region.guest_memfd = guest_memfd;
> + region->region.guest_memfd_offset = guest_memfd_offset;
> + } else {
> + region->region.guest_memfd = -1;
> + }
> +
> /*
> * When using THP mmap is not guaranteed to returned a hugepage aligned
> * address so we have to pad the mmap. Padding is not needed for HugeTLB
> @@ -1061,10 +1088,13 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
> if (alignment > 1)
> region->mmap_size += alignment;
>
> - region->fd = -1;
> - if (backing_src_is_shared(src_type))
> + if (backing_src_is_guest_memfd(src_type))
> + region->fd = guest_memfd;

This seems to cause a double-close in __vm_mem_region_delete() - it was
fine when this patch was written but now we have kvm_free_fd() which
crashes the test when this happens.

AFAICS it's easy to fix we just need to enlighten
__vm_mem_region_delete() that they might be the same FD.