On Thu, Mar 03, 2022, Paolo Bonzini wrote: > diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c > index 0b88592495f8..9287ee078c49 100644 > --- a/arch/x86/kvm/mmu/mmu.c > +++ b/arch/x86/kvm/mmu/mmu.c > @@ -5730,7 +5730,6 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm) > kvm_make_all_cpus_request(kvm, KVM_REQ_MMU_FREE_OBSOLETE_ROOTS); > > kvm_zap_obsolete_pages(kvm); > - Spurious whitespace deletion. > write_unlock(&kvm->mmu_lock); > > /* > @@ -5741,11 +5740,8 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm) > * Deferring the zap until the final reference to the root is put would > * lead to use-after-free. > */ > - if (is_tdp_mmu_enabled(kvm)) { > - read_lock(&kvm->mmu_lock); > + if (is_tdp_mmu_enabled(kvm)) > kvm_tdp_mmu_zap_invalidated_roots(kvm); > - read_unlock(&kvm->mmu_lock); > - } > } > > static bool kvm_has_zapped_obsolete_pages(struct kvm *kvm) ... > +static void tdp_mmu_schedule_zap_root(struct kvm *kvm, struct kvm_mmu_page *root) > +{ Definitely worth doing (I'll provide more info in the "Zap defunct roots" patch): WARN_ON_ONCE(!root->role.invalid || root->tdp_mmu_async_data); The assertion on role.invalid is a little overkill, but might help document when and how this is used. > + root->tdp_mmu_async_data = kvm; > + INIT_WORK(&root->tdp_mmu_async_work, tdp_mmu_zap_root_work); > + queue_work(kvm->arch.tdp_mmu_zap_wq, &root->tdp_mmu_async_work); > +} > + > +static inline bool kvm_tdp_root_mark_invalid(struct kvm_mmu_page *page) > +{ > + union kvm_mmu_page_role role = page->role; > + role.invalid = true; > + > + /* No need to use cmpxchg, only the invalid bit can change. */ > + role.word = xchg(&page->role.word, role.word); > + return role.invalid; This helper is unused. It _could_ be used here, but I think it belongs in the next patch. Critically, until zapping defunct roots creates the invariant that invalid roots are _always_ zapped via worker, kvm_tdp_mmu_invalidate_all_roots() must not assume that an invalid root is queued for zapping. I.e. doing this before the "Zap defunct roots" would be wrong: list_for_each_entry(root, &kvm->arch.tdp_mmu_roots, link) { if (kvm_tdp_root_mark_invalid(root)) continue; if (WARN_ON_ONCE(!kvm_tdp_mmu_get_root(root))); continue; tdp_mmu_schedule_zap_root(kvm, root); }