On Thu, 7 May 2026 at 21:22, Ackerley Tng via B4 Relay <[email protected]> wrote: > > From: Ackerley Tng <[email protected]> > > Update the guest_memfd populate() flow to pull memory attributes from the > gmem instance instead of the VM when KVM is not configured to track > shared/private status in the VM. > > Rename the per-VM API to make it clear that it retrieves per-VM > attributes, i.e. is not suitable for use outside of flows that are > specific to generic per-VM attributes. > > Co-developed-by: Sean Christopherson <[email protected]> > Signed-off-by: Sean Christopherson <[email protected]> > Signed-off-by: Ackerley Tng <[email protected]>
Reviewed-by: Fuad Tabba <[email protected]> /fuad > --- > arch/x86/kvm/mmu/mmu.c | 2 +- > include/linux/kvm_host.h | 14 +++++++++++++- > virt/kvm/guest_memfd.c | 24 +++++++++++++++++++++--- > virt/kvm/kvm_main.c | 8 +++----- > 4 files changed, 38 insertions(+), 10 deletions(-) > > diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c > index 153bcc5369985..bfcf9be25598e 100644 > --- a/arch/x86/kvm/mmu/mmu.c > +++ b/arch/x86/kvm/mmu/mmu.c > @@ -7997,7 +7997,7 @@ static bool hugepage_has_attrs(struct kvm *kvm, struct > kvm_memory_slot *slot, > const unsigned long end = start + KVM_PAGES_PER_HPAGE(level); > > if (level == PG_LEVEL_2M) > - return kvm_range_has_memory_attributes(kvm, start, end, ~0, > attrs); > + return kvm_range_has_vm_memory_attributes(kvm, start, end, > ~0, attrs); > > for (gfn = start; gfn < end; gfn += KVM_PAGES_PER_HPAGE(level - 1)) { > if (hugepage_test_mixed(slot, gfn, level - 1) || > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h > index 28a54298d27db..1deab76dc0a2c 100644 > --- a/include/linux/kvm_host.h > +++ b/include/linux/kvm_host.h > @@ -2549,12 +2549,24 @@ static inline bool kvm_mem_is_private(struct kvm > *kvm, gfn_t gfn) > #endif > > #ifdef CONFIG_KVM_VM_MEMORY_ATTRIBUTES > -bool kvm_range_has_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t end, > +extern bool vm_memory_attributes; > +bool kvm_range_has_vm_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t > end, > unsigned long mask, unsigned long attrs); > bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm, > struct kvm_gfn_range *range); > bool kvm_arch_post_set_memory_attributes(struct kvm *kvm, > struct kvm_gfn_range *range); > +#else > +#define vm_memory_attributes false > +static inline bool kvm_range_has_vm_memory_attributes(struct kvm *kvm, > + gfn_t start, gfn_t end, > + unsigned long mask, > + unsigned long attrs) > +{ > + WARN_ONCE(1, "Unexpected call to > kvm_range_has_vm_memory_attributes()"); > + > + return false; > +} > #endif /* CONFIG_KVM_VM_MEMORY_ATTRIBUTES */ > > unsigned long kvm_gmem_get_memory_attributes(struct kvm *kvm, gfn_t gfn); > diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c > index f055e058a3f28..9d025f518c025 100644 > --- a/virt/kvm/guest_memfd.c > +++ b/virt/kvm/guest_memfd.c > @@ -924,12 +924,31 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct > kvm_memory_slot *slot, > EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_gmem_get_pfn); > > #ifdef CONFIG_HAVE_KVM_ARCH_GMEM_POPULATE > +static bool kvm_gmem_range_is_private(struct gmem_inode *gi, pgoff_t index, > + size_t nr_pages, struct kvm *kvm, gfn_t > gfn) > +{ > + pgoff_t end = index + nr_pages - 1; > + void *entry; > + > + if (vm_memory_attributes) > + return kvm_range_has_vm_memory_attributes(kvm, gfn, gfn + > nr_pages, > + > KVM_MEMORY_ATTRIBUTE_PRIVATE, > + > KVM_MEMORY_ATTRIBUTE_PRIVATE); > + > + mt_for_each(&gi->attributes, entry, index, end) { > + if (xa_to_value(entry) != KVM_MEMORY_ATTRIBUTE_PRIVATE) > + return false; > + } > + > + return true; > +} > > static long __kvm_gmem_populate(struct kvm *kvm, struct kvm_memory_slot > *slot, > struct file *file, gfn_t gfn, struct page > *src_page, > kvm_gmem_populate_cb post_populate, void > *opaque) > { > pgoff_t index = kvm_gmem_get_index(slot, gfn); > + struct gmem_inode *gi; > struct folio *folio; > kvm_pfn_t pfn; > int ret; > @@ -944,9 +963,8 @@ static long __kvm_gmem_populate(struct kvm *kvm, struct > kvm_memory_slot *slot, > > folio_unlock(folio); > > - if (!kvm_range_has_memory_attributes(kvm, gfn, gfn + 1, > - KVM_MEMORY_ATTRIBUTE_PRIVATE, > - KVM_MEMORY_ATTRIBUTE_PRIVATE)) { > + gi = GMEM_I(file_inode(file)); > + if (!kvm_gmem_range_is_private(gi, index, 1, kvm, gfn)) { > ret = -EINVAL; > goto out_put_folio; > } > diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c > index 4139e903f756a..0a4024948711a 100644 > --- a/virt/kvm/kvm_main.c > +++ b/virt/kvm/kvm_main.c > @@ -103,9 +103,7 @@ module_param(allow_unsafe_mappings, bool, 0444); > > #ifdef CONFIG_KVM_MEMORY_ATTRIBUTES > #ifdef CONFIG_KVM_VM_MEMORY_ATTRIBUTES > -static bool vm_memory_attributes = true; > -#else > -#define vm_memory_attributes false > +bool vm_memory_attributes = true; > #endif > DEFINE_STATIC_CALL_RET0(__kvm_get_memory_attributes, > kvm_get_memory_attributes_t); > EXPORT_SYMBOL_FOR_KVM_INTERNAL(STATIC_CALL_KEY(__kvm_get_memory_attributes)); > @@ -2450,7 +2448,7 @@ static unsigned long > kvm_get_vm_memory_attributes(struct kvm *kvm, gfn_t gfn) > * Returns true if _all_ gfns in the range [@start, @end) have attributes > * such that the bits in @mask match @attrs. > */ > -bool kvm_range_has_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t end, > +bool kvm_range_has_vm_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t > end, > unsigned long mask, unsigned long attrs) > { > XA_STATE(xas, &kvm->mem_attr_array, start); > @@ -2584,7 +2582,7 @@ static int kvm_vm_set_mem_attributes(struct kvm *kvm, > gfn_t start, gfn_t end, > mutex_lock(&kvm->slots_lock); > > /* Nothing to do if the entire range has the desired attributes. */ > - if (kvm_range_has_memory_attributes(kvm, start, end, ~0, attributes)) > + if (kvm_range_has_vm_memory_attributes(kvm, start, end, ~0, > attributes)) > goto out_unlock; > > /* > > -- > 2.54.0.563.g4f69b47b94-goog > >
