[PATCH v4 5/6] KVM: x86: Request the guest TLB flush from record_steal_time()
From: David Woodhouse
Date: Tue Aug 11 2026 - 09:26:20 EST
From: David Woodhouse <dwmw@xxxxxxxxxxxx>
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 <sashiko-bot@xxxxxxxxxx>
Closes: https://lore.kernel.org/all/20260530061932.7849D1F00893@xxxxxxxxxxxxxxx
Suggested-by: Sean Christopherson <seanjc@xxxxxxxxxx>
Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
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