[PATCH] KVM: x86: Drop redundant call to kvm_deliver_exception_payload()

Yosry Ahmed posted 1 patch 1 month, 1 week ago
arch/x86/kvm/x86.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
[PATCH] KVM: x86: Drop redundant call to kvm_deliver_exception_payload()
Posted by Yosry Ahmed 1 month, 1 week ago
In kvm_check_and_inject_events(), kvm_deliver_exception_payload() is
called for pending #DB exceptions. However, shortly after, the
per-vendor inject_exception callbacks are made. Both
vmx_inject_exception() and svm_inject_exception() unconditionally call
kvm_deliver_exception_payload(), so the call in
kvm_check_and_inject_events() is redundant.

Note that the extra call for pending #DB exceptions is harmless, as
kvm_deliver_exception_payload() clears exception.has_payload after the
first call.

The call in kvm_check_and_inject_events() was added in commit
f10c729ff965 ("kvm: vmx: Defer setting of DR6 until #DB delivery"). At
that point, the call was likely needed because svm_queue_exception()
checked whether an exception for L2 is intercepted by L1 before calling
kvm_deliver_exception_payload(), as SVM did not have a
check_nested_events callback. Since DR6 is updated before the #DB
intercept in SVM (unlike VMX), it was necessary to deliver the DR6
payload before calling svm_queue_exception().

