diff options
Diffstat (limited to 'drivers/xen/events.c')
-rw-r--r-- | drivers/xen/events.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index d17aa41a9041..aa85881d17b2 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -403,11 +403,23 @@ static void unmask_evtchn(int port) | |||
403 | 403 | ||
404 | if (unlikely((cpu != cpu_from_evtchn(port)))) | 404 | if (unlikely((cpu != cpu_from_evtchn(port)))) |
405 | do_hypercall = 1; | 405 | do_hypercall = 1; |
406 | else | 406 | else { |
407 | /* | ||
408 | * Need to clear the mask before checking pending to | ||
409 | * avoid a race with an event becoming pending. | ||
410 | * | ||
411 | * EVTCHNOP_unmask will only trigger an upcall if the | ||
412 | * mask bit was set, so if a hypercall is needed | ||
413 | * remask the event. | ||
414 | */ | ||
415 | sync_clear_bit(port, BM(&s->evtchn_mask[0])); | ||
407 | evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0])); | 416 | evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0])); |
408 | 417 | ||
409 | if (unlikely(evtchn_pending && xen_hvm_domain())) | 418 | if (unlikely(evtchn_pending && xen_hvm_domain())) { |
410 | do_hypercall = 1; | 419 | sync_set_bit(port, BM(&s->evtchn_mask[0])); |
420 | do_hypercall = 1; | ||
421 | } | ||
422 | } | ||
411 | 423 | ||
412 | /* Slow path (hypercall) if this is a non-local port or if this is | 424 | /* Slow path (hypercall) if this is a non-local port or if this is |
413 | * an hvm domain and an event is pending (hvm domains don't have | 425 | * an hvm domain and an event is pending (hvm domains don't have |
@@ -418,8 +430,6 @@ static void unmask_evtchn(int port) | |||
418 | } else { | 430 | } else { |
419 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); | 431 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); |
420 | 432 | ||
421 | sync_clear_bit(port, BM(&s->evtchn_mask[0])); | ||
422 | |||
423 | /* | 433 | /* |
424 | * The following is basically the equivalent of | 434 | * The following is basically the equivalent of |
425 | * 'hw_resend_irq'. Just like a real IO-APIC we 'lose | 435 | * 'hw_resend_irq'. Just like a real IO-APIC we 'lose |