Hi Ackerley, On Wed, 29 Jul 2026 at 01:35, Ackerley Tng via B4 Relay <[email protected]> wrote: > > From: Ackerley Tng <[email protected]> > > When memory in guest_memfd is converted from private to shared, the > platform-specific state associated with the guest-private pages must be > invalidated or cleaned up. > > Iterate over the folios in the affected range and call the > kvm_arch_gmem_invalidate() hook for each PFN range. This allows
I think this line is left over from v8. The patch calls kvm_arch_gmem_make_shared() now, and kvm_arch_gmem_invalidate() no longer exists after the reclaim/convert rework, so the changelog describes a hook the code doesn't call. With that fixed: Reviewed-by: Fuad Tabba <[email protected]> Cheers, /fuad > architectures to perform necessary teardown, such as updating hardware > metadata or encryption states, before the pages are transitioned to the > shared state. > > Invoke this helper after indicating to KVM's mmu code that an invalidation > is in progress to stop in-flight page faults from succeeding. > > Omit support for calling the arch hook to make private, since SNP, the only > implementer of the arch make-private hook today, would actually prefer > making private only just before faulting memory into the NPTs. > > Calling the make-private arch hook would require iterating both bindings > and the filemap to find the intersection of bindings and allocated > folios. On top of that, SNP would need to figure out whether to actually > make private based on whether the memory is about the be faulted, or > whether it is a conversion. > > This does leak SNP-specific details into guest_memfd (as in, why only > make-shared during conversions but not make-private?), but the additional > complexity is not worth taking on until guest_memfd has a user actually > requiring an arch make-private call. > > Signed-off-by: Ackerley Tng <[email protected]> > --- > arch/x86/include/asm/kvm-x86-ops.h | 2 +- > arch/x86/include/asm/kvm_host.h | 2 +- > arch/x86/kvm/x86.c | 5 +++++ > include/linux/kvm_host.h | 1 + > virt/kvm/guest_memfd.c | 42 > ++++++++++++++++++++++++++++++++++++++ > 5 files changed, 50 insertions(+), 2 deletions(-) > > diff --git a/arch/x86/include/asm/kvm-x86-ops.h > b/arch/x86/include/asm/kvm-x86-ops.h > index 5cb132eca3c35..8e0d6970c43b5 100644 > --- a/arch/x86/include/asm/kvm-x86-ops.h > +++ b/arch/x86/include/asm/kvm-x86-ops.h > @@ -149,7 +149,7 @@ KVM_X86_OP_OPTIONAL(alloc_apic_backing_page) > #ifdef CONFIG_HAVE_KVM_ARCH_GMEM_CONVERT > KVM_X86_OP_OPTIONAL_RET0(gmem_make_private) > #endif > -#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_RECLAIM > +#if defined(CONFIG_HAVE_KVM_ARCH_GMEM_CONVERT) || > defined(CONFIG_HAVE_KVM_ARCH_GMEM_RECLAIM) > KVM_X86_OP_OPTIONAL(gmem_make_shared) > #endif > #ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index 9fdf13b071097..ceb2abf43b76f 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -1730,7 +1730,7 @@ struct kvm_x86_ops { > int (*gmem_make_private)(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, > kvm_pfn_t nr_pages); > #endif > -#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_RECLAIM > +#if defined(CONFIG_HAVE_KVM_ARCH_GMEM_CONVERT) || > defined(CONFIG_HAVE_KVM_ARCH_GMEM_RECLAIM) > void (*gmem_make_shared)(kvm_pfn_t pfn, kvm_pfn_t nr_pages); > #endif > #ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index 3308d58342955..52de3ec7c7f73 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -10639,6 +10639,11 @@ int kvm_arch_gmem_make_private(struct kvm *kvm, > gfn_t gfn, kvm_pfn_t pfn, > { > return kvm_x86_call(gmem_make_private)(kvm, gfn, pfn, nr_pages); > } > + > +void kvm_arch_gmem_make_shared(kvm_pfn_t pfn, kvm_pfn_t nr_pages) > +{ > + kvm_x86_call(gmem_make_shared)(pfn, nr_pages); > +} > #endif > > #ifdef CONFIG_HAVE_KVM_ARCH_GMEM_RECLAIM > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h > index f408746d315f7..47f633cddffe0 100644 > --- a/include/linux/kvm_host.h > +++ b/include/linux/kvm_host.h > @@ -2612,6 +2612,7 @@ static inline int kvm_gmem_get_pfn(struct kvm *kvm, > #ifdef CONFIG_HAVE_KVM_ARCH_GMEM_CONVERT > int kvm_arch_gmem_make_private(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, > kvm_pfn_t nr_pages); > +void kvm_arch_gmem_make_shared(kvm_pfn_t pfn, kvm_pfn_t nr_pages); > #endif > > #ifdef CONFIG_HAVE_KVM_ARCH_GMEM_POPULATE > diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c > index d3c813dcbf96d..612fcde4ae8ea 100644 > --- a/virt/kvm/guest_memfd.c > +++ b/virt/kvm/guest_memfd.c > @@ -563,6 +563,43 @@ static bool kvm_gmem_is_safe_for_conversion(struct inode > *inode, pgoff_t start, > return safe; > } > > +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_CONVERT > +static void kvm_gmem_make_shared(struct inode *inode, pgoff_t start, pgoff_t > end) > +{ > + struct folio_batch fbatch; > + pgoff_t next = start; > + int i; > + > + folio_batch_init(&fbatch); > + while (filemap_get_folios(inode->i_mapping, &next, end - 1, &fbatch)) > { > + for (i = 0; i < folio_batch_count(&fbatch); ++i) { > + struct folio *folio = fbatch.folios[i]; > + pgoff_t start_index, end_index; > + kvm_pfn_t start_pfn; > + kvm_pfn_t nr_pages; > + > + start_index = max(start, folio->index); > + end_index = min(end, folio_next_index(folio)); > + /* > + * end_index is either in folio or points to > + * the first page of the next folio. Hence, > + * all pages in range [start_index, end_index) > + * are contiguous. > + */ > + start_pfn = folio_file_pfn(folio, start_index); > + nr_pages = end_index - start_index; > + > + kvm_arch_gmem_make_shared(start_pfn, nr_pages); > + } > + > + folio_batch_release(&fbatch); > + cond_resched(); > + } > +} > +#else > +static void kvm_gmem_make_shared(struct inode *inode, pgoff_t start, pgoff_t > end) {} > +#endif > + > static int __kvm_gmem_set_attributes(struct inode *inode, pgoff_t start, > size_t nr_pages, uint64_t attrs, > pgoff_t *err_index) > @@ -605,7 +642,12 @@ static int __kvm_gmem_set_attributes(struct inode > *inode, pgoff_t start, > > filter = to_private ? KVM_FILTER_SHARED : KVM_FILTER_PRIVATE; > kvm_gmem_invalidate_start(inode, start, end, filter); > + > + if (!to_private) > + kvm_gmem_make_shared(inode, start, end); > + > mas_store_prealloc(&mas, xa_mk_value(attrs)); > + > kvm_gmem_invalidate_end(inode, start, end); > out: > filemap_invalidate_unlock(mapping); > > -- > 2.55.0.508.g3f0d502094-goog > >
