Skip to content

Commit 576a15d

Browse files
committed
KVM: x86/mmu: Free TDP MMU roots while holding mmy_lock for read
Free TDP MMU roots from vCPU context while holding mmu_lock for read, it is completely legal to invoke kvm_tdp_mmu_put_root() as a reader. This eliminates the last mmu_lock writer in the TDP MMU's "fast zap" path after requesting vCPUs to reload roots, i.e. allows KVM to zap invalidated roots, free obsolete roots, and allocate new roots in parallel. On large VMs, e.g. 100+ vCPUs, allowing the bulk of the "fast zap" operation to run in parallel with freeing and allocating roots reduces the worst case latency for a vCPU to reload a root from 2-3ms to <100us. Link: https://lore.kernel.org/r/20240111020048.844847-9-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent dab285e commit 576a15d

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

arch/x86/kvm/mmu/mmu.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3575,10 +3575,14 @@ static void mmu_free_root_page(struct kvm *kvm, hpa_t *root_hpa,
35753575
if (WARN_ON_ONCE(!sp))
35763576
return;
35773577

3578-
if (is_tdp_mmu_page(sp))
3578+
if (is_tdp_mmu_page(sp)) {
3579+
lockdep_assert_held_read(&kvm->mmu_lock);
35793580
kvm_tdp_mmu_put_root(kvm, sp);
3580-
else if (!--sp->root_count && sp->role.invalid)
3581-
kvm_mmu_prepare_zap_page(kvm, sp, invalid_list);
3581+
} else {
3582+
lockdep_assert_held_write(&kvm->mmu_lock);
3583+
if (!--sp->root_count && sp->role.invalid)
3584+
kvm_mmu_prepare_zap_page(kvm, sp, invalid_list);
3585+
}
35823586

35833587
*root_hpa = INVALID_PAGE;
35843588
}
@@ -3587,6 +3591,7 @@ static void mmu_free_root_page(struct kvm *kvm, hpa_t *root_hpa,
35873591
void kvm_mmu_free_roots(struct kvm *kvm, struct kvm_mmu *mmu,
35883592
ulong roots_to_free)
35893593
{
3594+
bool is_tdp_mmu = tdp_mmu_enabled && mmu->root_role.direct;
35903595
int i;
35913596
LIST_HEAD(invalid_list);
35923597
bool free_active_root;
@@ -3609,7 +3614,10 @@ void kvm_mmu_free_roots(struct kvm *kvm, struct kvm_mmu *mmu,
36093614
return;
36103615
}
36113616

3612-
write_lock(&kvm->mmu_lock);
3617+
if (is_tdp_mmu)
3618+
read_lock(&kvm->mmu_lock);
3619+
else
3620+
write_lock(&kvm->mmu_lock);
36133621

36143622
for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++)
36153623
if (roots_to_free & KVM_MMU_ROOT_PREVIOUS(i))
@@ -3635,8 +3643,13 @@ void kvm_mmu_free_roots(struct kvm *kvm, struct kvm_mmu *mmu,
36353643
mmu->root.pgd = 0;
36363644
}
36373645

3638-
kvm_mmu_commit_zap_page(kvm, &invalid_list);
3639-
write_unlock(&kvm->mmu_lock);
3646+
if (is_tdp_mmu) {
3647+
read_unlock(&kvm->mmu_lock);
3648+
WARN_ON_ONCE(!list_empty(&invalid_list));
3649+
} else {
3650+
kvm_mmu_commit_zap_page(kvm, &invalid_list);
3651+
write_unlock(&kvm->mmu_lock);
3652+
}
36403653
}
36413654
EXPORT_SYMBOL_GPL(kvm_mmu_free_roots);
36423655

0 commit comments

Comments
 (0)