On 11/20/2025 1:29 AM, Peter Xu wrote:
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 in-place.  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, in place), rather than
having another backend supporting the pages converted to shared.

To use the in-place 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 in-place guest_memfd.

Signed-off-by: Peter Xu <[email protected]>

overall looks good to me except a few comments below,

Reviewed-by: Xiaoyao Li <[email protected]>

---
  qapi/qom.json            |  6 +++-
  backends/hostmem-memfd.c | 66 +++++++++++++++++++++++++++++++++++++---
  2 files changed, 67 insertions(+), 5 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..1fa16c1e1d 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,10 +56,40 @@ 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 (m->guest_memfd) {
+        /* User choose to use in-place guest-memfd to back the VM.. */
+        if (!backend->share) {
+            error_setg(errp, "In-place guest-memfd must be used with 
share=on");
+            return false;
+        }
+
+        /*
+         * This is the request to have a guest-memfd to back private pages.
+         * In-place guest-memfd doesn't work like that.  Disable it for now

This seems not correct to me. I think in-place guest-memfd can work with guest_memfd_private. The former serves as shared memory and referenced by the userspace_addr while the latter serves as private memory referenced by the fd of guest_memfd.

While the argument of "disable it for now to make it simple" does make sense to me.

+         * to make it simple, so that each memory backend can only have
+         * guest-memfd either as private, or fully shared.
+         */
+        if (backend->guest_memfd_private) {
+            error_setg(errp, "In-place guest-memfd cannot be used with another 
"
+                       "private guest-memfd");
+            return false;
+        }

please add the following check as I commented in v1:

        if (!kvm_enabled()) {
                error_setg(errp, "in-place guest-memfd requires KVM");
                return false;
        }

+        /* TODO: add huge page support */
+        fd = kvm_create_guest_memfd(backend->size,
+                                    GUEST_MEMFD_FLAG_MMAP |
+                                    GUEST_MEMFD_FLAG_INIT_SHARED,
+                                    errp);
+        if (fd < 0) {
+            return false;
+        }

how about just removing the fd check here because ...

+    } 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 == -1) {
          return false;
      }

... the existing check can work for the guest memfd as well.

@@ -65,6 +104,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 +203,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);


Reply via email to