* [PATCH v4 01/12] kvm: Decouple memory attribute check from kvm_guest_memfd_supported
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-12 20:16 ` [PATCH v4 02/12] kvm: Detect guest-memfd flags supported Michael Roth
` (10 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Xiaoyao Li <xiaoyao.li@intel.com>
With the mmap support of guest memfd, KVM allows userspace to create
guest memfd serving as normal non-private memory for X86 DEFAULT VM.
However, KVM doesn't support private memory attribute for X86 DEFAULT
VM.
Make kvm_guest_memfd_supported not rely on KVM_MEMORY_ATTRIBUTE_PRIVATE
and check KVM_MEMORY_ATTRIBUTE_PRIVATE separately when the machine
requires guest_memfd to serve as private memory.
This allows QEMU to create guest memfd with mmap to serve as the memory
backend for X86 DEFAULT VM.
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
accel/kvm/kvm-all.c | 8 ++++++--
accel/stubs/kvm-stub.c | 5 +++++
include/system/kvm.h | 1 +
system/physmem.c | 8 ++++++++
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 83cbd120a8..cdc7554082 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -1627,6 +1627,11 @@ int kvm_set_memory_attributes_shared(hwaddr start, uint64_t size)
return kvm_set_memory_attributes(start, size, 0);
}
+bool kvm_private_memory_attribute_supported(void)
+{
+ return !!(kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE);
+}
+
/* Called with KVMMemoryListener.slots_lock held */
static void kvm_set_phys_mem(KVMMemoryListener *kml,
MemoryRegionSection *section, bool add)
@@ -3058,8 +3063,7 @@ static int kvm_init(AccelState *as, MachineState *ms)
kvm_supported_memory_attributes = kvm_vm_check_extension(s, KVM_CAP_MEMORY_ATTRIBUTES);
kvm_guest_memfd_supported =
kvm_vm_check_extension(s, KVM_CAP_GUEST_MEMFD) &&
- kvm_vm_check_extension(s, KVM_CAP_USER_MEMORY2) &&
- (kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE);
+ kvm_vm_check_extension(s, KVM_CAP_USER_MEMORY2);
kvm_pre_fault_memory_supported = kvm_vm_check_extension(s, KVM_CAP_PRE_FAULT_MEMORY);
if (s->kernel_irqchip_split == ON_OFF_AUTO_AUTO) {
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 32b4b07403..3d34e3b99d 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -143,3 +143,8 @@ int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
{
return -ENOSYS;
}
+
+bool kvm_private_memory_attribute_supported(void)
+{
+ return false;
+}
diff --git a/include/system/kvm.h b/include/system/kvm.h
index 714b8c7b01..d29624034c 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -551,6 +551,7 @@ int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp);
int kvm_set_memory_attributes_private(hwaddr start, uint64_t size);
int kvm_set_memory_attributes_shared(hwaddr start, uint64_t size);
+bool kvm_private_memory_attribute_supported(void);
int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private);
diff --git a/system/physmem.c b/system/physmem.c
index c21ea92915..406338f165 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -2192,6 +2192,14 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
object_get_typename(OBJECT(current_machine->cgs)));
goto out_free;
}
+
+ if (!kvm_private_memory_attribute_supported()) {
+ error_setg(errp, "cannot set up private guest memory for %s: "
+ "KVM does not support private memory attribute",
+ object_get_typename(OBJECT(current_machine->cgs)));
+ goto out_free;
+ }
+
assert(new_block->guest_memfd < 0);
ret = ram_block_coordinated_discard_require(true);
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v4 02/12] kvm: Detect guest-memfd flags supported
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
2026-08-12 20:16 ` [PATCH v4 01/12] kvm: Decouple memory attribute check from kvm_guest_memfd_supported Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-12 20:16 ` [PATCH v4 03/12] kvm: Provide explicit error for kvm_create_guest_memfd() Michael Roth
` (9 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
Detect supported guest-memfd flags by the current kernel, and reject
creations of guest-memfd using invalid flags. When the cap isn't
available, then no flag is supported.
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
accel/kvm/kvm-all.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index cdc7554082..120cab1e22 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -107,6 +107,7 @@ bool kvm_pre_fault_memory_supported;
static bool kvm_immediate_exit;
static uint64_t kvm_supported_memory_attributes;
static bool kvm_guest_memfd_supported;
+static uint64_t kvm_guest_memfd_flags_supported;
static hwaddr kvm_max_slot_size = ~0;
static const KVMCapabilityInfo kvm_required_capabilities[] = {
@@ -3065,6 +3066,8 @@ static int kvm_init(AccelState *as, MachineState *ms)
kvm_vm_check_extension(s, KVM_CAP_GUEST_MEMFD) &&
kvm_vm_check_extension(s, KVM_CAP_USER_MEMORY2);
kvm_pre_fault_memory_supported = kvm_vm_check_extension(s, KVM_CAP_PRE_FAULT_MEMORY);
+ kvm_guest_memfd_flags_supported =
+ kvm_vm_check_extension(s, KVM_CAP_GUEST_MEMFD_FLAGS);
if (s->kernel_irqchip_split == ON_OFF_AUTO_AUTO) {
s->kernel_irqchip_split = mc->default_kernel_irqchip_split ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
@@ -4760,6 +4763,13 @@ int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
return -1;
}
+ if (flags & ~kvm_guest_memfd_flags_supported) {
+ error_setg(errp, "Current KVM instance does not support "
+ "guest-memfd flag: 0x%"PRIx64,
+ flags & ~kvm_guest_memfd_flags_supported);
+ return -1;
+ }
+
fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_GUEST_MEMFD, &guest_memfd);
if (fd < 0) {
error_setg_errno(errp, errno, "Error creating KVM guest_memfd");
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v4 03/12] kvm: Provide explicit error for kvm_create_guest_memfd()
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
2026-08-12 20:16 ` [PATCH v4 01/12] kvm: Decouple memory attribute check from kvm_guest_memfd_supported Michael Roth
2026-08-12 20:16 ` [PATCH v4 02/12] kvm: Detect guest-memfd flags supported Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-14 5:56 ` Philippe Mathieu-Daudé
2026-08-12 20:16 ` [PATCH v4 04/12] ramblock: Rename guest_memfd to guest_memfd_private Michael Roth
` (8 subsequent siblings)
11 siblings, 1 reply; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
So that there will be a verbal string returned when kvm not enabled, or
kvm not compiled.
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
accel/kvm/kvm-all.c | 5 +++++
accel/stubs/kvm-stub.c | 1 +
2 files changed, 6 insertions(+)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 120cab1e22..bda2e25a66 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -4758,6 +4758,11 @@ int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
.flags = flags,
};
+ if (!kvm_enabled()) {
+ error_setg(errp, "guest-memfd requires KVM accelerator");
+ return -1;
+ }
+
if (!kvm_guest_memfd_supported) {
error_setg(errp, "KVM does not support guest_memfd");
return -1;
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 3d34e3b99d..acbd0785e0 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -141,6 +141,7 @@ bool kvm_hwpoisoned_mem(void)
int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
{
+ error_setg(errp, "KVM is not enabled");
return -ENOSYS;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v4 03/12] kvm: Provide explicit error for kvm_create_guest_memfd()
2026-08-12 20:16 ` [PATCH v4 03/12] kvm: Provide explicit error for kvm_create_guest_memfd() Michael Roth
@ 2026-08-14 5:56 ` Philippe Mathieu-Daudé
2026-08-14 12:44 ` Peter Xu
0 siblings, 1 reply; 22+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-14 5:56 UTC (permalink / raw)
To: Michael Roth, qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
Hi Peter, Michael,
On 12/8/26 22:16, Michael Roth wrote:
> From: Peter Xu <peterx@redhat.com>
>
> So that there will be a verbal string returned when kvm not enabled, or
> kvm not compiled.
>
> Signed-off-by: Peter Xu <peterx@redhat.com>
> Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> Reviewed-by: Fabiano Rosas <farosas@suse.de>
> Reviewed-by: Michael Roth <michael.roth@amd.com>
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
> accel/kvm/kvm-all.c | 5 +++++
> accel/stubs/kvm-stub.c | 1 +
> 2 files changed, 6 insertions(+)
>
> diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
> index 120cab1e22..bda2e25a66 100644
> --- a/accel/kvm/kvm-all.c
> +++ b/accel/kvm/kvm-all.c
> @@ -4758,6 +4758,11 @@ int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
> .flags = flags,
> };
>
> + if (!kvm_enabled()) {
> + error_setg(errp, "guest-memfd requires KVM accelerator");
> + return -1;
This doesn't sound right withing a KVM-specific method. We want to
assert() here.
The call in ram_block_add() is already protected:
2147 static void ram_block_add(RAMBlock *new_block, Error **errp)
2148 {
...
2185 if (new_block->flags & RAM_GUEST_MEMFD) {
2188 if (!kvm_enabled()) {
2189 error_setg(errp, "cannot set up private guest memory
for %s: KVM required",
2190
object_get_typename(OBJECT(current_machine->cgs)));
2191 goto out_free;
2192 }
...
2203 new_block->guest_memfd =
kvm_create_guest_memfd(new_block->max_length,
2204 0, errp);
The other one is:
2823 int ram_block_rebind(Error **errp)
2824 {
...
2829 RAMBLOCK_FOREACH(block) {
...
2834 block->guest_memfd =
kvm_create_guest_memfd(block->max_length,
2835 0, errp);
which is only called from KVM:
2776 static int kvm_reset_vmfd(MachineState *ms)
2777 {
...
2827 /* rebind memory to new vm fd */
2828 ret = ram_block_rebind(&err);
So maybe what we want is:
-- >8 --
diff --git a/system/physmem.c b/system/physmem.c
index b97016b1303..66ff74541aa 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -2824,6 +2824,8 @@ int ram_block_rebind(Error **errp)
{
RAMBlock *block;
+ assert(kvm_enabled()); /* Only supported by KVM so far */
+
qemu_mutex_lock_ramlist();
RAMBLOCK_FOREACH(block) {
---
Or less aggressive:
-- >8 --
diff --git a/system/physmem.c b/system/physmem.c
index b97016b1303..2988d1dd6c9 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -2824,6 +2824,11 @@ int ram_block_rebind(Error **errp)
{
RAMBlock *block;
+ if (!kvm_enabled()) {
+ error_setg(errp, "guest-memfd requires KVM accelerator");
+ return -1;
+ }
+
qemu_mutex_lock_ramlist();
RAMBLOCK_FOREACH(block) {
---
WDYT?
> + }
> +
> if (!kvm_guest_memfd_supported) {
> error_setg(errp, "KVM does not support guest_memfd");
> return -1;
> diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
> index 3d34e3b99d..acbd0785e0 100644
> --- a/accel/stubs/kvm-stub.c
> +++ b/accel/stubs/kvm-stub.c
> @@ -141,6 +141,7 @@ bool kvm_hwpoisoned_mem(void)
>
> int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
> {
> + error_setg(errp, "KVM is not enabled");
> return -ENOSYS;
> }
>
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v4 03/12] kvm: Provide explicit error for kvm_create_guest_memfd()
2026-08-14 5:56 ` Philippe Mathieu-Daudé
@ 2026-08-14 12:44 ` Peter Xu
0 siblings, 0 replies; 22+ messages in thread
From: Peter Xu @ 2026-08-14 12:44 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Michael Roth, qemu-devel, jmarcin, david, pbonzini, chenyi.qiang,
farosas, aik, xiaoyao.li
On Fri, Aug 14, 2026 at 07:56:42AM +0200, Philippe Mathieu-Daudé wrote:
> Hi Peter, Michael,
>
> On 12/8/26 22:16, Michael Roth wrote:
> > From: Peter Xu <peterx@redhat.com>
> >
> > So that there will be a verbal string returned when kvm not enabled, or
> > kvm not compiled.
> >
> > Signed-off-by: Peter Xu <peterx@redhat.com>
> > Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > Reviewed-by: Fabiano Rosas <farosas@suse.de>
> > Reviewed-by: Michael Roth <michael.roth@amd.com>
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> > accel/kvm/kvm-all.c | 5 +++++
> > accel/stubs/kvm-stub.c | 1 +
> > 2 files changed, 6 insertions(+)
> >
> > diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
> > index 120cab1e22..bda2e25a66 100644
> > --- a/accel/kvm/kvm-all.c
> > +++ b/accel/kvm/kvm-all.c
> > @@ -4758,6 +4758,11 @@ int kvm_create_guest_memfd(uint64_t size, uint64_t flags, Error **errp)
> > .flags = flags,
> > };
> > + if (!kvm_enabled()) {
> > + error_setg(errp, "guest-memfd requires KVM accelerator");
> > + return -1;
>
> This doesn't sound right withing a KVM-specific method. We want to
> assert() here.
>
> The call in ram_block_add() is already protected:
>
> 2147 static void ram_block_add(RAMBlock *new_block, Error **errp)
> 2148 {
> ...
> 2185 if (new_block->flags & RAM_GUEST_MEMFD) {
> 2188 if (!kvm_enabled()) {
> 2189 error_setg(errp, "cannot set up private guest memory for
> %s: KVM required",
> 2190 object_get_typename(OBJECT(current_machine->cgs)));
> 2191 goto out_free;
> 2192 }
> ...
> 2203 new_block->guest_memfd =
> kvm_create_guest_memfd(new_block->max_length,
> 2204 0, errp);
>
> The other one is:
>
> 2823 int ram_block_rebind(Error **errp)
> 2824 {
> ...
> 2829 RAMBLOCK_FOREACH(block) {
> ...
> 2834 block->guest_memfd =
> kvm_create_guest_memfd(block->max_length,
> 2835 0, errp);
>
> which is only called from KVM:
>
> 2776 static int kvm_reset_vmfd(MachineState *ms)
> 2777 {
> ...
> 2827 /* rebind memory to new vm fd */
> 2828 ret = ram_block_rebind(&err);
>
> So maybe what we want is:
>
> -- >8 --
> diff --git a/system/physmem.c b/system/physmem.c
> index b97016b1303..66ff74541aa 100644
> --- a/system/physmem.c
> +++ b/system/physmem.c
> @@ -2824,6 +2824,8 @@ int ram_block_rebind(Error **errp)
> {
> RAMBlock *block;
>
> + assert(kvm_enabled()); /* Only supported by KVM so far */
> +
> qemu_mutex_lock_ramlist();
>
> RAMBLOCK_FOREACH(block) {
> ---
>
> Or less aggressive:
>
> -- >8 --
> diff --git a/system/physmem.c b/system/physmem.c
> index b97016b1303..2988d1dd6c9 100644
> --- a/system/physmem.c
> +++ b/system/physmem.c
> @@ -2824,6 +2824,11 @@ int ram_block_rebind(Error **errp)
> {
> RAMBlock *block;
>
> + if (!kvm_enabled()) {
> + error_setg(errp, "guest-memfd requires KVM accelerator");
> + return -1;
> + }
> +
> qemu_mutex_lock_ramlist();
>
> RAMBLOCK_FOREACH(block) {
> ---
>
> WDYT?
Fine by me.
IMHO it's normally more of an issue the other way round, if we used an
assert() where we should use error_setg() (hence, user triggerable
assert()s). Here we expect it to never happen, so either way should not
happen..
If so, we could also assert() in ram_block_rebind(), as it's only used in
kvm_reset_vmfd() only, so I don't see how it can be reached if KVM is not
enabled first..
Thanks,
--
Peter Xu
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v4 04/12] ramblock: Rename guest_memfd to guest_memfd_private
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
` (2 preceding siblings ...)
2026-08-12 20:16 ` [PATCH v4 03/12] kvm: Provide explicit error for kvm_create_guest_memfd() Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-12 20:16 ` [PATCH v4 05/12] memory: Rename RAM_GUEST_MEMFD to RAM_GUEST_MEMFD_PRIVATE Michael Roth
` (7 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
Rename the field to reflect the fact that the guest_memfd in this case only
backs private portion of the ramblock rather than all of it.
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
accel/kvm/kvm-all.c | 2 +-
include/system/memory.h | 7 ++++---
include/system/ramblock.h | 7 ++++++-
system/memory.c | 2 +-
system/physmem.c | 33 +++++++++++++++++----------------
5 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index bda2e25a66..3afe491242 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -1729,7 +1729,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
mem->ram_start_offset = ram_start_offset;
mem->ram = ram;
mem->flags = kvm_mem_flags(mr);
- mem->guest_memfd = mr->ram_block->guest_memfd;
+ mem->guest_memfd = mr->ram_block->guest_memfd_private;
mem->guest_memfd_offset = mem->guest_memfd >= 0 ?
(uint8_t*)ram - mr->ram_block->host : 0;
diff --git a/include/system/memory.h b/include/system/memory.h
index 2192fc9bdc..96b0a0a444 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -1507,10 +1507,11 @@ bool memory_region_skip_iommu_map(const MemoryRegion *mr);
void memory_region_set_skip_iommu_map(MemoryRegion *mr, bool skip);
/**
- * memory_region_has_guest_memfd: check whether a memory region has guest_memfd
- * associated
+ * memory_region_has_guest_memfd: check whether a memory region has
+ * guest_memfd_private associated
*
- * Returns %true if a memory region's ram_block has valid guest_memfd assigned.
+ * Returns %true if a memory region's ram_block has valid guest_memfd_private
+ * assigned.
*
* @mr: the memory region being queried
*/
diff --git a/include/system/ramblock.h b/include/system/ramblock.h
index f0639287bf..8ed5e10710 100644
--- a/include/system/ramblock.h
+++ b/include/system/ramblock.h
@@ -40,7 +40,12 @@ struct RAMBlock {
Error *cpr_blocker;
int fd;
uint64_t fd_offset;
- int guest_memfd;
+ /*
+ * When RAM_GUEST_MEMFD_PRIVATE flag is set, this ramblock can have
+ * private pages backed by guest_memfd_private specified, while shared
+ * pages are backed by the ramblock on its own.
+ */
+ int guest_memfd_private;
RamBlockAttributes *attributes;
size_t page_size;
/* dirty bitmap used during migration */
diff --git a/system/memory.c b/system/memory.c
index 5fc36708ec..4e6d54148e 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -1843,7 +1843,7 @@ void memory_region_set_skip_iommu_map(MemoryRegion *mr, bool skip)
bool memory_region_has_guest_memfd(const MemoryRegion *mr)
{
- return mr->ram_block && mr->ram_block->guest_memfd >= 0;
+ return mr->ram_block && mr->ram_block->guest_memfd_private >= 0;
}
uint8_t memory_region_get_dirty_log_mask(const MemoryRegion *mr)
diff --git a/system/physmem.c b/system/physmem.c
index 406338f165..b979518bf6 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -2200,7 +2200,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
goto out_free;
}
- assert(new_block->guest_memfd < 0);
+ assert(new_block->guest_memfd_private < 0);
ret = ram_block_coordinated_discard_require(true);
if (ret < 0) {
@@ -2210,9 +2210,9 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
goto out_free;
}
- new_block->guest_memfd = kvm_create_guest_memfd(new_block->max_length,
- 0, errp);
- if (new_block->guest_memfd < 0) {
+ new_block->guest_memfd_private =
+ kvm_create_guest_memfd(new_block->max_length, 0, errp);
+ if (new_block->guest_memfd_private < 0) {
qemu_mutex_unlock_ramlist();
goto out_free;
}
@@ -2229,7 +2229,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
new_block->attributes = ram_block_attributes_create(new_block);
if (!new_block->attributes) {
error_setg(errp, "Failed to create ram block attribute");
- close(new_block->guest_memfd);
+ close(new_block->guest_memfd_private);
ram_block_coordinated_discard_require(false);
qemu_mutex_unlock_ramlist();
goto out_free;
@@ -2365,7 +2365,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, ram_addr_t max_size,
new_block->max_length = max_size;
new_block->resized = resized;
new_block->flags = ram_flags;
- new_block->guest_memfd = -1;
+ new_block->guest_memfd_private = -1;
new_block->host = file_ram_alloc(new_block, max_size, fd,
file_size < offset + max_size,
offset, errp);
@@ -2538,7 +2538,7 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
new_block->used_length = size;
new_block->max_length = max_size;
new_block->fd = -1;
- new_block->guest_memfd = -1;
+ new_block->guest_memfd_private = -1;
new_block->page_size = qemu_real_host_page_size();
new_block->host = host;
new_block->flags = ram_flags;
@@ -2589,8 +2589,8 @@ static void reclaim_ramblock(RAMBlock *block)
qemu_anon_ram_free(block->host, block->max_length);
}
- if (block->guest_memfd >= 0) {
- close(block->guest_memfd);
+ if (block->guest_memfd_private >= 0) {
+ close(block->guest_memfd_private);
ram_block_coordinated_discard_require(false);
}
@@ -2838,12 +2838,12 @@ int ram_block_rebind(Error **errp)
RAMBLOCK_FOREACH(block) {
if (block->flags & RAM_GUEST_MEMFD) {
- if (block->guest_memfd >= 0) {
- close(block->guest_memfd);
+ if (block->guest_memfd_private >= 0) {
+ close(block->guest_memfd_private);
}
- block->guest_memfd = kvm_create_guest_memfd(block->max_length,
- 0, errp);
- if (block->guest_memfd < 0) {
+ block->guest_memfd_private = kvm_create_guest_memfd(
+ block->max_length, 0, errp);
+ if (block->guest_memfd_private < 0) {
qemu_mutex_unlock_ramlist();
return -1;
}
@@ -4227,7 +4227,7 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t offset, size_t length)
return ret;
}
- if (rb->guest_memfd >= 0) {
+ if (rb->guest_memfd_private >= 0) {
ret = ram_block_discard_guest_memfd_range(rb, offset, length);
}
@@ -4241,7 +4241,8 @@ int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t offset,
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
/* ignore fd_offset with guest_memfd */
- ret = fallocate(rb->guest_memfd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ ret = fallocate(rb->guest_memfd_private,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
offset, length);
if (ret) {
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v4 05/12] memory: Rename RAM_GUEST_MEMFD to RAM_GUEST_MEMFD_PRIVATE
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
` (3 preceding siblings ...)
2026-08-12 20:16 ` [PATCH v4 04/12] ramblock: Rename guest_memfd to guest_memfd_private Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-12 20:16 ` [PATCH v4 06/12] memory: Rename memory_region_has_guest_memfd() to *_private() Michael Roth
` (6 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
This name is too generic, and can conflict with support for using
guest-memfd for shared memory. Add a _PRIVATE suffix to show what it
really means: it is using guest_memfd specifically for private memory;
whether or not guest_memfd is being used for shared memory is something
to be configured/determined separately.
This also paves way for in-place guest-memfd, which means we can have a
ramblock that allocates pages completely from guest-memfd (private or
shared).
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
backends/hostmem-file.c | 2 +-
backends/hostmem-memfd.c | 2 +-
backends/hostmem-ram.c | 2 +-
backends/hostmem-shm.c | 2 +-
include/system/memory.h | 8 ++++----
include/system/ramblock.h | 2 +-
system/memory.c | 2 +-
system/physmem.c | 10 +++++-----
8 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c
index 8e3219c061..1f20cd8fd6 100644
--- a/backends/hostmem-file.c
+++ b/backends/hostmem-file.c
@@ -86,7 +86,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
ram_flags |= fb->readonly ? RAM_READONLY_FD : 0;
ram_flags |= fb->rom == ON_OFF_AUTO_ON ? RAM_READONLY : 0;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
- ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
+ ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD_PRIVATE : 0;
ram_flags |= fb->is_pmem ? RAM_PMEM : 0;
ram_flags |= RAM_NAMED_FILE;
return memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name,
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
index 923239f9cf..3f3e485709 100644
--- a/backends/hostmem-memfd.c
+++ b/backends/hostmem-memfd.c
@@ -60,7 +60,7 @@ have_fd:
backend->aligned = true;
ram_flags = backend->share ? RAM_SHARED : RAM_PRIVATE;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
- ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
+ ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD_PRIVATE : 0;
return memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name,
backend->size, ram_flags, fd, 0, errp);
}
diff --git a/backends/hostmem-ram.c b/backends/hostmem-ram.c
index 062b1abb11..96ad29112d 100644
--- a/backends/hostmem-ram.c
+++ b/backends/hostmem-ram.c
@@ -30,7 +30,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
name = host_memory_backend_get_name(backend);
ram_flags = backend->share ? RAM_SHARED : RAM_PRIVATE;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
- ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
+ ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD_PRIVATE : 0;
return memory_region_init_ram_flags_nomigrate(&backend->mr, OBJECT(backend),
name, backend->size,
ram_flags, errp);
diff --git a/backends/hostmem-shm.c b/backends/hostmem-shm.c
index 806e2670e0..e86fb2e0aa 100644
--- a/backends/hostmem-shm.c
+++ b/backends/hostmem-shm.c
@@ -54,7 +54,7 @@ have_fd:
/* Let's do the same as memory-backend-ram,share=on would do. */
ram_flags = RAM_SHARED;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
- ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0;
+ ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD_PRIVATE : 0;
return memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
backend_name, backend->size,
diff --git a/include/system/memory.h b/include/system/memory.h
index 96b0a0a444..e960738af5 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -262,7 +262,7 @@ typedef struct IOMMUTLBEvent {
#define RAM_READONLY_FD (1 << 11)
/* RAM can be private that has kvm guest memfd backend */
-#define RAM_GUEST_MEMFD (1 << 12)
+#define RAM_GUEST_MEMFD_PRIVATE (1 << 12)
/*
* In RAMBlock creation functions, if MAP_SHARED is 0 in the flags parameter,
@@ -1119,7 +1119,7 @@ void memory_region_init_io(MemoryRegion *mr,
* must be unique within any device
* @size: size of the region.
* @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_NORESERVE,
- * RAM_GUEST_MEMFD.
+ * RAM_GUEST_MEMFD_PRIVATE.
* @errp: pointer to Error*, to store an error if it happens.
*
* Note that this function does not do anything to cause the data in the
@@ -1181,7 +1181,7 @@ bool memory_region_init_resizeable_ram(MemoryRegion *mr,
* (getpagesize()) will be used.
* @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
* RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
- * RAM_READONLY_FD, RAM_GUEST_MEMFD
+ * RAM_READONLY_FD, RAM_GUEST_MEMFD_PRIVATE
* @path: the path in which to allocate the RAM.
* @offset: offset within the file referenced by path
* @errp: pointer to Error*, to store an error if it happens.
@@ -1212,7 +1212,7 @@ bool memory_region_init_ram_from_file(MemoryRegion *mr,
* @size: size of the region.
* @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
* RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
- * RAM_READONLY_FD, RAM_GUEST_MEMFD
+ * RAM_READONLY_FD, RAM_GUEST_MEMFD_PRIVATE
* @fd: the fd to mmap.
* @offset: offset within the file referenced by fd
* @errp: pointer to Error*, to store an error if it happens.
diff --git a/include/system/ramblock.h b/include/system/ramblock.h
index 8ed5e10710..4550a19a3f 100644
--- a/include/system/ramblock.h
+++ b/include/system/ramblock.h
@@ -251,7 +251,7 @@ static inline unsigned long int ramblock_recv_bitmap_offset(void *host_addr,
* @resized: callback after calls to qemu_ram_resize
* @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
* RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
- * RAM_READONLY_FD, RAM_GUEST_MEMFD
+ * RAM_READONLY_FD, RAM_GUEST_MEMFD_PRIVATE
* @mem_path or @fd: specify the backing file or device
* @offset: Offset into target file
* @grow: extend file if necessary (but an empty file is always extended).
diff --git a/system/memory.c b/system/memory.c
index 4e6d54148e..84dcd9954e 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -3660,7 +3660,7 @@ bool memory_region_init_ram_guest_memfd(MemoryRegion *mr, Object *owner,
Error **errp)
{
if (!memory_region_init_ram_flags_nomigrate(mr, owner, name, size,
- RAM_GUEST_MEMFD, errp)) {
+ RAM_GUEST_MEMFD_PRIVATE, errp)) {
return false;
}
memory_region_register_ram(mr, owner);
diff --git a/system/physmem.c b/system/physmem.c
index b979518bf6..3a7a1a8b16 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -2184,7 +2184,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
}
}
- if (new_block->flags & RAM_GUEST_MEMFD) {
+ if (new_block->flags & RAM_GUEST_MEMFD_PRIVATE) {
int ret;
if (!kvm_enabled()) {
@@ -2321,7 +2321,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, ram_addr_t max_size,
/* Just support these ram flags by now. */
assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE |
RAM_PROTECTED | RAM_NAMED_FILE | RAM_READONLY |
- RAM_READONLY_FD | RAM_GUEST_MEMFD |
+ RAM_READONLY_FD | RAM_GUEST_MEMFD_PRIVATE |
RAM_RESIZEABLE)) == 0);
assert(max_size >= size);
@@ -2478,7 +2478,7 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
ram_flags &= ~RAM_PRIVATE;
assert((ram_flags & ~(RAM_SHARED | RAM_RESIZEABLE | RAM_PREALLOC |
- RAM_NORESERVE | RAM_GUEST_MEMFD)) == 0);
+ RAM_NORESERVE | RAM_GUEST_MEMFD_PRIVATE)) == 0);
assert(!host ^ (ram_flags & RAM_PREALLOC));
assert(max_size >= size);
@@ -2561,7 +2561,7 @@ RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
RAMBlock *qemu_ram_alloc(ram_addr_t size, uint32_t ram_flags,
MemoryRegion *mr, Error **errp)
{
- assert((ram_flags & ~(RAM_SHARED | RAM_NORESERVE | RAM_GUEST_MEMFD |
+ assert((ram_flags & ~(RAM_SHARED | RAM_NORESERVE | RAM_GUEST_MEMFD_PRIVATE |
RAM_PRIVATE)) == 0);
return qemu_ram_alloc_internal(size, size, NULL, NULL, ram_flags, mr, errp);
}
@@ -2837,7 +2837,7 @@ int ram_block_rebind(Error **errp)
qemu_mutex_lock_ramlist();
RAMBLOCK_FOREACH(block) {
- if (block->flags & RAM_GUEST_MEMFD) {
+ if (block->flags & RAM_GUEST_MEMFD_PRIVATE) {
if (block->guest_memfd_private >= 0) {
close(block->guest_memfd_private);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v4 06/12] memory: Rename memory_region_has_guest_memfd() to *_private()
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
` (4 preceding siblings ...)
2026-08-12 20:16 ` [PATCH v4 05/12] memory: Rename RAM_GUEST_MEMFD to RAM_GUEST_MEMFD_PRIVATE Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-12 20:16 ` [PATCH v4 07/12] hostmem: Rename guest_memfd to guest_memfd_private Michael Roth
` (5 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
Rename the function with "_private" suffix, to show that it returns true
only if it has an internal guest-memfd to back private pages (rather than
fully shared guest-memfd).
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
accel/kvm/kvm-all.c | 6 +++---
include/system/memory.h | 4 ++--
system/memory.c | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 3afe491242..9e73c84f7c 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -792,7 +792,7 @@ static int kvm_mem_flags(MemoryRegion *mr)
if (readonly && kvm_readonly_mem_allowed) {
flags |= KVM_MEM_READONLY;
}
- if (memory_region_has_guest_memfd(mr)) {
+ if (memory_region_has_guest_memfd_private(mr)) {
assert(kvm_guest_memfd_supported);
flags |= KVM_MEM_GUEST_MEMFD;
}
@@ -1741,7 +1741,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
abort();
}
- if (memory_region_has_guest_memfd(mr)) {
+ if (memory_region_has_guest_memfd_private(mr)) {
err = kvm_set_memory_attributes_private(start_addr, slot_size);
if (err) {
error_report("%s: failed to set memory attribute private: %s",
@@ -3372,7 +3372,7 @@ int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
return ret;
}
- if (!memory_region_has_guest_memfd(mr)) {
+ if (!memory_region_has_guest_memfd_private(mr)) {
/*
* Because vMMIO region must be shared, guest TD may convert vMMIO
* region to shared explicitly. Don't complain such case. See
diff --git a/include/system/memory.h b/include/system/memory.h
index e960738af5..e3096699ba 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -1507,7 +1507,7 @@ bool memory_region_skip_iommu_map(const MemoryRegion *mr);
void memory_region_set_skip_iommu_map(MemoryRegion *mr, bool skip);
/**
- * memory_region_has_guest_memfd: check whether a memory region has
+ * memory_region_has_guest_memfd_private: check whether a memory region has
* guest_memfd_private associated
*
* Returns %true if a memory region's ram_block has valid guest_memfd_private
@@ -1515,7 +1515,7 @@ void memory_region_set_skip_iommu_map(MemoryRegion *mr, bool skip);
*
* @mr: the memory region being queried
*/
-bool memory_region_has_guest_memfd(const MemoryRegion *mr);
+bool memory_region_has_guest_memfd_private(const MemoryRegion *mr);
/**
* memory_region_get_iommu: check whether a memory region is an iommu
diff --git a/system/memory.c b/system/memory.c
index 84dcd9954e..db52cfe90e 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -1841,7 +1841,7 @@ void memory_region_set_skip_iommu_map(MemoryRegion *mr, bool skip)
mr->ram_device_skip_iommu_map = skip;
}
-bool memory_region_has_guest_memfd(const MemoryRegion *mr)
+bool memory_region_has_guest_memfd_private(const MemoryRegion *mr)
{
return mr->ram_block && mr->ram_block->guest_memfd_private >= 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v4 07/12] hostmem: Rename guest_memfd to guest_memfd_private
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
` (5 preceding siblings ...)
2026-08-12 20:16 ` [PATCH v4 06/12] memory: Rename memory_region_has_guest_memfd() to *_private() Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-12 20:16 ` [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM Michael Roth
` (4 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
Rename the HostMemoryBackend.guest_memfd field to reflect what it really
means: whether it needs guest_memfd to back its private guest memory.
This will help avoid conflicts when we introduce supported for using
guest_memfd for shared guest memory via hostmem.
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
backends/hostmem-file.c | 2 +-
backends/hostmem-memfd.c | 2 +-
backends/hostmem-ram.c | 2 +-
backends/hostmem-shm.c | 2 +-
backends/hostmem.c | 2 +-
include/system/hostmem.h | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c
index 1f20cd8fd6..0e4cfd6dc6 100644
--- a/backends/hostmem-file.c
+++ b/backends/hostmem-file.c
@@ -86,7 +86,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
ram_flags |= fb->readonly ? RAM_READONLY_FD : 0;
ram_flags |= fb->rom == ON_OFF_AUTO_ON ? RAM_READONLY : 0;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
- ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD_PRIVATE : 0;
+ ram_flags |= backend->guest_memfd_private ? RAM_GUEST_MEMFD_PRIVATE : 0;
ram_flags |= fb->is_pmem ? RAM_PMEM : 0;
ram_flags |= RAM_NAMED_FILE;
return memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name,
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
index 3f3e485709..ea93f034e4 100644
--- a/backends/hostmem-memfd.c
+++ b/backends/hostmem-memfd.c
@@ -60,7 +60,7 @@ have_fd:
backend->aligned = true;
ram_flags = backend->share ? RAM_SHARED : RAM_PRIVATE;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
- ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD_PRIVATE : 0;
+ ram_flags |= backend->guest_memfd_private ? RAM_GUEST_MEMFD_PRIVATE : 0;
return memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name,
backend->size, ram_flags, fd, 0, errp);
}
diff --git a/backends/hostmem-ram.c b/backends/hostmem-ram.c
index 96ad29112d..6a507fad77 100644
--- a/backends/hostmem-ram.c
+++ b/backends/hostmem-ram.c
@@ -30,7 +30,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
name = host_memory_backend_get_name(backend);
ram_flags = backend->share ? RAM_SHARED : RAM_PRIVATE;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
- ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD_PRIVATE : 0;
+ ram_flags |= backend->guest_memfd_private ? RAM_GUEST_MEMFD_PRIVATE : 0;
return memory_region_init_ram_flags_nomigrate(&backend->mr, OBJECT(backend),
name, backend->size,
ram_flags, errp);
diff --git a/backends/hostmem-shm.c b/backends/hostmem-shm.c
index e86fb2e0aa..4766db6aad 100644
--- a/backends/hostmem-shm.c
+++ b/backends/hostmem-shm.c
@@ -54,7 +54,7 @@ have_fd:
/* Let's do the same as memory-backend-ram,share=on would do. */
ram_flags = RAM_SHARED;
ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
- ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD_PRIVATE : 0;
+ ram_flags |= backend->guest_memfd_private ? RAM_GUEST_MEMFD_PRIVATE : 0;
return memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
backend_name, backend->size,
diff --git a/backends/hostmem.c b/backends/hostmem.c
index 5dd5fb155c..d54d9091c3 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -290,7 +290,7 @@ static void host_memory_backend_init(Object *obj)
/* TODO: convert access to globals to compat properties */
backend->merge = machine_mem_merge(machine);
backend->dump = machine_dump_guest_core(machine);
- backend->guest_memfd = machine_require_guest_memfd(machine);
+ backend->guest_memfd_private = machine_require_guest_memfd(machine);
backend->reserve = true;
backend->prealloc_threads = machine->smp.cpus;
}
diff --git a/include/system/hostmem.h b/include/system/hostmem.h
index 88fa791ac7..dcbf81aeae 100644
--- a/include/system/hostmem.h
+++ b/include/system/hostmem.h
@@ -76,7 +76,7 @@ struct HostMemoryBackend {
uint64_t size;
bool merge, dump, use_canonical_path;
bool prealloc, is_mapped, share, reserve;
- bool guest_memfd, aligned;
+ bool guest_memfd_private, aligned;
uint32_t prealloc_threads;
ThreadContext *prealloc_context;
DECLARE_BITMAP(host_nodes, MAX_NODES + 1);
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
` (6 preceding siblings ...)
2026-08-12 20:16 ` [PATCH v4 07/12] hostmem: Rename guest_memfd to guest_memfd_private Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-13 8:24 ` Daniel P. Berrangé
2026-08-12 20:16 ` [PATCH v4 09/12] machine: Rename machine_require_guest_memfd() to *_private() Michael Roth
` (3 subsequent siblings)
11 siblings, 1 reply; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
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 <peterx@redhat.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
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");
+ }
+
+ 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' }
##
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM
2026-08-12 20:16 ` [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM Michael Roth
@ 2026-08-13 8:24 ` Daniel P. Berrangé
2026-08-13 12:28 ` Peter Xu
0 siblings, 1 reply; 22+ messages in thread
From: Daniel P. Berrangé @ 2026-08-13 8:24 UTC (permalink / raw)
To: Michael Roth
Cc: qemu-devel, jmarcin, david, pbonzini, chenyi.qiang, peterx,
farosas, aik, xiaoyao.li
On Wed, Aug 12, 2026 at 03:16:46PM -0500, Michael Roth wrote:
> From: Peter Xu <peterx@redhat.com>
>
> 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 <peterx@redhat.com>
> Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> Reviewed-by: Fabiano Rosas <farosas@suse.de>
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> ---
> 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.
"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.
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 :|
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM
2026-08-13 8:24 ` Daniel P. Berrangé
@ 2026-08-13 12:28 ` Peter Xu
2026-08-13 12:48 ` Daniel P. Berrangé
0 siblings, 1 reply; 22+ messages in thread
From: Peter Xu @ 2026-08-13 12:28 UTC (permalink / raw)
To: Daniel P. Berrangé
Cc: Michael Roth, qemu-devel, jmarcin, david, pbonzini, chenyi.qiang,
farosas, aik, xiaoyao.li
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 <peterx@redhat.com>
> >
> > 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 <peterx@redhat.com>
> > Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > Reviewed-by: Fabiano Rosas <farosas@suse.de>
> > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > ---
> > 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.
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.
>
> "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.
Please check if you agree after reading above. We can definitely still
rethink the interfacing.
Thanks,
--
Peter Xu
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM
2026-08-13 12:28 ` Peter Xu
@ 2026-08-13 12:48 ` Daniel P. Berrangé
2026-08-13 14:06 ` Peter Xu
2026-08-13 22:10 ` Michael Roth via qemu development
0 siblings, 2 replies; 22+ messages in thread
From: Daniel P. Berrangé @ 2026-08-13 12:48 UTC (permalink / raw)
To: Peter Xu
Cc: Michael Roth, qemu-devel, jmarcin, david, pbonzini, chenyi.qiang,
farosas, aik, xiaoyao.li
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 <peterx@redhat.com>
> > >
> > > 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 <peterx@redhat.com>
> > > Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > > Reviewed-by: Fabiano Rosas <farosas@suse.de>
> > > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > > ---
> > > 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.
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.
> 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.
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 :|
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM
2026-08-13 12:48 ` Daniel P. Berrangé
@ 2026-08-13 14:06 ` Peter Xu
2026-08-14 15:19 ` Daniel P. Berrangé
2026-08-13 22:10 ` Michael Roth via qemu development
1 sibling, 1 reply; 22+ messages in thread
From: Peter Xu @ 2026-08-13 14:06 UTC (permalink / raw)
To: Daniel P. Berrangé
Cc: Michael Roth, qemu-devel, jmarcin, david, pbonzini, chenyi.qiang,
farosas, aik, xiaoyao.li
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 <peterx@redhat.com>
> > > >
> > > > 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 <peterx@redhat.com>
> > > > Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > > > Reviewed-by: Fabiano Rosas <farosas@suse.de>
> > > > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > > > ---
> > > > 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.
>
> 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.
>
> > 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.
>
> 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.
The idea of that, at least in my mind.. is an user shouldn't need to worry
about differences of guest-memfd and memfd, QEMU should just do it for the
users, based on the machine configurations. Memfd is a concept more widely
spread, the hope is anyone using guest-memfd should simply treat it as one
memfd, no matter it is shared, in-place converted, two-layer-backed, or
whatever is happening underneath.
Now we do create guest-memfd via a separate ioctl, what if we can create it
via memfd_create() syscall too? Then do we need to do the separation from
QEMU layer?
IMHO that is now an ioctl is not required; it really can be part of
memfd_create() syscall, it's just easier to manage, e.g. it's completely
KVM alone, and it also has attached to the KVM instance. The idea is still
similar, and we can see that from possibly shared properties here on huge
pages and so. I don't treat seal= a block just to introduce a new object
for that, and I expect as gmemfd evolves it will gradually get most
features memfd supports.. like folio migration and so.. but I could be
wrong.
IMHO one major question to ask is, is it more convenient for libvirt to
have that new object? Please keep in mind that after we introduce this as
a new object, we may start to introduce even more *-guest-memfd in the
future, we roughly talked about DAX in the previous discussion. My goal is
to make it most convenient for either user or libvirt to maintain the
cmdlines for QEMU, but if you think that makes libvirt live harder instead,
I've no strong feeling to go back to what Michael initially suggested.
For example, if libvirt wants to detect hugetlb supports for an object, it
can still pass in the parameters and test-boot a QEMU and then IIUC it'll
still correctly capture an error for gmemfd case. It might be that I
didn't really get what will make libvirt complex by reusing the object, but
I'll definitely follow your judgement on that.
Thanks,
--
Peter Xu
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM
2026-08-13 14:06 ` Peter Xu
@ 2026-08-14 15:19 ` Daniel P. Berrangé
0 siblings, 0 replies; 22+ messages in thread
From: Daniel P. Berrangé @ 2026-08-14 15:19 UTC (permalink / raw)
To: Peter Xu
Cc: Michael Roth, qemu-devel, jmarcin, david, pbonzini, chenyi.qiang,
farosas, aik, xiaoyao.li
On Thu, Aug 13, 2026 at 10:06:17AM -0400, Peter Xu wrote:
> 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 <peterx@redhat.com>
> > > > >
> > > > > 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 <peterx@redhat.com>
> > > > > Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > > > > Reviewed-by: Fabiano Rosas <farosas@suse.de>
> > > > > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > > > > ---
> > > > > backends/hostmem-memfd.c | 56 ++++++++++++++++++++++++++++++++++++----
> > > > > qapi/qom.json | 6 ++++-
> > > > > 2 files changed, 56 insertions(+), 6 deletions(-)
snip
> > > > "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.
> >
> > 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.
>
> The idea of that, at least in my mind.. is an user shouldn't need to worry
> about differences of guest-memfd and memfd, QEMU should just do it for the
> users, based on the machine configurations. Memfd is a concept more widely
> spread, the hope is anyone using guest-memfd should simply treat it as one
> memfd, no matter it is shared, in-place converted, two-layer-backed, or
> whatever is happening underneath.
>
> Now we do create guest-memfd via a separate ioctl, what if we can create it
> via memfd_create() syscall too? Then do we need to do the separation from
> QEMU layer?
If QEMU automatically did "the right thing" choosing between traditional
memfd and guest-memfd, then I wouldn't have even started this thread :-)
The "guest-memfd=on|off" is the trigger that made me think the design
was wrong from a public interface POV, as that explicitly says that the
memfd vs guest-memfd distinction is not automatic - it requires the
mgmt app to understand it and choose between them.
> IMHO that is now an ioctl is not required; it really can be part of
> memfd_create() syscall, it's just easier to manage, e.g. it's completely
> KVM alone, and it also has attached to the KVM instance. The idea is still
> similar, and we can see that from possibly shared properties here on huge
> pages and so. I don't treat seal= a block just to introduce a new object
> for that, and I expect as gmemfd evolves it will gradually get most
> features memfd supports.. like folio migration and so.. but I could be
> wrong.
>
> IMHO one major question to ask is, is it more convenient for libvirt to
> have that new object? Please keep in mind that after we introduce this as
> a new object, we may start to introduce even more *-guest-memfd in the
> future, we roughly talked about DAX in the previous discussion. My goal is
> to make it most convenient for either user or libvirt to maintain the
> cmdlines for QEMU, but if you think that makes libvirt live harder instead,
> I've no strong feeling to go back to what Michael initially suggested.
It is no more or less difficult for libvirt to use different object
types vs using different guest-memfd=bool values.
What makes a difference for libvirt is understanding whether QEMU
implements a given feature or not.
If we have the situation with
memory-backend-memfd,hugetlb=bool,guest-memfd=bool
with this series, IIUC, libvirt can introspect to see the new
guest-memfd property, but it has no way of knowing that it can't
use the hugetlb proeprty when guest-memfd=on
If the next QEMU release now permits hugetlb=on at the same time
as guest-memfd=on, then libvirt has no way to know the restriction
was relaxed.
The QAPI introspection data for memory-backend-memfd is identical
in both cases.
To deal with this, you need to introduce a workaround to QAPI
by declaring a feature flag like
features: ['hugetlb-with-guest-memfd-works']
that libvirt can probe for to determine the functional improvement
in QEMU.
By comparison, if we introduce a memory-backend-guest-memfd
object today, then it will omit the hugetlb property entirely.
If the next QEMU release adds a hugetlb property to the
memory-backend-guest-memfd object, this change is now visible
in the introspection data, and thus libvirt knows that combo
is possible with QEMU
(yes, there is the issue that this might have kernel dependancy
that is not visible from QEMU's introspection, so not perfect,
but at least libvirt can determine what QEMU is capable of)
> For example, if libvirt wants to detect hugetlb supports for an object, it
> can still pass in the parameters and test-boot a QEMU and then IIUC it'll
> still correctly capture an error for gmemfd case. It might be that I
> didn't really get what will make libvirt complex by reusing the object, but
> I'll definitely follow your judgement on that.
Trying parameters to see if they fail and then boot again with different
options is not a viable approach. That is an indication that QEMU's
design and/or introspection is flawed.
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 :|
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM
2026-08-13 12:48 ` Daniel P. Berrangé
2026-08-13 14:06 ` Peter Xu
@ 2026-08-13 22:10 ` Michael Roth via qemu development
2026-08-14 15:27 ` Daniel P. Berrangé
1 sibling, 1 reply; 22+ messages in thread
From: Michael Roth via qemu development @ 2026-08-13 22:10 UTC (permalink / raw)
To: Daniel P. Berrangé
Cc: Peter Xu, qemu-devel, jmarcin, david, pbonzini, chenyi.qiang,
farosas, aik, xiaoyao.li
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 <peterx@redhat.com>
> > > >
> > > > 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 <peterx@redhat.com>
> > > > Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > > > Reviewed-by: Fabiano Rosas <farosas@suse.de>
> > > > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > > > ---
> > > > 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 :|
>
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM
2026-08-13 22:10 ` Michael Roth via qemu development
@ 2026-08-14 15:27 ` Daniel P. Berrangé
0 siblings, 0 replies; 22+ messages in thread
From: Daniel P. Berrangé @ 2026-08-14 15:27 UTC (permalink / raw)
To: Michael Roth
Cc: Peter Xu, qemu-devel, jmarcin, david, pbonzini, chenyi.qiang,
farosas, aik, xiaoyao.li
On Thu, Aug 13, 2026 at 05:10:45PM -0500, Michael Roth wrote:
> 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 <peterx@redhat.com>
> > > > >
> > > > > 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 <peterx@redhat.com>
> > > > > Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > > > > Reviewed-by: Fabiano Rosas <farosas@suse.de>
> > > > > Signed-off-by: Michael Roth <michael.roth@amd.com>
> > > > > ---
> > > > > backends/hostmem-memfd.c | 56 ++++++++++++++++++++++++++++++++++++----
> > > > > qapi/qom.json | 6 ++++-
> > > > > 2 files changed, 56 insertions(+), 6 deletions(-)
snip
> > > > > 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?
The difference only matters if what QEMU supports changes over
time. eg if current QEMU required 'reserve=off', but later
changed to allow either reserve=on or reserve=off, as libvirt
can't introspect the built-in runtime restriction.
> 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.
Yes, the varying kernel dependancy makes the QEMU introspection less
valuable than it would otherwise be :-(
> 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.
Hmm, if we think that even a separate memory-backend-guest-memfd is not
going to suitable / sufficiently flexible for future enhancements, that
reduces its value somewhat :-(
> > > 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.
Ah, I missed that the guest_memfd stuff for Coco is magically
handled with QEMU able to "do the right thing" there.
> 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.
Yes, if we think we can make QEMU "do the right thing" internally
that makes a separate object much less desirable. That would
be saying that we have a tri-state, guest_memfd=auto|on|off,
and such tri-state's would not invite a separate sub-class
design. The need for "auto" rather forces the approach you have
in this patch.
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 :|
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v4 09/12] machine: Rename machine_require_guest_memfd() to *_private()
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
` (7 preceding siblings ...)
2026-08-12 20:16 ` [PATCH v4 08/12] hostmem: Support fully shared guest memfd to back a VM Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-12 20:16 ` [PATCH v4 10/12] memory: Rename memory_region_init_ram_guest_memfd() " Michael Roth
` (2 subsequent siblings)
11 siblings, 0 replies; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
Differenciate it from fully shared guest-memfd use cases.
When at it, add proper brackets in kvm_handle_hc_map_gpa_range() otherwise
checkpatch may complain.
Suggested-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
backends/hostmem.c | 2 +-
hw/core/machine.c | 2 +-
hw/i386/pc.c | 2 +-
hw/i386/pc_sysfw.c | 4 ++--
hw/i386/x86-common.c | 4 ++--
include/hw/core/boards.h | 2 +-
target/i386/kvm/kvm.c | 3 ++-
7 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/backends/hostmem.c b/backends/hostmem.c
index d54d9091c3..0cc5adcd38 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -290,7 +290,7 @@ static void host_memory_backend_init(Object *obj)
/* TODO: convert access to globals to compat properties */
backend->merge = machine_mem_merge(machine);
backend->dump = machine_dump_guest_core(machine);
- backend->guest_memfd_private = machine_require_guest_memfd(machine);
+ backend->guest_memfd_private = machine_require_guest_memfd_private(machine);
backend->reserve = true;
backend->prealloc_threads = machine->smp.cpus;
}
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 73b4d82b4a..b78e9c2135 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -1330,7 +1330,7 @@ bool machine_mem_merge(MachineState *machine)
return machine->mem_merge;
}
-bool machine_require_guest_memfd(MachineState *machine)
+bool machine_require_guest_memfd_private(MachineState *machine)
{
return machine->cgs && machine->cgs->require_guest_memfd;
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index f064aa2b3e..3ca8468c0f 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -870,7 +870,7 @@ void pc_memory_init(PCMachineState *pcms,
if (!is_tdx_vm()) {
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
- if (machine_require_guest_memfd(machine)) {
+ if (machine_require_guest_memfd_private(machine)) {
memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
PC_ROM_SIZE, &error_fatal);
} else {
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 1a41a5972b..4a7694c131 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -51,7 +51,7 @@ static void pc_isa_bios_init(PCMachineState *pcms, MemoryRegion *isa_bios,
/* map the last 128KB of the BIOS in ISA space */
isa_bios_size = MIN(flash_size, 128 * KiB);
- if (machine_require_guest_memfd(MACHINE(pcms))) {
+ if (machine_require_guest_memfd_private(MACHINE(pcms))) {
memory_region_init_ram_guest_memfd(isa_bios, NULL, "isa-bios",
isa_bios_size, &error_fatal);
} else {
@@ -70,7 +70,7 @@ static void pc_isa_bios_init(PCMachineState *pcms, MemoryRegion *isa_bios,
((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
isa_bios_size);
- if (!machine_require_guest_memfd(current_machine)) {
+ if (!machine_require_guest_memfd_private(current_machine)) {
memory_region_set_readonly(isa_bios, true);
}
}
diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index 8f9419e7d3..dd526c561c 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -1036,7 +1036,7 @@ static void load_bios_from_file(X86MachineState *x86ms, const char *bios_name,
ssize_t ret;
/* BIOS load */
- if (machine_require_guest_memfd(MACHINE(x86ms))) {
+ if (machine_require_guest_memfd_private(MACHINE(x86ms))) {
memory_region_init_ram_guest_memfd(&x86ms->bios, NULL, "pc.bios",
bios_size, &error_fatal);
if (is_tdx_vm()) {
@@ -1106,7 +1106,7 @@ void x86_bios_rom_init(X86MachineState *x86ms, const char *default_firmware,
bios_size = get_bios_size(x86ms, bios_name, filename);
load_bios_from_file(x86ms, bios_name, filename, bios_size, isapc_ram_fw);
- if (!machine_require_guest_memfd(MACHINE(x86ms))) {
+ if (!machine_require_guest_memfd_private(MACHINE(x86ms))) {
/* map the last 128KB of the BIOS in ISA space */
x86_isa_bios_init(&x86ms->isa_bios, rom_memory, &x86ms->bios,
!isapc_ram_fw);
diff --git a/include/hw/core/boards.h b/include/hw/core/boards.h
index 29c68931d8..7c46db4dd9 100644
--- a/include/hw/core/boards.h
+++ b/include/hw/core/boards.h
@@ -43,7 +43,7 @@ bool machine_usb(MachineState *machine);
int machine_phandle_start(MachineState *machine);
bool machine_dump_guest_core(MachineState *machine);
bool machine_mem_merge(MachineState *machine);
-bool machine_require_guest_memfd(MachineState *machine);
+bool machine_require_guest_memfd_private(MachineState *machine);
HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine);
void machine_set_cpu_numa_node(MachineState *machine,
const CpuInstanceProperties *props,
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 4272b6770c..176d65d44f 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -6488,8 +6488,9 @@ static int kvm_handle_hc_map_gpa_range(X86CPU *cpu, struct kvm_run *run)
uint64_t gpa, size, attributes;
int ret;
- if (!machine_require_guest_memfd(current_machine))
+ if (!machine_require_guest_memfd_private(current_machine)) {
return -EINVAL;
+ }
gpa = run->hypercall.args[0];
size = run->hypercall.args[1] * TARGET_PAGE_SIZE;
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v4 10/12] memory: Rename memory_region_init_ram_guest_memfd() to *_private()
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
` (8 preceding siblings ...)
2026-08-12 20:16 ` [PATCH v4 09/12] machine: Rename machine_require_guest_memfd() to *_private() Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-12 20:16 ` [PATCH v4 11/12] tests/migration-test: Support guest-memfd init shared mem type Michael Roth
2026-08-12 20:16 ` [PATCH v4 12/12] tests/migration-test: Add a precopy test for guest-memfd Michael Roth
11 siblings, 0 replies; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
Differenciate it from fully shared guest-memfd use cases.
Suggested-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
backends/igvm.c | 4 ++--
hw/i386/pc.c | 4 ++--
hw/i386/pc_sysfw.c | 4 ++--
hw/i386/x86-common.c | 4 ++--
include/system/memory.h | 10 +++++-----
system/memory.c | 8 +++++---
6 files changed, 18 insertions(+), 16 deletions(-)
diff --git a/backends/igvm.c b/backends/igvm.c
index 80e87fe602..87e6290f46 100644
--- a/backends/igvm.c
+++ b/backends/igvm.c
@@ -256,8 +256,8 @@ static void *qigvm_prepare_memory(QIgvm *ctx, uint64_t addr, uint64_t size,
igvm_pages = g_new0(MemoryRegion, 1);
if (ctx->machine_state->cgs &&
ctx->machine_state->cgs->require_guest_memfd) {
- if (!memory_region_init_ram_guest_memfd(igvm_pages, NULL,
- region_name, size, errp)) {
+ if (!memory_region_init_ram_guest_memfd_private(
+ igvm_pages, NULL, region_name, size, errp)) {
g_free(igvm_pages);
return NULL;
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 3ca8468c0f..b9537edb82 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -871,8 +871,8 @@ void pc_memory_init(PCMachineState *pcms,
if (!is_tdx_vm()) {
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
if (machine_require_guest_memfd_private(machine)) {
- memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
- PC_ROM_SIZE, &error_fatal);
+ memory_region_init_ram_guest_memfd_private(
+ option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE, &error_fatal);
} else {
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
&error_fatal);
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 4a7694c131..3e0b9e1d28 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -52,8 +52,8 @@ static void pc_isa_bios_init(PCMachineState *pcms, MemoryRegion *isa_bios,
/* map the last 128KB of the BIOS in ISA space */
isa_bios_size = MIN(flash_size, 128 * KiB);
if (machine_require_guest_memfd_private(MACHINE(pcms))) {
- memory_region_init_ram_guest_memfd(isa_bios, NULL, "isa-bios",
- isa_bios_size, &error_fatal);
+ memory_region_init_ram_guest_memfd_private(
+ isa_bios, NULL, "isa-bios", isa_bios_size, &error_fatal);
} else {
memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size,
&error_fatal);
diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index dd526c561c..ffe9cc90b6 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -1037,8 +1037,8 @@ static void load_bios_from_file(X86MachineState *x86ms, const char *bios_name,
/* BIOS load */
if (machine_require_guest_memfd_private(MACHINE(x86ms))) {
- memory_region_init_ram_guest_memfd(&x86ms->bios, NULL, "pc.bios",
- bios_size, &error_fatal);
+ memory_region_init_ram_guest_memfd_private(
+ &x86ms->bios, NULL, "pc.bios", bios_size, &error_fatal);
if (is_tdx_vm()) {
tdx_set_tdvf_region(&x86ms->bios);
}
diff --git a/include/system/memory.h b/include/system/memory.h
index e3096699ba..d9ccb0142b 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -1358,11 +1358,11 @@ bool memory_region_init_ram(MemoryRegion *mr,
uint64_t size,
Error **errp);
-bool memory_region_init_ram_guest_memfd(MemoryRegion *mr,
- Object *owner,
- const char *name,
- uint64_t size,
- Error **errp);
+bool memory_region_init_ram_guest_memfd_private(MemoryRegion *mr,
+ Object *owner,
+ const char *name,
+ uint64_t size,
+ Error **errp);
/**
* memory_region_init_rom: Initialize a ROM memory region.
diff --git a/system/memory.c b/system/memory.c
index db52cfe90e..05b2943bcd 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -3655,9 +3655,11 @@ bool memory_region_init_ram(MemoryRegion *mr, Object *owner,
return true;
}
-bool memory_region_init_ram_guest_memfd(MemoryRegion *mr, Object *owner,
- const char *name, uint64_t size,
- Error **errp)
+bool memory_region_init_ram_guest_memfd_private(MemoryRegion *mr,
+ Object *owner,
+ const char *name,
+ uint64_t size,
+ Error **errp)
{
if (!memory_region_init_ram_flags_nomigrate(mr, owner, name, size,
RAM_GUEST_MEMFD_PRIVATE, errp)) {
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v4 11/12] tests/migration-test: Support guest-memfd init shared mem type
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
` (9 preceding siblings ...)
2026-08-12 20:16 ` [PATCH v4 10/12] memory: Rename memory_region_init_ram_guest_memfd() " Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
2026-08-12 20:16 ` [PATCH v4 12/12] tests/migration-test: Add a precopy test for guest-memfd Michael Roth
11 siblings, 0 replies; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
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 <peterx@redhat.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
tests/qtest/migration/framework.c | 60 +++++++++++++++++++++++++++++++
tests/qtest/migration/framework.h | 4 +++
2 files changed, 64 insertions(+)
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index a830b96f41..b7aef6b21c 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"
@@ -296,6 +300,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;
@@ -444,8 +451,55 @@ int migrate_args(char **from, char **to, 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 support 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)) {
@@ -453,6 +507,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;
}
diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
index 941cbd7102..10761f6e28 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;
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v4 12/12] tests/migration-test: Add a precopy test for guest-memfd
2026-08-12 20:16 [PATCH v4 00/12] KVM/hostmem: Support init-shared guest-memfd as VM backends Michael Roth
` (10 preceding siblings ...)
2026-08-12 20:16 ` [PATCH v4 11/12] tests/migration-test: Support guest-memfd init shared mem type Michael Roth
@ 2026-08-12 20:16 ` Michael Roth
11 siblings, 0 replies; 22+ messages in thread
From: Michael Roth @ 2026-08-12 20:16 UTC (permalink / raw)
To: qemu-devel
Cc: jmarcin, david, pbonzini, chenyi.qiang, peterx, farosas, aik,
xiaoyao.li
From: Peter Xu <peterx@redhat.com>
Add a plain tcp test for guest-memfd. Note that the test will be
automatically skipped whenever not supported (e.g. qemu compiled without
KVM, or host kernel doesn't support kvm, or old kernels, etc.).
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
tests/qtest/migration/precopy-tests.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index a23d51126b..8146f37d61 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -182,6 +182,14 @@ static void test_precopy_tcp_plain(char *name, MigrateCommon *args)
test_precopy_common(args);
}
+static void test_precopy_tcp_plain_gmemfd(char *name, MigrateCommon *args)
+{
+ args->uri = "tcp:127.0.0.1:0";
+ args->start.mem_type = MEM_TYPE_GUEST_MEMFD;
+
+ test_precopy_common(args);
+}
+
static void test_precopy_tcp_switchover_ack(char *name, MigrateCommon *args)
{
/*
@@ -1108,6 +1116,8 @@ void migration_test_add_precopy(MigrationTestEnv *env)
return;
}
+ migration_test_add("/migration/precopy/tcp/plain/guest-memfd",
+ test_precopy_tcp_plain_gmemfd);
migration_test_add("/migration/precopy/tcp/plain/switchover-ack",
test_precopy_tcp_switchover_ack);
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread