Re: [PATCH RFC v4 07/44] KVM: guest_memfd: Only prepare folios for private pages

Michael Roth
2026-04-01T15:16:34Z

On Wed, Apr 01, 2026 at 07:05:16AM -0700, Ackerley Tng wrote:
> Ackerley Tng <ackerleytng@google.com> writes:
>
> > All-shared guest_memfd used to be only supported for non-CoCo VMs where
> > preparation doesn't apply. INIT_SHARED is about to be supported for
> > non-CoCo VMs in a later patch in this series.
> >
> > In addition, KVM_SET_MEMORY_ATTRIBUTES2 is about to be supported in
> > guest_memfd in a later patch in this series.
> >
> > This means that the kvm fault handler may now call kvm_gmem_get_pfn() on a
> > shared folio for a CoCo VM where preparation applies.
> >
> > Add a check to make sure that preparation is only performed for private
> > folios.
> >
> > Preparation will be undone on freeing (see kvm_gmem_free_folio()) and on
> > conversion to shared.
> >
> > Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> > ---
> > virt/kvm/guest_memfd.c | 9 ++++++---
> > 1 file changed, 6 insertions(+), 3 deletions(-)
> >
> > diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> > index b6ffa8734175d..d414ebfcb4c19 100644
> > --- a/virt/kvm/guest_memfd.c
> > +++ b/virt/kvm/guest_memfd.c
> > @@ -900,6 +900,7 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
> > int *max_order)
> > {
> > pgoff_t index = kvm_gmem_get_index(slot, gfn);
> > + struct inode *inode;
> > struct folio *folio;
> > int r = 0;
> >
> > @@ -907,7 +908,8 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
> > if (!file)
> > return -EFAULT;
> >
> > - filemap_invalidate_lock_shared(file_inode(file)->i_mapping);
> > + inode = file_inode(file);
> > + filemap_invalidate_lock_shared(inode->i_mapping);
> >
> > folio = __kvm_gmem_get_pfn(file, slot, index, pfn, max_order);
> > if (IS_ERR(folio)) {
> > @@ -920,7 +922,8 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
> > folio_mark_uptodate(folio);
> > }
> >
> > - r = kvm_gmem_prepare_folio(kvm, slot, gfn, folio);
> > + if (kvm_gmem_is_private_mem(inode, index))
> > + r = kvm_gmem_prepare_folio(kvm, slot, gfn, folio);
>
> Michael, I might have misunderstood you at the last guest_memfd call:
> sev_gmem_prepare() doesn't prepare a page for being a shared page,
> right? Does this work? That prepare is only called to "make private"?

Hmm, I guess your guest_memfd-inplace-conversion-v4 branch is out of sync with
these patches?

I have the below local patch based on top of that for SNP-specific enablement,
which is basically identically, so suffice to say: yes, this should work
for SNP :) If any architecture pops up that needs to do some prep in
advance of mapping shared pages, then we could potentially plumb the
shared/private flag through to the arch-specific prep hook, as was also
suggested on the call, but it doesn't seem like that's needed by any
users for now.

-Mike

Author: Michael Roth <michael.roth@amd.com>
Date: Mon Oct 27 07:58:32 2025 -0500

KVM: guest_memfd: Don't prepare shared folios

In the current guest_memfd logic, "preparation" is only used currently
to describe the additional work of putting a guest_memfd page into an
architecturally-defined "private" state, such as updating RMP table
entries for SEV-SNP guests. As such, there's no input to the
corresponding kvm_arch_gmem_prepare() hooks as to whether a page is
being prepared/accessed as shared or as private, so "preparation" will
end up being erroneously done on pages that were supposed to remain in a
shared state. Rather than plumb through the additional information
needed to distinguish between shared vs. private preparation, just
continue to only do preparation on private pages, as was the case prior
to support for GUEST_MEMFD_FLAG_MMAP being introduced.

Signed-off-by: Michael Roth <michael.roth@amd.com>

diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 3acc6d983449..4869e59e4fc5 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -1249,7 +1249,8 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
folio_mark_uptodate(folio);
}

- r = kvm_gmem_prepare_folio(kvm, slot, gfn, folio);
+ if (!kvm_gmem_is_shared_mem(file_inode(file), index))
+ r = kvm_gmem_prepare_folio(kvm, slot, gfn, folio);

folio_unlock(folio);

>
> >
> > folio_unlock(folio);
> >
> > @@ -930,7 +933,7 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
> > folio_put(folio);
> >
> > out:
> > - filemap_invalidate_unlock_shared(file_inode(file)->i_mapping);
> > + filemap_invalidate_unlock_shared(inode->i_mapping);
> > return r;
> > }
> > EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_gmem_get_pfn);
> >
> > --
> > 2.53.0.1018.g2bb0e51243-goog