| From 5cec98834989a014a9560b1841649eaca95cf00e Mon Sep 17 00:00:00 2001 |
| From: Boris Ostrovsky <boris.ostrovsky@oracle.com> |
| Date: Wed, 29 Apr 2015 17:10:12 -0400 |
| Subject: xen/events: Clear cpu_evtchn_mask before resuming |
| |
| From: Boris Ostrovsky <boris.ostrovsky@oracle.com> |
| |
| commit 5cec98834989a014a9560b1841649eaca95cf00e upstream. |
| |
| When a guest is resumed, the hypervisor may change event channel |
| assignments. If this happens and the guest uses 2-level events it |
| is possible for the interrupt to be claimed by wrong VCPU since |
| cpu_evtchn_mask bits may be stale. This can happen even though |
| evtchn_2l_bind_to_cpu() attempts to clear old bits: irq_info that |
| is passed in is not necessarily the original one (from pre-migration |
| times) but instead is freshly allocated during resume and so any |
| information about which CPU the channel was bound to is lost. |
| |
| Thus we should clear the mask during resume. |
| |
| We also need to make sure that bits for xenstore and console channels |
| are set when these two subsystems are resumed. While rebind_evtchn_irq() |
| (which is invoked for both of them on a resume) calls irq_set_affinity(), |
| the latter will in fact postpone setting affinity until handling the |
| interrupt. But because cpu_evtchn_mask will have bits for these two |
| cleared we won't be able to take the interrupt. |
| |
| With that in mind, we need to bind those two channels explicitly in |
| rebind_evtchn_irq(). We will keep irq_set_affinity() so that we have a |
| pass through generic irq affinity code later, in case something needs |
| to be updated there as well. |
| |
| (Also replace cpumask_of(0) with cpumask_of(info->cpu) in |
| rebind_evtchn_irq(): it should be set to zero in preceding |
| xen_irq_info_evtchn_setup().) |
| |
| Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> |
| Reported-by: Annie Li <annie.li@oracle.com> |
| Signed-off-by: David Vrabel <david.vrabel@citrix.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/xen/events/events_2l.c | 10 ++++++++++ |
| drivers/xen/events/events_base.c | 5 +++-- |
| 2 files changed, 13 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/xen/events/events_2l.c |
| +++ b/drivers/xen/events/events_2l.c |
| @@ -345,6 +345,15 @@ irqreturn_t xen_debug_interrupt(int irq, |
| return IRQ_HANDLED; |
| } |
| |
| +static void evtchn_2l_resume(void) |
| +{ |
| + int i; |
| + |
| + for_each_online_cpu(i) |
| + memset(per_cpu(cpu_evtchn_mask, i), 0, sizeof(xen_ulong_t) * |
| + EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD); |
| +} |
| + |
| static const struct evtchn_ops evtchn_ops_2l = { |
| .max_channels = evtchn_2l_max_channels, |
| .nr_channels = evtchn_2l_max_channels, |
| @@ -356,6 +365,7 @@ static const struct evtchn_ops evtchn_op |
| .mask = evtchn_2l_mask, |
| .unmask = evtchn_2l_unmask, |
| .handle_events = evtchn_2l_handle_events, |
| + .resume = evtchn_2l_resume, |
| }; |
| |
| void __init xen_evtchn_2l_init(void) |
| --- a/drivers/xen/events/events_base.c |
| +++ b/drivers/xen/events/events_base.c |
| @@ -1279,8 +1279,9 @@ void rebind_evtchn_irq(int evtchn, int i |
| |
| mutex_unlock(&irq_mapping_update_lock); |
| |
| - /* new event channels are always bound to cpu 0 */ |
| - irq_set_affinity(irq, cpumask_of(0)); |
| + bind_evtchn_to_cpu(evtchn, info->cpu); |
| + /* This will be deferred until interrupt is processed */ |
| + irq_set_affinity(irq, cpumask_of(info->cpu)); |
| |
| /* Unmask the event channel. */ |
| enable_irq(irq); |