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 81eae09c92..73536c8f29 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" @@ -279,6 +283,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; case MEM_TYPE_ANON: backend = g_strdup("-object memory-backend-ram"); share = false; @@ -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) +{ + 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) { + *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; } -- 2.50.1
