Commit b7d2a5e8 authored by David Vrabel's avatar David Vrabel Committed by Greg Kroah-Hartman

xen/events: mask events when changing their VCPU binding

commit 5e72fdb8 upstream.

commit 4704fe4f upstream.

When a event is being bound to a VCPU there is a window between the
EVTCHNOP_bind_vpcu call and the adjustment of the local per-cpu masks
where an event may be lost.  The hypervisor upcalls the new VCPU but
the kernel thinks that event is still bound to the old VCPU and
ignores it.

There is even a problem when the event is being bound to the same VCPU
as there is a small window beween the clear_bit() and set_bit() calls
in bind_evtchn_to_cpu().  When scanning for pending events, the kernel
may read the bit when it is momentarily clear and ignore the event.

Avoid this by masking the event during the whole bind operation.
Signed-off-by: default avatarDavid Vrabel <david.vrabel@citrix.com>
Signed-off-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: default avatarJan Beulich <jbeulich@suse.com>
[bwh: Backported to 3.2: remove the BM() cast]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
Cc: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 62047439
...@@ -1422,8 +1422,10 @@ void rebind_evtchn_irq(int evtchn, int irq) ...@@ -1422,8 +1422,10 @@ void rebind_evtchn_irq(int evtchn, int irq)
/* Rebind an evtchn so that it gets delivered to a specific cpu */ /* Rebind an evtchn so that it gets delivered to a specific cpu */
static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
{ {
struct shared_info *s = HYPERVISOR_shared_info;
struct evtchn_bind_vcpu bind_vcpu; struct evtchn_bind_vcpu bind_vcpu;
int evtchn = evtchn_from_irq(irq); int evtchn = evtchn_from_irq(irq);
int masked;
if (!VALID_EVTCHN(evtchn)) if (!VALID_EVTCHN(evtchn))
return -1; return -1;
...@@ -1439,6 +1441,12 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) ...@@ -1439,6 +1441,12 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
bind_vcpu.port = evtchn; bind_vcpu.port = evtchn;
bind_vcpu.vcpu = tcpu; bind_vcpu.vcpu = tcpu;
/*
* Mask the event while changing the VCPU binding to prevent
* it being delivered on an unexpected VCPU.
*/
masked = sync_test_and_set_bit(evtchn, s->evtchn_mask);
/* /*
* If this fails, it usually just indicates that we're dealing with a * If this fails, it usually just indicates that we're dealing with a
* virq or IPI channel, which don't actually need to be rebound. Ignore * virq or IPI channel, which don't actually need to be rebound. Ignore
...@@ -1447,6 +1455,9 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) ...@@ -1447,6 +1455,9 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0) if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
bind_evtchn_to_cpu(evtchn, tcpu); bind_evtchn_to_cpu(evtchn, tcpu);
if (!masked)
unmask_evtchn(evtchn);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment