From: Sean Christopherson <[email protected]>

When removing one or more folios from a guest_memfd instance, invalidate
both SHARED and PRIVATE mappings if in-place conversion is enabled, because
stating the obvious, KVM needs to ensure that all mappings to the folio(s)
are dropped.

Opportunistically rename the helper to capture that it returns a filter for
all gfns in anticipation of zapping only the previous mapping types on
conversion.  I.e. when doing in-place conversion to PRIVATE, only SHARED
mappings need to be zapped (ignoring that KVM would ideally not invalidate
ranges whose attributes aren't changing in the first place).

Note, precisely zapping only the possible mapping types when in-place
conversion is disabled is important for functional correctness, not just
for performance.  Specifically, if KVM zaps both when SHARED vs. PRIVATE is
tracked per-VM, then a PUNCH_HOLE operation on a PRIVATE guest_memfd will
incorrectly zap SHARED mappings that have nothing to do with that gmem
instance (because they're mapped via a VMA, not a gmem fd).

The incorrect over-zapping of SHARED memory that doesn't belong to the gmem
fd requesting the zapping will be resolved in a later patch, where, if
in-place conversion is enabled, KVM will use both shared and private memory
from the guest_memfd. If both shared and private memory are from the
guest_memfd, invalidation will only zap memory belonging to the given gmem
instance.

Signed-off-by: Sean Christopherson <[email protected]>
Signed-off-by: Ackerley Tng <[email protected]>
---
 virt/kvm/guest_memfd.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index cd966eef45b69..0afe1468d2d9d 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -139,8 +139,11 @@ static struct folio *kvm_gmem_get_folio(struct inode 
*inode, pgoff_t index)
        return folio;
 }
 
-static enum kvm_gfn_range_filter kvm_gmem_get_invalidate_filter(struct inode 
*inode)
+static enum kvm_gfn_range_filter kvm_gmem_get_all_gfns_filter(struct inode 
*inode)
 {
+       if (gmem_in_place_conversion)
+               return KVM_FILTER_SHARED | KVM_FILTER_PRIVATE;
+
        if (GMEM_I(inode)->flags & GUEST_MEMFD_FLAG_INIT_SHARED)
                return KVM_FILTER_SHARED;
 
@@ -191,11 +194,9 @@ static void __kvm_gmem_invalidate_start(struct gmem_file 
*f, pgoff_t start,
 static void kvm_gmem_invalidate_start(struct inode *inode, pgoff_t start,
                                      pgoff_t end)
 {
-       enum kvm_gfn_range_filter attr_filter;
+       enum kvm_gfn_range_filter attr_filter = 
kvm_gmem_get_all_gfns_filter(inode);
        struct gmem_file *f;
 
-       attr_filter = kvm_gmem_get_invalidate_filter(inode);
-
        kvm_gmem_for_each_file(f, inode)
                __kvm_gmem_invalidate_start(f, start, end, attr_filter);
 }
@@ -347,7 +348,7 @@ static int kvm_gmem_release(struct inode *inode, struct 
file *file)
         * memory, as its lifetime is associated with the inode, not the file.
         */
        __kvm_gmem_invalidate_start(f, 0, -1ul,
-                                   kvm_gmem_get_invalidate_filter(inode));
+                                   kvm_gmem_get_all_gfns_filter(inode));
        __kvm_gmem_invalidate_end(f, 0, -1ul);
 
        list_del(&f->entry);

-- 
2.55.0.897.gb25b4bd76c-goog



Reply via email to