|
@@ -403,11 +403,23 @@ static void unmask_evtchn(int port)
|
|
|
|
|
|
if (unlikely((cpu != cpu_from_evtchn(port))))
|
|
|
do_hypercall = 1;
|
|
|
- else
|
|
|
+ else {
|
|
|
+ /*
|
|
|
+ * Need to clear the mask before checking pending to
|
|
|
+ * avoid a race with an event becoming pending.
|
|
|
+ *
|
|
|
+ * EVTCHNOP_unmask will only trigger an upcall if the
|
|
|
+ * mask bit was set, so if a hypercall is needed
|
|
|
+ * remask the event.
|
|
|
+ */
|
|
|
+ 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())) {
|
|
|
+ sync_set_bit(port, BM(&s->evtchn_mask[0]));
|
|
|
+ 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 +430,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
|