From: Sean Christopherson <seanjc@google.com>
To: Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
Fuad Tabba <fuad.tabba@linux.dev>,
Ackerley Tng <ackerleytng@google.com>,
Xiaoyao Li <xiaoyao.li@intel.com>,
Michael Roth <michael.roth@amd.com>,
Fuad Tabba <tabba@google.com>
Subject: [PATCH v6 9/9] KVM: guest_memfd: Make private exactly what can be mapped on page fault
Date: Thu, 23 Jul 2026 14:08:11 -0700 [thread overview]
Message-ID: <20260723210811.72720-10-seanjc@google.com> (raw)
In-Reply-To: <20260723210811.72720-1-seanjc@google.com>
When calling into arch code to make the underlying memory private, i.e. to
assign memory to the VM in SNP's RMP table, assign/convert *exactly* the
range of memory that can be mapped into the guest for the current page
fault, instead of aggressively converting/assigning the entire folio. For
SNP, the mapping size in the stage-2 page tables (Nested Page Tables, NPT)
must be at least the size of the corresponding RMP entry, e.g. assigning a
2MiB mapping in the RMP when it can only be mapped at 4KiB granualarity
will ultimate result in another page fault (#NPF for SNP) to "smash" the
RMP down to the correct mapping size.
Assigning the entire folio was necessary back when guest_memfd tracked
preparedness, which was done on a per-folio basis. At the time, it made
sense to do per-folio tracking/preparation, because tracking per-folio
meant guest_memfd didn't need to add a separate data structure to track
that information, and doing per-folio tracking only works if the entire
folio is prepared (or not).
Now that guest_memfd no longer does preparation tracking (see commit
8622ef05709f ("KVM: guest_memfd: Remove preparation tracking")), in favor
having SNP query the RMP, per-folio preparation, i.e. per-folio conversions
to private, doesn't make any sense.
*If* SNP allowed the RMP size to be greater than the NPT size, then
per-folio conversion could theoretically provide marginal value, as it
would allow KVM to assign a hugepage in the RMP even if it can only be
mapped into the NPT with a smaller page, e.g. because of memslot alignment.
The documentation of that reasoning would be something like this:
/*
* If the memory is private from KVM's perspective, and hardware tracks
* VM-assigned private memory in a dedicated data structure, i.e. not
* in the stage-2 page tables, then call into arch code to assign the
* entire folio to the guest. Assigning the entire folio, e.g. instead
* of only the memory being mapped into the guest, allows KVM to assign
* an entire hugepage of memory in the out-of-band structure even if
* KVM can only map a smaller page size into the MMU, e.g. because the
* gmem hugepage is spread across multiple memslots.
*/
But even *if* a future SNP implementation supported that behavior, the
value added would be dubious, as having a huge folio that is fully private,
but can only be mapped at a smaller granularity, would be rare. E.g. maybe
for memory at the top of lower DRAM that has holes for non-RAM assets?
So, convert/assign exactly what guest_memfd allows the caller to map to
simplify the guest_memfd code and provide a (super) minor performance
optimization for SNP. E.g. once hugepage support comes along, guest_memfd
will only need a single flow to compute "how much memory can be assigned
and at what size".
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
virt/kvm/guest_memfd.c | 53 ++++++------------------------------------
1 file changed, 7 insertions(+), 46 deletions(-)
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 255860c472ee..0bca42a0b346 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -70,50 +70,6 @@ static bool kvm_gmem_is_shared_mem(struct inode *inode, pgoff_t index)
return !kvm_gmem_is_private_mem(inode, index);
}
-static int __kvm_gmem_prepare_folio(struct kvm *kvm, struct kvm_memory_slot *slot,
- pgoff_t index, struct folio *folio)
-{
-#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_CONVERT
- kvm_pfn_t pfn = folio_file_pfn(folio, index);
- gfn_t gfn = slot->base_gfn + index - slot->gmem.pgoff;
-
- return kvm_arch_gmem_make_private(kvm, gfn, pfn, folio_nr_pages(folio));
-#else
- return 0;
-#endif
-}
-
-/*
- * Process @folio, which contains @gfn, so that the guest can use it.
- * The folio must be locked and the gfn must be contained in @slot.
- * On successful return the guest sees a zero page so as to avoid
- * leaking host data and the up-to-date flag is set.
- */
-static int kvm_gmem_prepare_folio(struct kvm *kvm, struct kvm_memory_slot *slot,
- gfn_t gfn, struct folio *folio)
-{
- pgoff_t index;
-
- /*
- * Preparing huge folios should always be safe, since it should
- * be possible to split them later if needed.
- *
- * Right now the folio order is always going to be zero, but the
- * code is ready for huge folios. The only assumption is that
- * the base pgoff of memslots is naturally aligned with the
- * requested page order, ensuring that huge folios can also use
- * huge page table entries for GPA->HPA mapping.
- *
- * The order will be passed when creating the guest_memfd, and
- * checked when creating memslots.
- */
- WARN_ON(!IS_ALIGNED(slot->gmem.pgoff, folio_nr_pages(folio)));
- index = kvm_gmem_get_index(slot, gfn);
- index = ALIGN_DOWN(index, folio_nr_pages(folio));
-
- return __kvm_gmem_prepare_folio(kvm, slot, index, folio);
-}
-
/*
* Returns a locked folio on success. The caller is responsible for
* setting the up-to-date flag before the memory is mapped into the guest.
@@ -799,7 +755,9 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
{
pgoff_t index = kvm_gmem_get_index(slot, gfn);
struct folio *folio;
- int r = 0;
+ int r = 0, __order;
+
+ max_order = max_order ?: &__order;
CLASS(gmem_get_file, file)(slot);
if (!file)
@@ -814,8 +772,11 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
folio_mark_uptodate(folio);
}
+#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_CONVERT
if (kvm_gmem_is_private_mem(file_inode(file), index))
- r = kvm_gmem_prepare_folio(kvm, slot, gfn, folio);
+ r = kvm_arch_gmem_make_private(kvm, gfn, *pfn,
+ (kvm_pfn_t)1 << *max_order);
+#endif
folio_unlock(folio);
--
2.55.0.229.g6434b31f56-goog
prev parent reply other threads:[~2026-07-23 21:08 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-23 21:08 [PATCH v6 0/9] KVM: guest_memfd: RECLAIM+CONVERT cleanups Sean Christopherson
2026-07-23 21:08 ` [PATCH v6 1/9] KVM: guest_memfd: Pass the number of pages instead of the end pfn into .invalidate() Sean Christopherson
2026-07-23 21:08 ` [PATCH v6 2/9] KVM: guest_memfd: Rename invalidate() arch hook to reclaim() and isolate it Sean Christopherson
2026-07-23 21:08 ` [PATCH v6 3/9] KVM: x86: Rename kvm_x86_ops' gmem_invalidate() to gmem_make_shared() Sean Christopherson
2026-07-23 21:08 ` [PATCH v6 4/9] KVM: guest_memfd: Drop the redundant printk on arch gmem_prepare() failure Sean Christopherson
2026-07-23 21:08 ` [PATCH v6 5/9] KVM: guest_memfd: Add helpers to query SHARED vs. PRIVATE for a given page Sean Christopherson
2026-07-23 21:08 ` [PATCH v6 6/9] KVM: guest_memfd: Only "prepare" folios for private pages Sean Christopherson
2026-07-23 21:08 ` [PATCH v6 7/9] KVM: guest_memfd: Rename prepare() hook and Kconfig to make_private() / CONVERT Sean Christopherson
2026-07-23 21:08 ` [PATCH v6 8/9] KVM: guest_memfd: Explicitly pass number of pages to make_private() hook Sean Christopherson
2026-07-23 21:08 ` Sean Christopherson [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260723210811.72720-10-seanjc@google.com \
--to=seanjc@google.com \
--cc=ackerleytng@google.com \
--cc=fuad.tabba@linux.dev \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=michael.roth@amd.com \
--cc=pbonzini@redhat.com \
--cc=tabba@google.com \
--cc=xiaoyao.li@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.