Peter Xu <[email protected]> writes:

> Support the guest-memfd type when the fd has init share enabled.  It means
> the gmemfd can be used similarly to memfd.
>
> Signed-off-by: Peter Xu <[email protected]>
> ---
>  tests/qtest/migration/framework.h |  4 +++
>  tests/qtest/migration/framework.c | 60 +++++++++++++++++++++++++++++++
>  2 files changed, 64 insertions(+)
>
> diff --git a/tests/qtest/migration/framework.h 
> b/tests/qtest/migration/framework.h
> index ed85ed502d..b4c5edcad3 100644
> --- a/tests/qtest/migration/framework.h
> +++ b/tests/qtest/migration/framework.h
> @@ -34,6 +34,10 @@ typedef enum {
>       * but only anonymously allocated.
>       */
>      MEM_TYPE_MEMFD,
> +    /*
> +     * Use guest-memfd, shared mappings.
> +     */
> +    MEM_TYPE_GUEST_MEMFD,
>      MEM_TYPE_NUM,
>  } MemType;
>  
> diff --git a/tests/qtest/migration/framework.c 
> b/tests/qtest/migration/framework.c
> index e35839c95f..9aa353bac6 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -26,6 +26,10 @@
>  #include "qemu/range.h"
>  #include "qemu/sockets.h"
>  
> +#ifdef CONFIG_LINUX
> +#include <linux/kvm.h>
> +#include <sys/ioctl.h>
> +#endif
>  
>  #define QEMU_VM_FILE_MAGIC 0x5145564d
>  #define QEMU_ENV_SRC "QTEST_QEMU_BINARY_SRC"
> @@ -283,6 +287,9 @@ static char *migrate_mem_type_get_opts(MemType type, 
> const char *memory_size)
>      case MEM_TYPE_MEMFD:
>          backend = g_strdup("-object memory-backend-memfd");
>          break;
> +    case MEM_TYPE_GUEST_MEMFD:
> +        backend = g_strdup("-object memory-backend-memfd,guest-memfd=on");
> +        break;
>      default:
>          g_assert_not_reached();
>          break;
> @@ -425,8 +432,55 @@ int migrate_args(char **from, char **to, const char 
> *uri, MigrateStart *args)
>      return 0;
>  }
>  
> +static bool kvm_guest_memfd_init_shared_supported(const char **reason)

Should be in migration-util.c, like kvm_dirty_ring_supported() and
ufd_version_check().

> +{
> +    assert(*reason == NULL);
> +
> +#ifdef CONFIG_LINUX
> +    int ret, fd = -1;
> +
> +    if (!migration_get_env()->has_kvm) {
> +        *reason = "KVM is not enabled in the current QEMU build";
> +        goto out;
> +    }
> +
> +    fd = open("/dev/kvm", O_RDWR);
> +    if (fd < 0) {
> +        *reason = "KVM module isn't available or missing permission";
> +        goto out;
> +    }
> +
> +    ret = ioctl(fd, KVM_CHECK_EXTENSION, KVM_CAP_GUEST_MEMFD);
> +    if (!ret) {
> +        *reason = "KVM module doesn't suport guest-memfd";
> +        goto out;
> +    }
> +
> +    ret = ioctl(fd, KVM_CHECK_EXTENSION, KVM_CAP_GUEST_MEMFD_FLAGS);
> +    if (ret < 0) {

Should this be <= ? I see there's a window between the addition of
KVM_CAP_GUEST_MEMFD and KVM_CAP_GUEST_MEMFD_FLAGS in the kernel.

> +        *reason = "KVM doesn't support KVM_CAP_GUEST_MEMFD_FLAGS";
> +        goto out;
> +    }
> +
> +    if (!(ret & GUEST_MEMFD_FLAG_INIT_SHARED)) {
> +        *reason = "KVM doesn't support GUEST_MEMFD_FLAG_INIT_SHARED";
> +        goto out;
> +    }
> +out:
> +    if (fd >= 0) {
> +        close(fd);
> +    }
> +#else
> +    *reason = "KVM not supported on non-Linux OS";
> +#endif
> +
> +    return !*reason;
> +}
> +
>  static bool migrate_mem_type_prepare(MemType type)
>  {
> +    const char *reason = NULL;
> +
>      switch (type) {
>      case MEM_TYPE_SHMEM:
>          if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) {
> @@ -434,6 +488,12 @@ static bool migrate_mem_type_prepare(MemType type)
>              return false;
>          }
>          break;
> +    case MEM_TYPE_GUEST_MEMFD:
> +        if (!kvm_guest_memfd_init_shared_supported(&reason)) {
> +            g_test_skip(reason);
> +            return false;
> +        }
> +        break;
>      default:
>          break;
>      }

Reply via email to