The page ready notification for asynchronous page faults is delivered as an interrupt to the same vCPU that received the not-present exception. As long as interrupts are not enabled before the page fault is registered in the sleepers' hash table, the page ready notification must happen after a prior registration. This is now the case indeed, so the dummy allocation case is dead and can be dropped. Note however that a write of the apf-enable MSR that goes from enabled to enabled might trigger *both* a broadcast notification interrupt and, later, individual interrupts for pending asynchronous page faults. While Linux will never do such a write, the host might do a KVM_SET_MSRS call that would result in the broadcast notification, so do not complain too loudly if the wait does not find a token and only do a pr_once(). Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_para.h | 1 - arch/x86/kernel/kvm.c | 66 ++++++++------------------------- 2 files changed, 15 insertions(+), 52 deletions(-) diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h index 1e28c89b1405..b986edb1a225 100644 --- a/arch/x86/include/asm/kvm_para.h +++ b/arch/x86/include/asm/kvm_para.h @@ -123,7 +123,6 @@ struct kvm_task_sleep_node { struct swait_queue_head wq; u32 token; int cpu; - bool dummy; }; #ifdef CONFIG_KVM_GUEST diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index d3a0e0d7bb84..ad0b6a4ad097 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -111,26 +111,11 @@ bool kvm_async_pf_queue_task(u32 token, struct kvm_task_sleep_node *n) raw_spin_lock(&b->lock); e = _find_apf_task(b, token); if (e) { - struct kvm_task_sleep_node *dummy = NULL; - - /* - * The entry can either be a 'dummy' entry (which is put on the - * list when wake-up happens ahead of APF handling completion) - * or a token from another task which should not be touched. - */ - if (e->dummy) { - hlist_del(&e->link); - dummy = e; - } - raw_spin_unlock(&b->lock); - kfree(dummy); return false; } - n->token = token; n->cpu = smp_processor_id(); - n->dummy = false; init_swait_queue_head(&n->wq); hlist_add_head(&n->link, &b->list); raw_spin_unlock(&b->lock); @@ -200,53 +185,32 @@ static void kvm_async_pf_task_wake(u32 token) { u32 key = hash_32(token, KVM_TASK_SLEEP_HASHBITS); struct kvm_task_sleep_head *b = &async_pf_sleepers[key]; - struct kvm_task_sleep_node *n, *dummy = NULL; + struct kvm_task_sleep_node *n; if (token == ~0) { apf_task_wake_all(); return; } -again: raw_spin_lock(&b->lock); n = _find_apf_task(b, token); - if (!n) { - /* - * Async #PF not yet handled, add a dummy entry for the token. - * Allocating the token must be down outside of the raw lock - * as the allocator is preemptible on PREEMPT_RT kernels. - */ - if (!dummy) { - raw_spin_unlock(&b->lock); - dummy = kzalloc_obj(*dummy, GFP_ATOMIC); - /* - * Continue looping on allocation failure, eventually - * the async #PF will be handled and allocating a new - * node will be unnecessary. - */ - if (!dummy) - cpu_relax(); - - /* - * Recheck for async #PF completion before enqueueing - * the dummy token to avoid duplicate list entries. - */ - goto again; - } - dummy->token = token; - dummy->cpu = smp_processor_id(); - dummy->dummy = true; - init_swait_queue_head(&dummy->wq); - hlist_add_head(&dummy->link, &b->list); - dummy = NULL; - } else { + /* + * A broadcast wakeup, which can happen for example if the VMM calls + * KVM_SET_MSRS, might still leave the individual wakeups queued. + * In that case _find_apf_task() will not find the token when the + * individual wakeup comes, so just ignore the case where n is NULL. + * Nevertheless it *should* not happen, so print a message for the + * user in case something bad actually happens later. + */ + if (n) apf_task_wake_one(n); - } - raw_spin_unlock(&b->lock); + else + pr_info_once("Async page fault waiter not found. This is probably triggered " + "by the host and harmless. However, if a userspace task hangs, " + "please include this message in your bug report.\n"); - /* A dummy token might be allocated and ultimately not used. */ - kfree(dummy); + raw_spin_unlock(&b->lock); } noinstr u32 kvm_read_and_reset_apf_flags(void) -- 2.56.0