Re: [RFC PATCH v2 09/23] KVM: x86/tdp_mmu: Add split_external_spt hook called during write mmu_lock

From: Huang, Kai

Date: Tue Nov 11 2025 - 05:08:44 EST


On Thu, 2025-08-07 at 17:43 +0800, Yan Zhao wrote:
> Introduce the split_external_spt hook and call it within tdp_mmu_set_spte()
> for the mirror page table.

Nit: I think you need to use split_external_spt() since it's a function,
even you already mentioned it is a hook.

>
> tdp_mmu_set_spte() is invoked for SPTE transitions under write mmu_lock.
> For the mirror page table, in addition to the valid transitions from a
> shadow-present entry to !shadow-present entry, introduce a new valid
> transition case for splitting and propagate the transition to the external
> page table via the hook split_external_spt.

Ditto: split_external_spt()


[...]

> static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(bool mirror);
> +static void *get_external_spt(gfn_t gfn, u64 new_spte, int level);

Is it possible to get rid of such declarations, e.g., by ...

>
> static void tdp_account_mmu_page(struct kvm *kvm, struct kvm_mmu_page *sp)
> {
> @@ -384,6 +385,18 @@ static void remove_external_spte(struct kvm *kvm, gfn_t gfn, u64 old_spte,
> KVM_BUG_ON(ret, kvm);
> }
>
> +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 = kvm_x86_call(split_external_spt)(kvm, gfn, level, external_spt);
> +
> + return ret;
> +}

... moving split_external_spt() somewhere else, e.g., after
set_external_spte_present() (which calls get_external_spt())?

Since ...

> /**
> * handle_removed_pt() - handle a page table removed from the TDP structure
> *
> @@ -765,12 +778,20 @@ 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.
> + * Propagate changes of SPTE to the external page table under write
> + * mmu_lock.
> + * Current valid transitions:
> + * - present leaf to !present.
> + * - present non-leaf to !present.
> + * - present leaf to present non-leaf (splitting)
> */
> 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);
> }
>

... split_external_spt() is only called here in tdp_mmu_set_spte() which is
way after set_external_spte_present() AFAICT.