On Thu, 2025-04-24 at 11:07 +0800, Yan Zhao wrote: > +static int split_external_spt(struct kvm *kvm, gfn_t gfn, u64 old_spte, > + u64 new_spte, int level) > +{ > + void *external_spt = get_external_spt(gfn, new_spte, level); > + int ret; > + > + KVM_BUG_ON(!external_spt, kvm); > + > + ret = static_call(kvm_x86_split_external_spt)(kvm, gfn, level, external_spt); > + KVM_BUG_ON(ret, kvm); Shouldn't this BUG_ON be handled in the split_external_spt implementation? I don't think we need another one. > + > + return ret; > +} > /** > * handle_removed_pt() - handle a page table removed from the TDP structure > * > @@ -764,13 +778,13 @@ static u64 tdp_mmu_set_spte(struct kvm *kvm, int as_id, tdp_ptep_t sptep, > > handle_changed_spte(kvm, as_id, gfn, old_spte, new_spte, level, false); > > - /* > - * Users that do non-atomic setting of PTEs don't operate on mirror > - * roots, so don't handle it and bug the VM if it's seen. > - */ > if (is_mirror_sptep(sptep)) { > - KVM_BUG_ON(is_shadow_present_pte(new_spte), kvm); > - remove_external_spte(kvm, gfn, old_spte, level); > + if (!is_shadow_present_pte(new_spte)) > + remove_external_spte(kvm, gfn, old_spte, level); > + else if (is_last_spte(old_spte, level) && !is_last_spte(new_spte, level)) > + split_external_spt(kvm, gfn, old_spte, new_spte, level); > + else > + KVM_BUG_ON(1, kvm); It might be worth a comment what this is looking for at this point. I think it's that external EPT only support certain operations, so bug if any unsupported operations are seen. > } > > return old_spte;