Rework gfn_to_memslot_dirty_bitmap() into a more generic helper that takes a memslot to check if said a memslot is suitable for auto-prefetch. "auto" in this case means prefetch that's initiated by KVM without a corresponding action from either the host or userspace. Taking a memslot will allow using the helper for other prefetch flows where KVM already has the memslot, i.e. will allow reusing the dirty logging logic in particular, without introducing potential TOCTOU bugs. Return error numbers that align with KVM's uAPI for prefaulting so that KVM is consistent in the unlikely case prefaulting ever ends up being subject to the same restrictions (prefaulting isn't "auto" in that it's an explicit request/command from userspace). No functional change intended. Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/mmu.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 5a2cc6a17a9b..393feeaddfb1 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -872,19 +872,19 @@ static void unaccount_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp, untrack_possible_nx_huge_page(kvm, sp, mmu_type); } -static struct kvm_memory_slot *gfn_to_memslot_dirty_bitmap(struct kvm_vcpu *vcpu, - gfn_t gfn, - bool no_dirty_log) +static int kvm_check_memslot_usable_for_auto_prefetch(struct kvm_memory_slot *slot, + unsigned int access) { - struct kvm_memory_slot *slot; + if (!slot) + return -ENOENT; - slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn); - if (!slot || slot->flags & KVM_MEMSLOT_INVALID) - return NULL; - if (no_dirty_log && kvm_slot_dirty_track_enabled(slot)) - return NULL; + if (slot->flags & KVM_MEMSLOT_INVALID) + return -EAGAIN; - return slot; + if ((access & ACC_WRITE_MASK) && kvm_slot_dirty_track_enabled(slot)) + return -EACCES; + + return 0; } /* @@ -3231,8 +3231,8 @@ static bool kvm_mmu_prefetch_sptes(struct kvm_vcpu *vcpu, gfn_t gfn, u64 *sptep, if (WARN_ON_ONCE(nr_pages > PTE_PREFETCH_NUM)) return false; - slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, access & ACC_WRITE_MASK); - if (!slot) + slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn); + if (kvm_check_memslot_usable_for_auto_prefetch(slot, access)) return false; nr_pages = kvm_prefetch_pages(slot, gfn, pages, nr_pages); -- 2.56.0.313.g2479322e68-goog