Re: [PATCH v12 11/45] KVM: guest_memfd: Invalidate both SHARED and PRIVATE mappings for in-place conversions
From: Fuad Tabba
Date: Tue Sep 01 2026 - 05:57:47 EST
On Mon, 31 Aug 2026 at 01:25, Ackerley Tng via B4 Relay
<devnull+ackerleytng.google.com@xxxxxxxxxx> wrote:
>
> From: Sean Christopherson <seanjc@xxxxxxxxxx>
>
> 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 <seanjc@xxxxxxxxxx>
> Signed-off-by: Ackerley Tng <ackerleytng@xxxxxxxxxx>
Reviewed-by: Fuad Tabba <fuad.tabba@xxxxxxxxx>
Cheers,
/fuad
> ---
> 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
>
>