]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
xen/events: avoid race with raising an event in unmask_evtchn()
authorDavid Vrabel <david.vrabel@citrix.com>
Tue, 12 Mar 2013 15:27:31 +0000 (15:27 +0000)
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Fri, 22 Mar 2013 12:25:13 +0000 (08:25 -0400)
In unmask_evtchn(), when the mask bit is cleared after testing for
pending and the event becomes pending between the test and clear, then
the upcall will not become pending and the event may be lost or
delayed.

Avoid this by always clearing the mask bit before checking for
pending.

This fixes a regression introduced in 3.7 by
b5e579232d635b79a3da052964cb357ccda8d9ea (xen/events: fix
unmask_evtchn for PV on HVM guests) which reordered the clear mask and
check pending operations.

Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Cc: stable@vger.kernel.org
Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
drivers/xen/events.c

index d17aa41a9041428fbff17a890b2af18b64422ef4..4bdd0a50f575aa5c6d51f756f2cd010de25c3ffa 100644 (file)
@@ -403,11 +403,13 @@ static void unmask_evtchn(int port)
 
        if (unlikely((cpu != cpu_from_evtchn(port))))
                do_hypercall = 1;
-       else
+       else {
+               sync_clear_bit(port, BM(&s->evtchn_mask[0]));
                evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0]));
 
-       if (unlikely(evtchn_pending && xen_hvm_domain()))
-               do_hypercall = 1;
+               if (unlikely(evtchn_pending && xen_hvm_domain()))
+                       do_hypercall = 1;
+       }
 
        /* Slow path (hypercall) if this is a non-local port or if this is
         * an hvm domain and an event is pending (hvm domains don't have
@@ -418,8 +420,6 @@ static void unmask_evtchn(int port)
        } else {
                struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
 
-               sync_clear_bit(port, BM(&s->evtchn_mask[0]));
-
                /*
                 * The following is basically the equivalent of
                 * 'hw_resend_irq'. Just like a real IO-APIC we 'lose