On Fri Apr 10, 2026 at 3:20 PM UTC, Nikita Kalyazin wrote:
> From: Patrick Roy <[email protected]>
>
> 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 <[email protected]>
> Signed-off-by: Nikita Kalyazin <[email protected]>
> ---
>  .../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.

Reply via email to