Skip to content

Commit 5cec988

Browse files
Boris OstrovskyDavid Vrabel
authored andcommitted
xen/events: Clear cpu_evtchn_mask before resuming
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> Cc: <stable@vger.kernel.org> # 3.14+ Signed-off-by: David Vrabel <david.vrabel@citrix.com>
1 parent 8014bcc commit 5cec988

File tree

2 files changed

+13
-2
lines changed

2 files changed

+13
-2
lines changed

drivers/xen/events/events_2l.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,15 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
345345
return IRQ_HANDLED;
346346
}
347347

348+
static void evtchn_2l_resume(void)
349+
{
350+
int i;
351+
352+
for_each_online_cpu(i)
353+
memset(per_cpu(cpu_evtchn_mask, i), 0, sizeof(xen_ulong_t) *
354+
EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD);
355+
}
356+
348357
static const struct evtchn_ops evtchn_ops_2l = {
349358
.max_channels = evtchn_2l_max_channels,
350359
.nr_channels = evtchn_2l_max_channels,
@@ -356,6 +365,7 @@ static const struct evtchn_ops evtchn_ops_2l = {
356365
.mask = evtchn_2l_mask,
357366
.unmask = evtchn_2l_unmask,
358367
.handle_events = evtchn_2l_handle_events,
368+
.resume = evtchn_2l_resume,
359369
};
360370

361371
void __init xen_evtchn_2l_init(void)

drivers/xen/events/events_base.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,8 +1279,9 @@ void rebind_evtchn_irq(int evtchn, int irq)
12791279

12801280
mutex_unlock(&irq_mapping_update_lock);
12811281

1282-
/* new event channels are always bound to cpu 0 */
1283-
irq_set_affinity(irq, cpumask_of(0));
1282+
bind_evtchn_to_cpu(evtchn, info->cpu);
1283+
/* This will be deferred until interrupt is processed */
1284+
irq_set_affinity(irq, cpumask_of(info->cpu));
12841285

12851286
/* Unmask the event channel. */
12861287
enable_irq(irq);

0 commit comments

Comments
 (0)