mirror of
https://github.com/torvalds/linux.git
synced 2026-07-29 10:41:49 +02:00
KVM: TDX: Move external page table freeing to TDX code
Move the freeing of external page tables into the reclaim operation that lives in TDX code. The TDP MMU supports traversing the TDP without holding locks. Page tables need to be freed via RCU to prevent walking one that gets freed. While none of these lockless walk operations actually happen for the mirror page table, the TDP MMU nonetheless frees the mirror page table in the same way, and (because it's a handy place to plug it in) the external page table as well. However, the external page table definitely can't be walked once the page table pages are reclaimed from the TDX module. The TDX module releases the page for the host VMM to use, so this RCU-time free is unnecessary for the external page table. So move the free_page() call to TDX code. Create an tdp_mmu_free_unused_sp() to allow for freeing external page tables that have never left the TDP MMU code (i.e. don't need to be freed in a special way). Link: https://lore.kernel.org/kvm/aYpjNrtGmogNzqwT@google.com [Based on a diff by Sean, added log] Co-developed-by: Rick Edgecombe <rick.p.edgecombe@intel.com> Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com> Signed-off-by: Yan Zhao <yan.y.zhao@intel.com> Link: https://patch.msgid.link/20260509075740.4371-1-yan.y.zhao@intel.com Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
parent
b35bda696e
commit
110d4d2634
|
|
@ -53,13 +53,18 @@ void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm)
|
|||
rcu_barrier();
|
||||
}
|
||||
|
||||
static void tdp_mmu_free_sp(struct kvm_mmu_page *sp)
|
||||
static void __tdp_mmu_free_sp(struct kvm_mmu_page *sp)
|
||||
{
|
||||
free_page((unsigned long)sp->external_spt);
|
||||
free_page((unsigned long)sp->spt);
|
||||
kmem_cache_free(mmu_page_header_cache, sp);
|
||||
}
|
||||
|
||||
static void tdp_mmu_free_unused_sp(struct kvm_mmu_page *sp)
|
||||
{
|
||||
free_page((unsigned long)sp->external_spt);
|
||||
__tdp_mmu_free_sp(sp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called through call_rcu in order to free TDP page table memory
|
||||
* safely with respect to other kernel threads that may be operating on
|
||||
|
|
@ -73,7 +78,8 @@ static void tdp_mmu_free_sp_rcu_callback(struct rcu_head *head)
|
|||
struct kvm_mmu_page *sp = container_of(head, struct kvm_mmu_page,
|
||||
rcu_head);
|
||||
|
||||
tdp_mmu_free_sp(sp);
|
||||
WARN_ON_ONCE(sp->external_spt);
|
||||
__tdp_mmu_free_sp(sp);
|
||||
}
|
||||
|
||||
void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root)
|
||||
|
|
@ -1268,7 +1274,7 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
|
|||
* failed, e.g. because a different task modified the SPTE.
|
||||
*/
|
||||
if (r) {
|
||||
tdp_mmu_free_sp(sp);
|
||||
tdp_mmu_free_unused_sp(sp);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
|
|
@ -1579,7 +1585,7 @@ static int tdp_mmu_split_huge_pages_root(struct kvm *kvm,
|
|||
* installs its own sp in place of the last sp we tried to split.
|
||||
*/
|
||||
if (sp)
|
||||
tdp_mmu_free_sp(sp);
|
||||
tdp_mmu_free_unused_sp(sp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1869,7 +1869,16 @@ static void tdx_sept_free_private_spt(struct kvm *kvm, struct kvm_mmu_page *sp)
|
|||
*/
|
||||
if (KVM_BUG_ON(is_hkid_assigned(to_kvm_tdx(kvm)), kvm) ||
|
||||
tdx_reclaim_page(virt_to_page(sp->external_spt)))
|
||||
sp->external_spt = NULL;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Immediately free the S-EPT page because RCU-time free is unnecessary
|
||||
* after TDH.PHYMEM.PAGE.RECLAIM ensures there are no outstanding
|
||||
* readers.
|
||||
*/
|
||||
free_page((unsigned long)sp->external_spt);
|
||||
out:
|
||||
sp->external_spt = NULL;
|
||||
}
|
||||
|
||||
void tdx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user