On Thu, Aug 13, 2026 at 01:48:21PM +0100, Daniel P. Berrangé wrote:
> On Thu, Aug 13, 2026 at 08:28:24AM -0400, Peter Xu wrote:
> > On Thu, Aug 13, 2026 at 09:24:22AM +0100, Daniel P. Berrangé wrote:
> > > On Wed, Aug 12, 2026 at 03:16:46PM -0500, Michael Roth wrote:
> > > > From: Peter Xu <[email protected]>
> > > > 
> > > > 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]>
> > > > Reviewed-by: Xiaoyao Li <[email protected]>
> > > > Reviewed-by: Fabiano Rosas <[email protected]>
> > > > Signed-off-by: Michael Roth <[email protected]>
> > > > ---
> > > >  backends/hostmem-memfd.c | 56 ++++++++++++++++++++++++++++++++++++----
> > > >  qapi/qom.json            |  6 ++++-
> > > >  2 files changed, 56 insertions(+), 6 deletions(-)
> > > > 
> > > > diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
> > > > index ea93f034e4..fbe65b00be 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 an 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,29 @@ 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) {
> > > > +        if (!backend->share) {
> > > > +            error_setg(errp, "guest-memfd=on must be used with 
> > > > share=on");
> > > > +            return false;
> > > > +        } else if (m->seal) {
> > > > +            error_setg(errp, "guest-memfd=on must be used with 
> > > > seal=off");
> > > > +            return false;
> > > > +        } else if (m->hugetlb) {
> > > > +            error_setg(errp, "guest-memfd=on must be used with 
> > > > hugetlb=off");
> > > 
> > > Reporting an error without returning false like the other cases.
> > > 
> > > > +        }
> > > > +
> > > > +        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 +92,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 +191,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);
> > > > diff --git a/qapi/qom.json b/qapi/qom.json
> > > > index c55776af7d..ee981fc44c 100644
> > > > --- a/qapi/qom.json
> > > > +++ b/qapi/qom.json
> > > > @@ -771,13 +771,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.2)
> > > > +#
> > > >  # Since: 2.12
> > > >  ##
> > > >  { 'struct': 'MemoryBackendMemfdProperties',
> > > >    'base': 'MemoryBackendProperties',
> > > >    'data': { '*hugetlb': 'bool',
> > > >              '*hugetlbsize': 'size',
> > > > -            '*seal': 'bool' },
> > > > +            '*seal': 'bool',
> > > > +            '*guest-memfd': 'bool' },
> > > >    'if': 'CONFIG_LINUX' }
> > > 
> > > We're reusing the 'memory-backend-memfd' class, and then at runtime
> > > refusing allow the user to control any of properties in
> > > MemoryBackendProperties.
> > 
> > gmemfd should be able to use all ultimately.
> > 
> > For seal, IMHO it's already implied, kind of forced seal=on but it doesn't
> > matter, gmemfd was introduced with sealing, at least what QEMU implies with
> > "F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL".  So IMHO we could ignore what
> > user selected and assume it's ON.

The naming threw me off, but looking at the actual schema description for
'seal', it basically implies 'fixed-size=on', which guest_memfd does
enforce. So, aside from the question of whether to reuse the memfd backend,
I do think it's more correct to imply seal=on for guest_memfd.

> 
> Then we should not have a 'seal' property defined for guest memfd
> at all. Defining a property and then ignoring it, or only ever
> allowing 1 value to be set is a design mistake. The property should
> not exist if it can't ever be changed by the user/app.

We have a couple examples of what seems like something similar with
memory-backend-file,rom=on,readonly=off and
memory-backend-*,prealloc=on,reserve=off. Granted, those seem a little
more obvious to recognize as mutually-exclusive, but as far as the
discussion around libvirt/mgmt/introspection: are there mechanisms in
place already to handle cases like that? Or are these special-cases that
would be problematic to try to handle similarly?

Regarding hugepage options, there will undoubtedly be kernels that support
guest_memfd but not hugetlb, so even if we introduce
memory-backend-guest-memfd now so that we can add options when/where it
makes sense, libvirt/mgmt. would still need to eventually handle a
'hugetlb' option existing, but not necessarilly implying that the guest can
actually use them. It seems like the issue exists in either case.

FWIW, I do anticipate that we will need something like
memory-backend-guest-memfd for some of the use-cases coming down the
pipeline, but for some stuff like CXL/HBM memory support where folks are
talking about stuff like custom guest_memfd allocators or special-purpose
NUMA nodes I'm not reasonably confident that memory-backend-guest-memfd won't
itself end up being too generic of a construct and be immediately relegated
to only handling the exact same set of options as memory-backend-memfd (give
or take a 'seal').

Peter's suggested approach allows us to assume less about how things will
eventually look by reusing existing options/command-lines and handling things
underneath the covers for the more basic use-cases in the meantime. Once we
hit cases that clearly have no business in memory-backend-memfd, we won't
really have lost anything as far as our options to introduce
memory-backend-guest-memfd at that point or maybe some subclass or something
else entirely.

So that's sort of my angle here, but despite the walls of text I don't have a
strong opinion one way or the other. But I do want to make sure we don't make
things harder on libvirt/mgmt than necessary.

> 
> > For hugetlb, we will support hugetlb (and allow specify hugetlb size) for
> > gmem in the future I believe.  It's only that this is done one step at a
> > time so we haven't supported it yet, while the kernel support is still in
> > progress.
> 
> The problem with this idea is that it makes it impossible for a mgmt
> app to know if hugetlb is supported or not, as QEMU will always
> report it supported against memory-backend-memfd.
> 
> Having a memory-backend-guest-memfd ensures the public interface
> matches what is actually implemented/permitted for guest memfd.
> 
> > > "memory-backend-memfd,guest-memfd=on|off" is switching between two
> > > separate implementations of the class.
> > > 
> > > This whole thing is just shouting "use a different class".
> > > 
> > > There is no meaningful sharing of code here, and the sharing of the
> > > public interface is offering apps no value as the impl prevents them
> > > from choosing the value of the properties - they have to be set of
> > > certain values which are not introspectable.
> > > 
> > > Please introduce a "memory-backend-guest-memfd" backend instead.
> > 
> > This is indeed what Michael used to suggest, and we were discussing in
> > previous version on which is better,
> > 
> > https://lore.kernel.org/r/rjqfiwh57gip3u3psqg33jhmo7ixaj2qwzupc7zdk7f3d26qnu@tglactz67ogk
> > 
> > The hope is this is also easier for either libvirt or most users, but
> > please correct me if it's not the case, especially for libvirt.  The plan
> > is when CoCo flags are provided, all things will automatically switch to a
> > CoCo-friendly implementation within QEMU.
> > 
> > It also means here the guest-memfd= parameter shouldn't be needed in real
> > CoCo contexts because they'll simply be implied (no cmdline change needed
> > for the same "-object memory-backend-memfd" one used to use without CoCo).
> > It's only needed for only special use of guest-memfd, in this case
> > init-shared is the special case where CoCo doesn't use.
> 
> Reading all this, IMHO reusing memory-backend-memfd for the current
> Coco support was a design mistake, it should have have a
> memory-backend-guest-memfd object from the start.

