Re: [PATCH v9 01/41] KVM: guest_memfd: Introduce per-gmem attributes, use to guard user mappings
"David Hildenbrand (Arm)" <[email protected]>
| Newsgroups | org.kernel.vger.linux-kselftest,dev.linux.lists.linux-coco,org.kernel.vger.kvm,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-trace-kernel,org.kvack.linux-mm |
|---|---|
| Message-ID | <[email protected]> |
On 7/29/26 02:35, Ackerley Tng via B4 Relay wrote: > From: Sean Christopherson <[email protected]> > > Start plumbing in guest_memfd support for in-place private<=>shared > conversions by tracking attributes via a maple tree. KVM currently tracks > private vs. shared attributes on a per-VM basis, which made sense when a > guest_memfd _only_ supported private memory, but tracking per-VM simply > can't work for in-place conversions as the shared/private status of a given > page needs to be per-gmem_inode, not per-VM. > > Use the filemap invalidation lock to protect the maple tree, as taking the > lock for read when faulting in memory (for userspace or the guest) isn't > expected to result in meaningful contention, and using a separate lock > would add significant complexity (avoiding deadlock is quite difficult). > > Co-developed-by: Vishal Annapurve <[email protected]> > Signed-off-by: Vishal Annapurve <[email protected]> > Co-developed-by: Fuad Tabba <[email protected]> > Signed-off-by: Fuad Tabba <[email protected]> > Signed-off-by: Sean Christopherson <[email protected]> > Tested-by: Shivank Garg <[email protected]> > Co-developed-by: Ackerley Tng <[email protected]> > Signed-off-by: Ackerley Tng <[email protected]> > --- > virt/kvm/guest_memfd.c | 133 ++++++++++++++++++++++++++++++++++++++++++------- > 1 file changed, 116 insertions(+), 17 deletions(-) > > diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c > index 0bca42a0b346b..3d6547c5ba9a6 100644 > --- a/virt/kvm/guest_memfd.c > +++ b/virt/kvm/guest_memfd.c > @@ -4,6 +4,7 @@ > #include <linux/falloc.h> > #include <linux/fs.h> > #include <linux/kvm_host.h> > +#include <linux/maple_tree.h> > #include <linux/mempolicy.h> > #include <linux/pseudo_fs.h> > #include <linux/pagemap.h> > @@ -33,6 +34,13 @@ struct gmem_inode { > struct list_head gmem_file_list; > > u64 flags; > + /* > + * Every index in this inode, whether memory is populated or > + * not, is tracked in attributes. The entire range of indices, > + * corresponding to the size of this inode, is represented in > + * this maple tree. > + */ > + struct maple_tree attributes; > }; > > static __always_inline struct gmem_inode *GMEM_I(struct inode *inode) > @@ -60,9 +68,25 @@ static pgoff_t kvm_gmem_get_index(struct kvm_memory_slot *slot, gfn_t gfn) > return gfn - slot->base_gfn + slot->gmem.pgoff; > } > > +static u64 kvm_gmem_interpret_entry(struct inode *inode, void *entry) > +{ > + if (WARN_ON_ONCE(!entry)) { > + bool initially_shared = GMEM_I(inode)->flags & > + GUEST_MEMFD_FLAG_INIT_SHARED; > + > + return initially_shared ? 0 : KVM_MEMORY_ATTRIBUTE_PRIVATE; We have the calculation of the default attribute here and ... > +static int kvm_gmem_init_inode(struct inode *inode, loff_t size, u64 flags) > +{ > + struct gmem_inode *gi = GMEM_I(inode); > + MA_STATE(mas, &gi->attributes, 0, (size >> PAGE_SHIFT) - 1); > + u64 attrs; > + int r; > + > + inode->i_op = &kvm_gmem_iops; > + inode->i_mapping->a_ops = &kvm_gmem_aops; > + inode->i_mode |= S_IFREG; > + inode->i_size = size; > + mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER); > + > + /* > + * guest_memfd memory is neither migratable nor swappable: set > + * inaccessible to gate off both. > + */ > + mapping_set_inaccessible(inode->i_mapping); > + WARN_ON_ONCE(!mapping_unevictable(inode->i_mapping)); > + > + gi->flags = flags; > + > + mt_set_external_lock(&gi->attributes, > + &inode->i_mapping->invalidate_lock); > + > + /* > + * Store default attributes for the entire gmem instance. Ensuring every > + * index is represented in the maple tree at all times simplifies the > + * conversion and merging logic. > + */ > + attrs = gi->flags & GUEST_MEMFD_FLAG_INIT_SHARED ? 0 : KVM_MEMORY_ATTRIBUTE_PRIVATE; ... here. Worth a helper? kvm_gmem_default_attribute(struct inode *inode) ? Nothing else jumped at me, and I agree with the kvm_gmem_get_attributes() improvement :) -- Cheers, David