• David Vrabel's avatar
    xen/evtchn: avoid a deadlock when unbinding an event channel · 179fbd5a
    David Vrabel authored
    Unbinding an event channel (either with the ioctl or when the evtchn
    device is closed) may deadlock because disable_irq() is called with
    port_user_lock held which is also locked by the interrupt handler.
    
    Think of the IOCTL_EVTCHN_UNBIND is being serviced, the routine has
    just taken the lock, and an interrupt happens. The evtchn_interrupt
    is invoked, tries to take the lock and spins forever.
    
    A quick glance at the code shows that the spinlock is a local IRQ
    variant. Unfortunately that does not help as "disable_irq() waits for
    the interrupt handler on all CPUs to stop running.  If the irq occurs
    on another VCPU, it tries to take port_user_lock and can't because
    the unbind ioctl is holding it." (from David). Hence we cannot
    depend on the said spinlock to protect us. We could make it a system
    wide IRQ disable spinlock but there is a better way.
    
    We can piggyback on the fact that the existence of the spinlock is
    to make get_port_user() checks be up-to-date. And we can alter those
    checks to not depend on the spin lock (as it's protected by u->bind_mutex
    in the ioctl) and can remove the unnecessary locking (this is
    IOCTL_EVTCHN_UNBIND) path.
    
    In the interrupt handler we cannot use the mutex, but we do not
    need it.
    
    "The unbind disables the irq before making the port user stale, so when
    you clear it you are guaranteed that the interrupt handler that might
    use that port cannot be running." (from David).
    
    Hence this patch removes the spinlock usage on the teardown path
    and piggybacks on disable_irq happening before we muck with the
    get_port_user() data. This ensures that the interrupt handler will
    never run on stale data.
    Signed-off-by: default avatarDavid Vrabel <david.vrabel@citrix.com>
    Signed-off-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
    [v1: Expanded the commit description a bit]
    179fbd5a
evtchn.c 13 KB