After that, commit 7c86663b68ba ("KVM: nSVM: inject exceptions via
svm_check_nested_events") added a check_nested_events callback for SVM,
which checked for L1 intercepts for L2's exceptions, and delivered the
the payload appropriately before the intercept. At that point,
svm_queue_exception() started calling kvm_deliver_exception_payload()
unconditionally, and the call to kvm_deliver_exception_payload() from
its caller became redundant.

No functional change intended.

Signed-off-by: Yosry Ahmed <yosry@kernel.org>
---
 arch/x86/kvm/x86.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index db3f393192d94..a9080418f3cfd 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10737,12 +10737,10 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu,
 			__kvm_set_rflags(vcpu, kvm_get_rflags(vcpu) |
 					     X86_EFLAGS_RF);
 
-		if (vcpu->arch.exception.vector == DB_VECTOR) {
-			kvm_deliver_exception_payload(vcpu, &vcpu->arch.exception);
-			if (vcpu->arch.dr7 & DR7_GD) {
-				vcpu->arch.dr7 &= ~DR7_GD;
-				kvm_update_dr7(vcpu);
-			}
+		if (vcpu->arch.exception.vector == DB_VECTOR &&
+		    vcpu->arch.dr7 & DR7_GD) {
+			vcpu->arch.dr7 &= ~DR7_GD;
+			kvm_update_dr7(vcpu);
 		}
 
 		kvm_inject_exception(vcpu);

base-commit: 183bb0ce8c77b0fd1fb25874112bc8751a461e49
-- 
2.53.0.473.g4a7958ca14-goog
Re: [PATCH] KVM: x86: Drop redundant call to kvm_deliver_exception_payload()
Posted by Sean Christopherson 1 month ago
On Mon, 02 Mar 2026 15:42:49 +0000, Yosry Ahmed wrote:
> In kvm_check_and_inject_events(), kvm_deliver_exception_payload() is
> called for pending #DB exceptions. However, shortly after, the
> per-vendor inject_exception callbacks are made. Both
> vmx_inject_exception() and svm_inject_exception() unconditionally call
> kvm_deliver_exception_payload(), so the call in
> kvm_check_and_inject_events() is redundant.
> 
> [...]

Applied to kvm-x86 misc, thanks!

[1/1] KVM: x86: Drop redundant call to kvm_deliver_exception_payload()
      https://github.com/kvm-x86/linux/commit/43e41846ac7e

--
https://github.com/kvm-x86/linux/tree/next
Re: [PATCH] KVM: x86: Drop redundant call to kvm_deliver_exception_payload()
Posted by Sean Christopherson 1 month, 1 week ago
On Mon, Mar 02, 2026, Yosry Ahmed wrote:
> In kvm_check_and_inject_events(), kvm_deliver_exception_payload() is
> called for pending #DB exceptions. However, shortly after, the
> per-vendor inject_exception callbacks are made. Both
> vmx_inject_exception() and svm_inject_exception() unconditionally call
> kvm_deliver_exception_payload(), so the call in
> kvm_check_and_inject_events() is redundant.
> 
> Note that the extra call for pending #DB exceptions is harmless, as
> kvm_deliver_exception_payload() clears exception.has_payload after the
> first call.
> 
> The call in kvm_check_and_inject_events() was added in commit
> f10c729ff965 ("kvm: vmx: Defer setting of DR6 until #DB delivery"). At
> that point, the call was likely needed because svm_queue_exception()
> checked whether an exception for L2 is intercepted by L1 before calling
> kvm_deliver_exception_payload(), as SVM did not have a
> check_nested_events callback. Since DR6 is updated before the #DB
> intercept in SVM (unlike VMX), it was necessary to deliver the DR6
> payload before calling svm_queue_exception().
> 
> After that, commit 7c86663b68ba ("KVM: nSVM: inject exceptions via
> svm_check_nested_events") added a check_nested_events callback for SVM,
> which checked for L1 intercepts for L2's exceptions, and delivered the
> the payload appropriately before the intercept. At that point,
> svm_queue_exception() started calling kvm_deliver_exception_payload()
> unconditionally, and the call to kvm_deliver_exception_payload() from
> its caller became redundant.

Nice!  I vaguely remember staring at this code when working on 5623f751bd9c
("KVM: x86: Treat #DBs from the emulator as fault-like (code and DR7.GD=1)"),
but never pieced together that it was redundant.
Re: [PATCH] KVM: x86: Drop redundant call to kvm_deliver_exception_payload()
Posted by Yosry Ahmed 1 month, 1 week ago
On Mon, Mar 2, 2026 at 7:52 AM Sean Christopherson <seanjc@google.com> wrote:
>
> On Mon, Mar 02, 2026, Yosry Ahmed wrote:
> > In kvm_check_and_inject_events(), kvm_deliver_exception_payload() is
> > called for pending #DB exceptions. However, shortly after, the
> > per-vendor inject_exception callbacks are made. Both
> > vmx_inject_exception() and svm_inject_exception() unconditionally call
> > kvm_deliver_exception_payload(), so the call in
> > kvm_check_and_inject_events() is redundant.
> >
> > Note that the extra call for pending #DB exceptions is harmless, as
> > kvm_deliver_exception_payload() clears exception.has_payload after the
> > first call.
> >
> > The call in kvm_check_and_inject_events() was added in commit
> > f10c729ff965 ("kvm: vmx: Defer setting of DR6 until #DB delivery"). At
> > that point, the call was likely needed because svm_queue_exception()
> > checked whether an exception for L2 is intercepted by L1 before calling
> > kvm_deliver_exception_payload(), as SVM did not have a
> > check_nested_events callback. Since DR6 is updated before the #DB
> > intercept in SVM (unlike VMX), it was necessary to deliver the DR6
> > payload before calling svm_queue_exception().
> >
> > After that, commit 7c86663b68ba ("KVM: nSVM: inject exceptions via
> > svm_check_nested_events") added a check_nested_events callback for SVM,
> > which checked for L1 intercepts for L2's exceptions, and delivered the
> > the payload appropriately before the intercept. At that point,
> > svm_queue_exception() started calling kvm_deliver_exception_payload()
> > unconditionally, and the call to kvm_deliver_exception_payload() from
> > its caller became redundant.
>
> Nice!  I vaguely remember staring at this code when working on 5623f751bd9c
> ("KVM: x86: Treat #DBs from the emulator as fault-like (code and DR7.GD=1)"),
> but never pieced together that it was redundant.

Yeah I was confused by that call a couple of times as well, then it
recently confused an AI bot into thinking there's a bug because we
call it for #DB and not #PF. At that point I thought enough is enough!