mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-04 10:33:13 +00:00
KVM: x86/mmu: simplify kvm_tdp_mmu_map flow when guest has to retry
A removed SPTE is never present, hence the "if" in kvm_tdp_mmu_map only fails in the exact same conditions that the earlier loop tested in order to issue a "break". So, instead of checking twice the condition (upper level SPTEs could not be created or was frozen), just exit the loop with a goto---the usual poor-man C replacement for RAII early returns. While at it, do not use the "ret" variable for return values of functions that do not return a RET_PF_* enum. This is clearer and also makes it possible to initialize ret to RET_PF_RETRY. Suggested-by: Robert Hoo <robert.hu@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
c4b33d28ea
commit
63d28a25e0
@ -1159,7 +1159,7 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
|
|||||||
struct kvm *kvm = vcpu->kvm;
|
struct kvm *kvm = vcpu->kvm;
|
||||||
struct tdp_iter iter;
|
struct tdp_iter iter;
|
||||||
struct kvm_mmu_page *sp;
|
struct kvm_mmu_page *sp;
|
||||||
int ret;
|
int ret = RET_PF_RETRY;
|
||||||
|
|
||||||
kvm_mmu_hugepage_adjust(vcpu, fault);
|
kvm_mmu_hugepage_adjust(vcpu, fault);
|
||||||
|
|
||||||
@ -1168,23 +1168,25 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
|
|||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
tdp_mmu_for_each_pte(iter, mmu, fault->gfn, fault->gfn + 1) {
|
tdp_mmu_for_each_pte(iter, mmu, fault->gfn, fault->gfn + 1) {
|
||||||
|
int r;
|
||||||
|
|
||||||
if (fault->nx_huge_page_workaround_enabled)
|
if (fault->nx_huge_page_workaround_enabled)
|
||||||
disallowed_hugepage_adjust(fault, iter.old_spte, iter.level);
|
disallowed_hugepage_adjust(fault, iter.old_spte, iter.level);
|
||||||
|
|
||||||
if (iter.level == fault->goal_level)
|
if (iter.level == fault->goal_level)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Step down into the lower level page table if it exists. */
|
|
||||||
if (is_shadow_present_pte(iter.old_spte) &&
|
|
||||||
!is_large_pte(iter.old_spte))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If SPTE has been frozen by another thread, just give up and
|
* If SPTE has been frozen by another thread, just give up and
|
||||||
* retry, avoiding unnecessary page table allocation and free.
|
* retry, avoiding unnecessary page table allocation and free.
|
||||||
*/
|
*/
|
||||||
if (is_removed_spte(iter.old_spte))
|
if (is_removed_spte(iter.old_spte))
|
||||||
break;
|
goto retry;
|
||||||
|
|
||||||
|
/* Step down into the lower level page table if it exists. */
|
||||||
|
if (is_shadow_present_pte(iter.old_spte) &&
|
||||||
|
!is_large_pte(iter.old_spte))
|
||||||
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The SPTE is either non-present or points to a huge page that
|
* The SPTE is either non-present or points to a huge page that
|
||||||
@ -1196,13 +1198,17 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
|
|||||||
sp->nx_huge_page_disallowed = fault->huge_page_disallowed;
|
sp->nx_huge_page_disallowed = fault->huge_page_disallowed;
|
||||||
|
|
||||||
if (is_shadow_present_pte(iter.old_spte))
|
if (is_shadow_present_pte(iter.old_spte))
|
||||||
ret = tdp_mmu_split_huge_page(kvm, &iter, sp, true);
|
r = tdp_mmu_split_huge_page(kvm, &iter, sp, true);
|
||||||
else
|
else
|
||||||
ret = tdp_mmu_link_sp(kvm, &iter, sp, true);
|
r = tdp_mmu_link_sp(kvm, &iter, sp, true);
|
||||||
|
|
||||||
if (ret) {
|
/*
|
||||||
|
* Also force the guest to retry the access if the upper level SPTEs
|
||||||
|
* aren't in place.
|
||||||
|
*/
|
||||||
|
if (r) {
|
||||||
tdp_mmu_free_sp(sp);
|
tdp_mmu_free_sp(sp);
|
||||||
break;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fault->huge_page_disallowed &&
|
if (fault->huge_page_disallowed &&
|
||||||
@ -1213,18 +1219,10 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Force the guest to retry the access if the upper level SPTEs aren't
|
|
||||||
* in place, or if the target leaf SPTE is frozen by another CPU.
|
|
||||||
*/
|
|
||||||
if (iter.level != fault->goal_level || is_removed_spte(iter.old_spte)) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
return RET_PF_RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = tdp_mmu_map_handle_target_level(vcpu, fault, &iter);
|
ret = tdp_mmu_map_handle_target_level(vcpu, fault, &iter);
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
|
retry:
|
||||||
|
rcu_read_unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user