On Mon, Mar 03, 2025 at 05:10:07PM +0000, Fuad Tabba wrote: > Add support for mmap() and fault() for guest_memfd backed memory > in the host for VMs that support in-place conversion between > shared and private. To that end, this patch adds the ability to > check whether the VM type supports in-place conversion, and only > allows mapping its memory if that's the case. > > Also add the KVM capability KVM_CAP_GMEM_SHARED_MEM, which > indicates that the VM supports shared memory in guest_memfd, or > that the host can create VMs that support shared memory. > Supporting shared memory implies that memory can be mapped when > shared with the host. > > This is controlled by the KVM_GMEM_SHARED_MEM configuration > option. > > Signed-off-by: Fuad Tabba <tabba@xxxxxxxxxx> > --- > include/linux/kvm_host.h | 11 ++++ > include/uapi/linux/kvm.h | 1 + > virt/kvm/guest_memfd.c | 105 +++++++++++++++++++++++++++++++++++++++ > virt/kvm/kvm_main.c | 4 ++ > 4 files changed, 121 insertions(+) > > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h > index 7788e3625f6d..2d025b8ee20e 100644 > --- a/include/linux/kvm_host.h > +++ b/include/linux/kvm_host.h > @@ -728,6 +728,17 @@ static inline bool kvm_arch_has_private_mem(struct kvm *kvm) > } > #endif > > +/* > + * Arch code must define kvm_arch_gmem_supports_shared_mem if support for > + * private memory is enabled and it supports in-place shared/private conversion. > + */ > +#if !defined(kvm_arch_gmem_supports_shared_mem) && !IS_ENABLED(CONFIG_KVM_PRIVATE_MEM) Hm. Do we expect any caller for !CONFIG_KVM_PRIVATE_MEM? > +static inline bool kvm_arch_gmem_supports_shared_mem(struct kvm *kvm) > +{ > + return false; > +} > +#endif > + > #ifndef kvm_arch_has_readonly_mem > static inline bool kvm_arch_has_readonly_mem(struct kvm *kvm) > { ... > diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c > index b2aa6bf24d3a..4291956b51ae 100644 > --- a/virt/kvm/guest_memfd.c > +++ b/virt/kvm/guest_memfd.c > @@ -312,7 +312,112 @@ static pgoff_t kvm_gmem_get_index(struct kvm_memory_slot *slot, gfn_t gfn) > return gfn - slot->base_gfn + slot->gmem.pgoff; > } > > +#ifdef CONFIG_KVM_GMEM_SHARED_MEM > +static bool kvm_gmem_offset_is_shared(struct file *file, pgoff_t index) > +{ > + struct kvm_gmem *gmem = file->private_data; > + > + /* For now, VMs that support shared memory share all their memory. */ > + return kvm_arch_gmem_supports_shared_mem(gmem->kvm); > +} > + > +static vm_fault_t kvm_gmem_fault(struct vm_fault *vmf) > +{ > + struct inode *inode = file_inode(vmf->vma->vm_file); > + struct folio *folio; > + vm_fault_t ret = VM_FAULT_LOCKED; > + > + filemap_invalidate_lock_shared(inode->i_mapping); > + > + folio = kvm_gmem_get_folio(inode, vmf->pgoff); > + if (IS_ERR(folio)) { > + switch (PTR_ERR(folio)) { > + case -EAGAIN: > + ret = VM_FAULT_RETRY; > + break; > + case -ENOMEM: > + ret = VM_FAULT_OOM; > + break; > + default: > + ret = VM_FAULT_SIGBUS; > + break; > + } > + goto out_filemap; > + } > + > + if (folio_test_hwpoison(folio)) { > + ret = VM_FAULT_HWPOISON; > + goto out_folio; > + } > + > + /* Must be called with folio lock held, i.e., after kvm_gmem_get_folio() */ If this is a requirement, it would be cleaner to rename the function and pass down the folio and check the lock state inside. -- Kiryl Shutsemau / Kirill A. Shutemov