x86/xen: disable premption when enabling local irqs
[linux-2.6-block.git] / arch / x86 / xen / irq.c
index 01a4dc015ae1e37206469df5ea45b3437da19cad..0da7f863056ff05fab1d31dc01e708bdc008badb 100644 (file)
@@ -47,23 +47,18 @@ static void xen_restore_fl(unsigned long flags)
        /* convert from IF type flag */
        flags = !(flags & X86_EFLAGS_IF);
 
-       /* There's a one instruction preempt window here.  We need to
-          make sure we're don't switch CPUs between getting the vcpu
-          pointer and updating the mask. */
+       /* See xen_irq_enable() for why preemption must be disabled. */
        preempt_disable();
        vcpu = this_cpu_read(xen_vcpu);
        vcpu->evtchn_upcall_mask = flags;
-       preempt_enable_no_resched();
-
-       /* Doesn't matter if we get preempted here, because any
-          pending event will get dealt with anyway. */
 
        if (flags == 0) {
-               preempt_check_resched();
                barrier(); /* unmask then check (avoid races) */
                if (unlikely(vcpu->evtchn_upcall_pending))
                        xen_force_evtchn_callback();
-       }
+               preempt_enable();
+       } else
+               preempt_enable_no_resched();
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_restore_fl);
 
@@ -82,10 +77,12 @@ static void xen_irq_enable(void)
 {
        struct vcpu_info *vcpu;
 
-       /* We don't need to worry about being preempted here, since
-          either a) interrupts are disabled, so no preemption, or b)
-          the caller is confused and is trying to re-enable interrupts
-          on an indeterminate processor. */
+       /*
+        * We may be preempted as soon as vcpu->evtchn_upcall_mask is
+        * cleared, so disable preemption to ensure we check for
+        * events on the VCPU we are still running on.
+        */
+       preempt_disable();
 
        vcpu = this_cpu_read(xen_vcpu);
        vcpu->evtchn_upcall_mask = 0;
@@ -96,6 +93,8 @@ static void xen_irq_enable(void)
        barrier(); /* unmask then check (avoid races) */
        if (unlikely(vcpu->evtchn_upcall_pending))
                xen_force_evtchn_callback();
+
+       preempt_enable();
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable);