Skip to content

Commit 2ac2a7d

Browse files
committed
xen: fix race in xen_qlock_wait()
In the following situation a vcpu waiting for a lock might not be woken up from xen_poll_irq(): CPU 1: CPU 2: CPU 3: takes a spinlock tries to get lock -> xen_qlock_wait() frees the lock -> xen_qlock_kick(cpu2) -> xen_clear_irq_pending() takes lock again tries to get lock -> *lock = _Q_SLOW_VAL -> *lock == _Q_SLOW_VAL ? -> xen_poll_irq() frees the lock -> xen_qlock_kick(cpu3) And cpu 2 will sleep forever. This can be avoided easily by modifying xen_qlock_wait() to call xen_poll_irq() only if the related irq was not pending and to call xen_clear_irq_pending() only if it was pending. Cc: [email protected] Cc: [email protected] Cc: [email protected] Signed-off-by: Juergen Gross <[email protected]> Reviewed-by: Jan Beulich <[email protected]> Signed-off-by: Juergen Gross <[email protected]>
1 parent af320de commit 2ac2a7d

File tree

1 file changed

+5
-10
lines changed

1 file changed

+5
-10
lines changed

arch/x86/xen/spinlock.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,12 @@ static void xen_qlock_wait(u8 *byte, u8 val)
4545
if (irq == -1)
4646
return;
4747

48-
/* clear pending */
49-
xen_clear_irq_pending(irq);
50-
barrier();
48+
/* If irq pending already clear it and return. */
49+
if (xen_test_irq_pending(irq)) {
50+
xen_clear_irq_pending(irq);
51+
return;
52+
}
5153

52-
/*
53-
* We check the byte value after clearing pending IRQ to make sure
54-
* that we won't miss a wakeup event because of the clearing.
55-
*
56-
* The sync_clear_bit() call in xen_clear_irq_pending() is atomic.
57-
* So it is effectively a memory barrier for x86.
58-
*/
5954
if (READ_ONCE(*byte) != val)
6055
return;
6156

0 commit comments

Comments
 (0)