xen: fix RMW when unmasking events
authorJeremy Fitzhardinge <jeremy@goop.org>
Mon, 17 Mar 2008 23:36:52 +0000 (16:36 -0700)
committerIngo Molnar <mingo@elte.hu>
Thu, 27 Mar 2008 15:08:45 +0000 (16:08 +0100)
xen_irq_enable_direct and xen_sysexit were using "andw $0x00ff,
XEN_vcpu_info_pending(vcpu)" to unmask events and test for pending ones
in one instuction.

Unfortunately, the pending flag must be modified with a locked operation
since it can be set by another CPU, and the unlocked form of this
operation was causing the pending flag to get lost, allowing the processor
to return to usermode with pending events and ultimately deadlock.

The simple fix would be to make it a locked operation, but that's rather
costly and unnecessary.  The fix here is to split the mask-clearing and
pending-testing into two instructions; the interrupt window between
them is of no concern because either way pending or new events will
be processed.

This should fix lingering bugs in using direct vcpu structure access too.

[ Stable: needed in 2.6.24.x ]

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Cc: Stable <stable@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/xen/enlighten.c
arch/x86/xen/xen-asm.S

index 8b9ee27805fdd10be4cb19b082131745d1c4a670..1a20318c8cfffe850899ce9bdf8b4a467174ee35 100644 (file)
@@ -95,7 +95,7 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&dummy_shared_info;
  *
  * 0: not available, 1: available
  */
-static int have_vcpu_info_placement = 0;
+static int have_vcpu_info_placement = 1;
 
 static void __init xen_vcpu_setup(int cpu)
 {
index 1a43b60c0c62533cf481d50591166d6530b35f32..6b7190449d07950b7cb869e2cca829497bf132af 100644 (file)
        events, then enter the hypervisor to get them handled.
  */
 ENTRY(xen_irq_enable_direct)
-       /* Clear mask and test pending */
-       andw $0x00ff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
+       /* Unmask events */
+       movb $0, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+
        /* Preempt here doesn't matter because that will deal with
           any pending interrupts.  The pending check may end up being
           run on the wrong CPU, but that doesn't hurt. */
+
+       /* Test for pending */
+       testb $0xff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
        jz 1f
+
 2:     call check_events
 1:
 ENDPATCH(xen_irq_enable_direct)