I think your point still stands, but the current CoCo support doesn't rely
on memory-backend-memfd, the private guest_memfd instance is handled by
QEMU completely separately as a function of whether or not we are running
a CoCo VM. The backends are only for shared memory, which aren't relevant
to guest_memfd (without in-place conversion support), so users can select
whatever they'd like.

However, backends like memory-backend-file tend to get used for special
cases like persisting memory, where there is a high chance of surprises
for users trying to make use of these sorts of things for a CoCo VM.
That's why memory-backend-memfd is the configuration we normally suggest
for CoCo VMs, but it's not required, since nothing stops users from
persisting shared memory ranges if that's actually their intent.

The need to enforce the backend more explicitly becomes much more apparent
once in-place conversion however, where even shared memory goes through
guest-memfd and so the backend necessarily needs to be
guest_memfd-aware. The in-place conversion series tracks this via a
RAMBlock flag that can be set by whatever backends we decide would be
appropriate for managing guest_memfd instances based on these
discussions.

So, at least for users following the recommended configuration:

  qemu -object sev-snp-guest,...
       -object memory-backend-memfd,...

they can then switch on in-place conversion via, e.g.:

  qemu -object sev-snp-guest,...,convert-in-place=on
       -object memory-backend-memfd,...

and we can flip guest_memfd=on automatically underneath the covers
so that both shared/private memory go through guest_memfd as
convert-in-place would necessarily imply.

It's not necessary that this happen automatically, but from a user
perspective it seems clean, and aligns with the above goals of trying
to defer the introduction of new backends/options until we have a
better idea of what the relevant uAPI bits are going to look like.

Thanks,

Mike

> 
> Given that we need to be able to control memfd vs guest-memfd for
> the non-Coco case, it is still worth introducing the new object
> class today.
> 
> Even if the two classes shared all their properties (which they
> don't given the comment about 'seal' being always on), then a
> "foo=on|off" that toggles two separate impls is still creating
> a pair of sub-classes by the backdoor. 
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
> |: https://libvirt.org          ~~          https://entangle-photo.org :|
> |: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
> 

Reply via email to