Skip to content

Commit 2a18b7e

Browse files
vittyvkbonzini
authored andcommitted
KVM: async_pf: Inject 'page ready' event only if 'page not present' was previously injected
'Page not present' event may or may not get injected depending on guest's state. If the event wasn't injected, there is no need to inject the corresponding 'page ready' event as the guest may get confused. E.g. Linux thinks that the corresponding 'page not present' event wasn't delivered *yet* and allocates a 'dummy entry' for it. This entry is never freed. Note, 'wakeup all' events have no corresponding 'page not present' event and always get injected. s390 seems to always be able to inject 'page not present', the change is effectively a nop. Suggested-by: Vivek Goyal <[email protected]> Signed-off-by: Vitaly Kuznetsov <[email protected]> Message-Id: <[email protected]> Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=208081 Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 7863e34 commit 2a18b7e

File tree

6 files changed

+12
-6
lines changed

6 files changed

+12
-6
lines changed

arch/s390/include/asm/kvm_host.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu);
978978
void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
979979
struct kvm_async_pf *work);
980980

981-
void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
981+
bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
982982
struct kvm_async_pf *work);
983983

984984
void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,

arch/s390/kvm/kvm-s390.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3923,11 +3923,13 @@ static void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token,
39233923
}
39243924
}
39253925

3926-
void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
3926+
bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
39273927
struct kvm_async_pf *work)
39283928
{
39293929
trace_kvm_s390_pfault_init(vcpu, work->arch.pfault_token);
39303930
__kvm_inject_pfault_token(vcpu, true, work->arch.pfault_token);
3931+
3932+
return true;
39313933
}
39323934

39333935
void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1670,7 +1670,7 @@ void kvm_make_scan_ioapic_request(struct kvm *kvm);
16701670
void kvm_make_scan_ioapic_request_mask(struct kvm *kvm,
16711671
unsigned long *vcpu_bitmap);
16721672

1673-
void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
1673+
bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
16741674
struct kvm_async_pf *work);
16751675
void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
16761676
struct kvm_async_pf *work);

arch/x86/kvm/x86.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10511,7 +10511,7 @@ bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)
1051110511
return kvm_arch_interrupt_allowed(vcpu);
1051210512
}
1051310513

10514-
void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
10514+
bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
1051510515
struct kvm_async_pf *work)
1051610516
{
1051710517
struct x86_exception fault;
@@ -10528,6 +10528,7 @@ void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
1052810528
fault.address = work->arch.token;
1052910529
fault.async_page_fault = true;
1053010530
kvm_inject_page_fault(vcpu, &fault);
10531+
return true;
1053110532
} else {
1053210533
/*
1053310534
* It is not possible to deliver a paravirtualized asynchronous
@@ -10538,6 +10539,7 @@ void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
1053810539
* fault is retried, hopefully the page will be ready in the host.
1053910540
*/
1054010541
kvm_make_request(KVM_REQ_APF_HALT, vcpu);
10542+
return false;
1054110543
}
1054210544
}
1054310545

@@ -10555,7 +10557,8 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
1055510557
kvm_del_async_pf_gfn(vcpu, work->arch.gfn);
1055610558
trace_kvm_async_pf_ready(work->arch.token, work->cr2_or_gpa);
1055710559

10558-
if (kvm_pv_async_pf_enabled(vcpu) &&
10560+
if ((work->wakeup_all || work->notpresent_injected) &&
10561+
kvm_pv_async_pf_enabled(vcpu) &&
1055910562
!apf_put_user_ready(vcpu, work->arch.token)) {
1056010563
vcpu->arch.apf.pageready_pending = true;
1056110564
kvm_apic_set_irq(vcpu, &irq, NULL);

include/linux/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ struct kvm_async_pf {
206206
unsigned long addr;
207207
struct kvm_arch_async_pf arch;
208208
bool wakeup_all;
209+
bool notpresent_injected;
209210
};
210211

211212
void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu);

virt/kvm/async_pf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
189189

190190
list_add_tail(&work->queue, &vcpu->async_pf.queue);
191191
vcpu->async_pf.queued++;
192-
kvm_arch_async_page_not_present(vcpu, work);
192+
work->notpresent_injected = kvm_arch_async_page_not_present(vcpu, work);
193193

194194
schedule_work(&work->work);
195195

0 commit comments

Comments
 (0)