Host backends supports guest-memfd now by detecting whether it's a confidential VM. There's no way to choose it yet from the memory level to use it fully shared. If we use guest-memfd, it so far always implies we need two layers of memory backends, while the guest-memfd only provides the private set of pages.
This patch introduces a way so that QEMU can consume guest memfd as the only source of memory to back the object (aka, fully shared). To use the fully shared guest-memfd, one can add a memfd object with: -object memory-backend-memfd,guest-memfd=on,share=on Note that share=on is required with fully shared guest_memfd. PS: there's a trivial touch-up on fd<0 check, because the stub to create guest-memfd may return negative but not -1. Signed-off-by: Peter Xu <[email protected]> --- qapi/qom.json | 6 ++++- backends/hostmem-memfd.c | 53 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/qapi/qom.json b/qapi/qom.json index 6f5c9de0f0..9ebf17bfc7 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -763,13 +763,17 @@ # @seal: if true, create a sealed-file, which will block further # resizing of the memory (default: true) # +# @guest-memfd: if true, use guest-memfd to back the memory region. +# (default: false, since: 11.0) +# # Since: 2.12 ## { 'struct': 'MemoryBackendMemfdProperties', 'base': 'MemoryBackendProperties', 'data': { '*hugetlb': 'bool', '*hugetlbsize': 'size', - '*seal': 'bool' }, + '*seal': 'bool', + '*guest-memfd': 'bool' }, 'if': 'CONFIG_LINUX' } ## diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c index ea93f034e4..9299cd7675 100644 --- a/backends/hostmem-memfd.c +++ b/backends/hostmem-memfd.c @@ -18,6 +18,8 @@ #include "qapi/error.h" #include "qom/object.h" #include "migration/cpr.h" +#include "system/kvm.h" +#include <linux/kvm.h> OBJECT_DECLARE_SIMPLE_TYPE(HostMemoryBackendMemfd, MEMORY_BACKEND_MEMFD) @@ -28,6 +30,13 @@ struct HostMemoryBackendMemfd { bool hugetlb; uint64_t hugetlbsize; bool seal; + /* + * NOTE: this differs from HostMemoryBackend's guest_memfd_private, + * which represents a internally private guest-memfd that only backs + * private pages. Instead, this flag marks the memory backend will + * 100% use the guest-memfd pages in-place. + */ + bool guest_memfd; }; static bool @@ -47,11 +56,26 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) goto have_fd; } - fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD, backend->size, - m->hugetlb, m->hugetlbsize, m->seal ? - F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL : 0, - errp); - if (fd == -1) { + if (m->guest_memfd) { + /* User choose to use fully shared guest-memfd to back the VM.. */ + if (!backend->share) { + error_setg(errp, "Guest-memfd=on must be used with share=on"); + return false; + } + + /* TODO: add huge page support */ + fd = kvm_create_guest_memfd(backend->size, + GUEST_MEMFD_FLAG_MMAP | + GUEST_MEMFD_FLAG_INIT_SHARED, + errp); + } else { + fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD, backend->size, + m->hugetlb, m->hugetlbsize, m->seal ? + F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL : 0, + errp); + } + + if (fd < 0) { return false; } cpr_save_fd(name, 0, fd); @@ -65,6 +89,18 @@ have_fd: backend->size, ram_flags, fd, 0, errp); } +static bool +memfd_backend_get_guest_memfd(Object *o, Error **errp) +{ + return MEMORY_BACKEND_MEMFD(o)->guest_memfd; +} + +static void +memfd_backend_set_guest_memfd(Object *o, bool value, Error **errp) +{ + MEMORY_BACKEND_MEMFD(o)->guest_memfd = value; +} + static bool memfd_backend_get_hugetlb(Object *o, Error **errp) { @@ -152,6 +188,13 @@ memfd_backend_class_init(ObjectClass *oc, const void *data) object_class_property_set_description(oc, "hugetlbsize", "Huge pages size (ex: 2M, 1G)"); } + + object_class_property_add_bool(oc, "guest-memfd", + memfd_backend_get_guest_memfd, + memfd_backend_set_guest_memfd); + object_class_property_set_description(oc, "guest-memfd", + "Use guest memfd"); + object_class_property_add_bool(oc, "seal", memfd_backend_get_seal, memfd_backend_set_seal); -- 2.50.1
