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;
> }