Skip to content

Commit 0547758

Browse files
sean-jcbonzini
authored andcommitted
x86/kvm: Alloc dummy async #PF token outside of raw spinlock
Drop the raw spinlock in kvm_async_pf_task_wake() before allocating the the dummy async #PF token, the allocator is preemptible on PREEMPT_RT kernels and must not be called from truly atomic contexts. Opportunistically document why it's ok to loop on allocation failure, i.e. why the function won't get stuck in an infinite loop. Reported-by: Yajun Deng <[email protected]> Cc: [email protected] Signed-off-by: Sean Christopherson <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent fee060c commit 0547758

File tree

1 file changed

+27
-14
lines changed

1 file changed

+27
-14
lines changed

arch/x86/kernel/kvm.c

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ void kvm_async_pf_task_wake(u32 token)
191191
{
192192
u32 key = hash_32(token, KVM_TASK_SLEEP_HASHBITS);
193193
struct kvm_task_sleep_head *b = &async_pf_sleepers[key];
194-
struct kvm_task_sleep_node *n;
194+
struct kvm_task_sleep_node *n, *dummy = NULL;
195195

196196
if (token == ~0) {
197197
apf_task_wake_all();
@@ -203,28 +203,41 @@ void kvm_async_pf_task_wake(u32 token)
203203
n = _find_apf_task(b, token);
204204
if (!n) {
205205
/*
206-
* async PF was not yet handled.
207-
* Add dummy entry for the token.
206+
* Async #PF not yet handled, add a dummy entry for the token.
207+
* Allocating the token must be down outside of the raw lock
208+
* as the allocator is preemptible on PREEMPT_RT kernels.
208209
*/
209-
n = kzalloc(sizeof(*n), GFP_ATOMIC);
210-
if (!n) {
210+
if (!dummy) {
211+
raw_spin_unlock(&b->lock);
212+
dummy = kzalloc(sizeof(*dummy), GFP_KERNEL);
213+
211214
/*
212-
* Allocation failed! Busy wait while other cpu
213-
* handles async PF.
215+
* Continue looping on allocation failure, eventually
216+
* the async #PF will be handled and allocating a new
217+
* node will be unnecessary.
218+
*/
219+
if (!dummy)
220+
cpu_relax();
221+
222+
/*
223+
* Recheck for async #PF completion before enqueueing
224+
* the dummy token to avoid duplicate list entries.
214225
*/
215-
raw_spin_unlock(&b->lock);
216-
cpu_relax();
217226
goto again;
218227
}
219-
n->token = token;
220-
n->cpu = smp_processor_id();
221-
init_swait_queue_head(&n->wq);
222-
hlist_add_head(&n->link, &b->list);
228+
dummy->token = token;
229+
dummy->cpu = smp_processor_id();
230+
init_swait_queue_head(&dummy->wq);
231+
hlist_add_head(&dummy->link, &b->list);
232+
dummy = NULL;
223233
} else {
224234
apf_task_wake_one(n);
225235
}
226236
raw_spin_unlock(&b->lock);
227-
return;
237+
238+
/* A dummy token might be allocated and ultimately not used. */
239+
if (dummy)
240+
kfree(dummy);
228241
}
229242
EXPORT_SYMBOL_GPL(kvm_async_pf_task_wake);
230243

0 commit comments

Comments
 (0)