From: David Woodhouse record_steal_time() performs a TLB flush on the guest's behalf when the guest sets KVM_VCPU_FLUSH_TLB. With shadow paging, kvm_vcpu_flush_tlb_guest() ends up in mmu_sync_children(), which can reschedule via cond_resched_rwlock_write(). That is why the flush currently sits between a user_access_end() and a fresh user_access_begin(): it cannot be done while the guest page is mapped for access. Raise KVM_REQ_TLB_FLUSH_GUEST instead of flushing inline, and move the processing of KVM_REQ_STEAL_UPDATE ahead of where the TLB flush requests are serviced in vcpu_enter_guest() so that the flush still happens before the vCPU enters the guest. There is no requirement for it to complete any earlier than that. kvm_make_request() on the vCPU which is running is nothing more than a barrier and a set_bit(), so unlike the flush itself it can be done from any context — which lets the surrounding access be simplified later. Note that the xchg() must stay where it is: it atomically consumes any KVM_VCPU_FLUSH_TLB which the guest has set, as required by commit b043138246a4 ("x86/KVM: Make sure KVM_VCPU_FLUSH_TLB flag is not missed"). Reported-by: Sashiko AI review Closes: https://lore.kernel.org/all/20260530061932.7849D1F00893@smtp.kernel.org Suggested-by: Sean Christopherson Signed-off-by: David Woodhouse Assisted-by: Claude:claude-mythos-5 --- arch/x86/kvm/x86.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 75e5f894153f..d2e60d1146e0 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2106,8 +2106,22 @@ static void record_steal_time(struct kvm_vcpu *vcpu) trace_kvm_pv_tlb_flush(vcpu->vcpu_id, st_preempted & KVM_VCPU_FLUSH_TLB); + /* + * Request the flush instead of performing it inline. With + * shadow paging kvm_vcpu_flush_tlb_guest() can reschedule (via + * mmu_sync_children()), which is why the user access above has + * to be closed before it. Requesting the flush is just a bit + * set on the running vCPU, and the request is serviced before + * the vCPU enters the guest; nothing requires the flush to + * have completed any earlier than that. + * + * Note the xchg above must remain as-is: it atomically + * consumes any KVM_VCPU_FLUSH_TLB the guest set, as required + * by commit b043138246a4 ("x86/KVM: Make sure + * KVM_VCPU_FLUSH_TLB flag is not missed"). + */ if (st_preempted & KVM_VCPU_FLUSH_TLB) - kvm_vcpu_flush_tlb_guest(vcpu); + kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu); if (!user_access_begin(st, sizeof(*st))) goto dirty; @@ -8089,6 +8103,14 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) if (unlikely(r)) goto out; } + /* + * Process the steal time update before the TLB flush requests + * are serviced below; a subsequent change will have it request + * KVM_REQ_TLB_FLUSH_GUEST on the guest's behalf rather than + * performing the flush itself. + */ + if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu)) + record_steal_time(vcpu); if (kvm_check_request(KVM_REQ_MMU_SYNC, vcpu)) kvm_mmu_sync_roots(vcpu); if (kvm_check_request(KVM_REQ_LOAD_MMU_PGD, vcpu)) @@ -8138,8 +8160,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) r = 1; goto out; } - if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu)) - record_steal_time(vcpu); if (kvm_check_request(KVM_REQ_PMU, vcpu)) kvm_pmu_handle_event(vcpu); if (kvm_check_request(KVM_REQ_PMI, vcpu)) -- 2.55.0