Differentiate between "manual" and "automatic" prefetching, where automatic means the prefetch is initiated by KVM without any corresponding userspace request/command (KVM_PRE_FAULT_MEMORY) or guest access (async #PF). Tracking auto-prefetch "faults" will allow implementing prefetching in the TDP MMU using the standard page fault path, without breaking existing prefetching rules in the shadow MMU, e.g. don't auto-prefetch if the slot is being dirty logged. Arguably, async #PFs could be considered automatic, not manual, but they _are_ initiated in response to an explicit guest access, and unlike true automatic prefetching, KVM generally wants to put more effort into handling async #PFs, e.g. wants to punch through dirty logging or wait for I/O, precisely because there was a prior guest access and so giving up likely means a vCPU task will end up paying the cost. No functional change intended. Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/mmu.c | 26 ++++++++++++++++++-------- arch/x86/kvm/mmu/mmu_internal.h | 1 + 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 393feeaddfb1..3bd0d921778d 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -5031,9 +5031,15 @@ static int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *faul return direct_page_fault(vcpu, fault); } +enum kvm_prefetch_type { + KVM_PREFETCH_NONE, + KVM_PREFETCH_MANUAL, + KVM_PREFETCH_AUTO, +}; + static int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, - u64 err, bool prefetch, int *emulation_type, - u8 *level) + u64 err, enum kvm_prefetch_type prefetch, + int *emulation_type, u8 *level) { struct kvm_page_fault fault = { .addr = cr2_or_gpa, @@ -5043,7 +5049,8 @@ static int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, .present = err & PFERR_PRESENT_MASK, .rsvd = err & PFERR_RSVD_MASK, .user = err & PFERR_USER_MASK, - .prefetch = prefetch, + .prefetch = prefetch != KVM_PREFETCH_NONE, + .auto_prefetch = prefetch == KVM_PREFETCH_AUTO, .is_tdp = likely(vcpu->arch.mmu->page_fault == kvm_tdp_page_fault), .nx_huge_page_workaround_enabled = is_nx_huge_page_enabled(vcpu->kvm), @@ -5097,7 +5104,8 @@ static int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, static int kvm_tdp_page_prefault(struct kvm_vcpu *vcpu, gpa_t gpa, - u64 error_code, u8 *level) + u64 error_code, + enum kvm_prefetch_type prefetch, u8 *level) { int r; @@ -5120,7 +5128,7 @@ static int kvm_tdp_page_prefault(struct kvm_vcpu *vcpu, gpa_t gpa, return r; cond_resched(); - r = kvm_mmu_do_page_fault(vcpu, gpa, error_code, true, NULL, level); + r = kvm_mmu_do_page_fault(vcpu, gpa, error_code, prefetch, NULL, level); } while (r == RET_PF_RETRY); if (r < 0) @@ -5175,7 +5183,8 @@ long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, * Shadow paging uses GVA for kvm page fault, so restrict to * two-dimensional paging. */ - r = kvm_tdp_page_prefault(vcpu, range->gpa | direct_bits, error_code, &level); + r = kvm_tdp_page_prefault(vcpu, range->gpa | direct_bits, error_code, + KVM_PREFETCH_MANUAL, &level); if (r < 0) return r; @@ -5207,7 +5216,7 @@ void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, struct kvm_async_pf *work) return; r = kvm_mmu_do_page_fault(vcpu, work->cr2_or_gpa, work->arch.error_code, - true, NULL, NULL); + KVM_PREFETCH_MANUAL, NULL, NULL); /* * Account fixed page faults, otherwise they'll never be counted, but @@ -6681,7 +6690,8 @@ int noinline kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u64 err if (r == RET_PF_INVALID) { vcpu->stat.pf_taken++; - r = kvm_mmu_do_page_fault(vcpu, cr2_or_gpa, error_code, false, + r = kvm_mmu_do_page_fault(vcpu, cr2_or_gpa, error_code, + KVM_PREFETCH_NONE, &emulation_type, NULL); if (KVM_BUG_ON(r == RET_PF_INVALID, vcpu->kvm)) return -EIO; diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index c29002c60126..b02cdacd3e42 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -228,6 +228,7 @@ struct kvm_page_fault { const gpa_t addr; const u64 error_code; const bool prefetch; + const bool auto_prefetch; /* Derived from error_code. */ const bool exec; -- 2.56.0.313.g2479322e68-goog