xen: mask event channels while binding them to a vCPU
Mask the event channel source before trying to bind it to a CPU, this prevents stray interrupts from firing while assigning them and hitting the KASSERT in xen_intr_handle_upcall. Sponsored by: Citrix Systems R&D
This commit is contained in:
parent
1093cd82e0
commit
23ca39cf61
@ -851,7 +851,7 @@ xen_intr_assign_cpu(struct intsrc *base_isrc, u_int apic_id)
|
|||||||
struct evtchn_bind_vcpu bind_vcpu;
|
struct evtchn_bind_vcpu bind_vcpu;
|
||||||
struct xenisrc *isrc;
|
struct xenisrc *isrc;
|
||||||
u_int to_cpu, vcpu_id;
|
u_int to_cpu, vcpu_id;
|
||||||
int error;
|
int error, masked;
|
||||||
|
|
||||||
#ifdef XENHVM
|
#ifdef XENHVM
|
||||||
if (xen_vector_callback_enabled == 0)
|
if (xen_vector_callback_enabled == 0)
|
||||||
@ -869,6 +869,11 @@ xen_intr_assign_cpu(struct intsrc *base_isrc, u_int apic_id)
|
|||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mask the event channel while binding it to prevent interrupt
|
||||||
|
* delivery with an inconsistent state in isrc->xi_cpu.
|
||||||
|
*/
|
||||||
|
masked = evtchn_test_and_set_mask(isrc->xi_port);
|
||||||
if ((isrc->xi_type == EVTCHN_TYPE_VIRQ) ||
|
if ((isrc->xi_type == EVTCHN_TYPE_VIRQ) ||
|
||||||
(isrc->xi_type == EVTCHN_TYPE_IPI)) {
|
(isrc->xi_type == EVTCHN_TYPE_IPI)) {
|
||||||
/*
|
/*
|
||||||
@ -879,29 +884,25 @@ xen_intr_assign_cpu(struct intsrc *base_isrc, u_int apic_id)
|
|||||||
evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
|
evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
|
||||||
isrc->xi_cpu = to_cpu;
|
isrc->xi_cpu = to_cpu;
|
||||||
evtchn_cpu_unmask_port(isrc->xi_cpu, isrc->xi_port);
|
evtchn_cpu_unmask_port(isrc->xi_cpu, isrc->xi_port);
|
||||||
mtx_unlock(&xen_intr_isrc_lock);
|
goto out;
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bind_vcpu.port = isrc->xi_port;
|
bind_vcpu.port = isrc->xi_port;
|
||||||
bind_vcpu.vcpu = vcpu_id;
|
bind_vcpu.vcpu = vcpu_id;
|
||||||
|
|
||||||
/*
|
|
||||||
* Allow interrupts to be fielded on the new VCPU before
|
|
||||||
* we ask the hypervisor to deliver them there.
|
|
||||||
*/
|
|
||||||
evtchn_cpu_unmask_port(to_cpu, isrc->xi_port);
|
|
||||||
error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu);
|
error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu);
|
||||||
if (isrc->xi_cpu != to_cpu) {
|
if (isrc->xi_cpu != to_cpu) {
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
/* Commit to new binding by removing the old one. */
|
/* Commit to new binding by removing the old one. */
|
||||||
evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
|
evtchn_cpu_mask_port(isrc->xi_cpu, isrc->xi_port);
|
||||||
isrc->xi_cpu = to_cpu;
|
isrc->xi_cpu = to_cpu;
|
||||||
} else {
|
evtchn_cpu_unmask_port(isrc->xi_cpu, isrc->xi_port);
|
||||||
/* Roll-back to previous binding. */
|
|
||||||
evtchn_cpu_mask_port(to_cpu, isrc->xi_port);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (masked == 0)
|
||||||
|
evtchn_unmask_port(isrc->xi_port);
|
||||||
mtx_unlock(&xen_intr_isrc_lock);
|
mtx_unlock(&xen_intr_isrc_lock);
|
||||||
return (0);
|
return (0);
|
||||||
#else
|
#else
|
||||||
|
Loading…
Reference in New Issue
Block a user