Skip to content

Commit a856531

Browse files
committed
xen: make xen_qlock_wait() nestable
xen_qlock_wait() isn't safe for nested calls due to interrupts. A call of xen_qlock_kick() might be ignored in case a deeper nesting level was active right before the call of xen_poll_irq(): CPU 1: CPU 2: spin_lock(lock1) spin_lock(lock1) -> xen_qlock_wait() -> xen_clear_irq_pending() Interrupt happens spin_unlock(lock1) -> xen_qlock_kick(CPU 2) spin_lock_irqsave(lock2) spin_lock_irqsave(lock2) -> xen_qlock_wait() -> xen_clear_irq_pending() clears kick for lock1 -> xen_poll_irq() spin_unlock_irq_restore(lock2) -> xen_qlock_kick(CPU 2) wakes up spin_unlock_irq_restore(lock2) IRET resumes in xen_qlock_wait() -> xen_poll_irq() never wakes up The solution is to disable interrupts in xen_qlock_wait() and not to poll for the irq in case xen_qlock_wait() is called in nmi context. 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 2ac2a7d commit a856531

File tree

1 file changed

+10
-14
lines changed

1 file changed

+10
-14
lines changed

arch/x86/xen/spinlock.c

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,25 @@ static void xen_qlock_kick(int cpu)
3939
*/
4040
static void xen_qlock_wait(u8 *byte, u8 val)
4141
{
42+
unsigned long flags;
4243
int irq = __this_cpu_read(lock_kicker_irq);
4344

4445
/* If kicker interrupts not initialized yet, just spin */
45-
if (irq == -1)
46+
if (irq == -1 || in_nmi())
4647
return;
4748

48-
/* If irq pending already clear it and return. */
49+
/* Guard against reentry. */
50+
local_irq_save(flags);
51+
52+
/* If irq pending already clear it. */
4953
if (xen_test_irq_pending(irq)) {
5054
xen_clear_irq_pending(irq);
51-
return;
55+
} else if (READ_ONCE(*byte) == val) {
56+
/* Block until irq becomes pending (or a spurious wakeup) */
57+
xen_poll_irq(irq);
5258
}
5359

54-
if (READ_ONCE(*byte) != val)
55-
return;
56-
57-
/*
58-
* If an interrupt happens here, it will leave the wakeup irq
59-
* pending, which will cause xen_poll_irq() to return
60-
* immediately.
61-
*/
62-
63-
/* Block until irq becomes pending (or perhaps a spurious wakeup) */
64-
xen_poll_irq(irq);
60+
local_irq_restore(flags);
6561
}
6662

6763
static irqreturn_t dummy_handler(int irq, void *dev_id)

0 commit comments

Comments
 (0)