From: Paolo Bonzini Date: Wed, 26 Nov 2025 08:32:44 +0000 (+0100) Subject: Merge tag 'kvm-x86-gmem-6.19' of https://github.com/kvm-x86/linux into HEAD X-Git-Tag: v6.19-rc1~103^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=236831743ced9162a8953aa281b73c65bd68b822;p=thirdparty%2Flinux.git Merge tag 'kvm-x86-gmem-6.19' of https://github.com/kvm-x86/linux into HEAD KVM guest_memfd changes for 6.19: - Add NUMA mempolicy support for guest_memfd, and clean up a variety of rough edges in guest_memfd along the way. - Define a CLASS to automatically handle get+put when grabbing a guest_memfd from a memslot to make it harder to leak references. - Enhance KVM selftests to make it easer to develop and debug selftests like those added for guest_memfd NUMA support, e.g. where test and/or KVM bugs often result in hard-to-debug SIGBUS errors. - Misc cleanups. --- 236831743ced9162a8953aa281b73c65bd68b822 diff --cc virt/kvm/guest_memfd.c index ffadc5ee8e045,427c0acee9d7a..fdaea3422c302 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@@ -623,53 -708,31 +708,49 @@@ err return r; } - static void __kvm_gmem_unbind(struct kvm_memory_slot *slot, struct kvm_gmem *gmem) -void kvm_gmem_unbind(struct kvm_memory_slot *slot) ++static void __kvm_gmem_unbind(struct kvm_memory_slot *slot, struct gmem_file *f) { unsigned long start = slot->gmem.pgoff; unsigned long end = start + slot->npages; - struct gmem_file *f; - - /* - * Nothing to do if the underlying file was already closed (or is being - * closed right now), kvm_gmem_release() invalidates all bindings. - */ - CLASS(gmem_get_file, file)(slot); - if (!file) - return; - - f = file->private_data; - xa_store_range(&gmem->bindings, start, end - 1, NULL, GFP_KERNEL); - filemap_invalidate_lock(file->f_mapping); + xa_store_range(&f->bindings, start, end - 1, NULL, GFP_KERNEL); /* * synchronize_srcu(&kvm->srcu) ensured that kvm_gmem_get_pfn() * cannot see this memslot. */ WRITE_ONCE(slot->gmem.file, NULL); +} + +void kvm_gmem_unbind(struct kvm_memory_slot *slot) +{ - struct file *file; - + /* + * Nothing to do if the underlying file was _already_ closed, as + * kvm_gmem_release() invalidates and nullifies all bindings. + */ + if (!slot->gmem.file) + return; + - file = kvm_gmem_get_file(slot); ++ CLASS(gmem_get_file, file)(slot); + + /* + * However, if the file is _being_ closed, then the bindings need to be + * removed as kvm_gmem_release() might not run until after the memslot + * is freed. Note, modifying the bindings is safe even though the file + * is dying as kvm_gmem_release() nullifies slot->gmem.file under + * slots_lock, and only puts its reference to KVM after destroying all + * bindings. I.e. reaching this point means kvm_gmem_release() hasn't + * yet destroyed the bindings or freed the gmem_file, and can't do so + * until the caller drops slots_lock. + */ + if (!file) { + __kvm_gmem_unbind(slot, slot->gmem.file->private_data); + return; + } + + filemap_invalidate_lock(file->f_mapping); + __kvm_gmem_unbind(slot, file->private_data); filemap_invalidate_unlock(file->f_mapping); - - fput(file); } /* Returns a locked folio on success. */