diff --git a/sys/dev/xen/bus/xen_intr.c b/sys/dev/xen/bus/xen_intr.c --- a/sys/dev/xen/bus/xen_intr.c +++ b/sys/dev/xen/bus/xen_intr.c @@ -341,7 +341,7 @@ /** * Interrupt handler for processing all Xen event channel events. * - * \param trap_frame The trap frame context for the current interrupt. + * \param unused */ int xen_intr_handle_upcall(void *unused __unused) @@ -354,6 +354,15 @@ struct xen_intr_pcpu_data *pc; u_long l1, l2; + /* + * The upcall handler is an interrupt handler itself (that calls other + * interrupt handlers), hence the caller has the responsibility to + * increase td_intr_nesting_level ahead of dispatching the upcall + * handler. + */ + KASSERT(curthread->td_intr_nesting_level > 0, + ("Unexpected thread context")); + /* We must remain on the same vCPU during this function */ CRITICAL_ASSERT(curthread); @@ -417,7 +426,17 @@ ("Received unexpected event on vCPU#%u, event bound to vCPU#%u", PCPU_GET(cpuid), isrc->xi_cpu)); + /* + * Reduce interrupt nesting level ahead of calling the + * per-arch interrupt dispatch helper. This is + * required because the per-arch dispatcher will also + * increase td_intr_nesting_level, and then handlers + * would wrongly see td_intr_nesting_level = 2 when + * there's no nesting at all. + */ + curthread->td_intr_nesting_level--; xen_arch_intr_execute_handlers(isrc, trap_frame); + curthread->td_intr_nesting_level++; /* * If this is the final port processed,