Re: [PATCH 3.10-stable] xen/evtchn: avoid a deadlock when unbinding an event channel

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 01, 2013 at 11:24:01PM +0900, Jonghwan Choi wrote:
> From: David Vrabel <david.vrabel@xxxxxxxxxx>
> 
> This patch looks like it should be in the 3.10-stable tree, should we apply
> it?

Yes please!

Thank you for catching that. If it would be possible to backport to
earlier version of Linux that would be super!
> 
> ------------------
> 
> From: "David Vrabel <david.vrabel@xxxxxxxxxx>"
> 
> commit 179fbd5a45f0d4034cc6fd37b8d367a3b79663c4 upstream
> 
> 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: David Vrabel <david.vrabel@xxxxxxxxxx>
> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
> [v1: Expanded the commit description a bit]
> Signed-off-by: Jonghwan Choi <jhbird.choi@xxxxxxxxxxx>
> ---
>  drivers/xen/evtchn.c | 21 ++-------------------
>  1 file changed, 2 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
> index 45c8efa..34924fb 100644
> --- a/drivers/xen/evtchn.c
> +++ b/drivers/xen/evtchn.c
> @@ -377,18 +377,12 @@ static long evtchn_ioctl(struct file *file,
>  		if (unbind.port >= NR_EVENT_CHANNELS)
>  			break;
>  
> -		spin_lock_irq(&port_user_lock);
> -
>  		rc = -ENOTCONN;
> -		if (get_port_user(unbind.port) != u) {
> -			spin_unlock_irq(&port_user_lock);
> +		if (get_port_user(unbind.port) != u)
>  			break;
> -		}
>  
>  		disable_irq(irq_from_evtchn(unbind.port));
>  
> -		spin_unlock_irq(&port_user_lock);
> -
>  		evtchn_unbind_from_user(u, unbind.port);
>  
>  		rc = 0;
> @@ -488,26 +482,15 @@ static int evtchn_release(struct inode *inode, struct file *filp)
>  	int i;
>  	struct per_user_data *u = filp->private_data;
>  
> -	spin_lock_irq(&port_user_lock);
> -
> -	free_page((unsigned long)u->ring);
> -
>  	for (i = 0; i < NR_EVENT_CHANNELS; i++) {
>  		if (get_port_user(i) != u)
>  			continue;
>  
>  		disable_irq(irq_from_evtchn(i));
> -	}
> -
> -	spin_unlock_irq(&port_user_lock);
> -
> -	for (i = 0; i < NR_EVENT_CHANNELS; i++) {
> -		if (get_port_user(i) != u)
> -			continue;
> -
>  		evtchn_unbind_from_user(get_port_user(i), i);
>  	}
>  
> +	free_page((unsigned long)u->ring);
>  	kfree(u->name);
>  	kfree(u);
>  
> -- 
> 1.8.1.2
> 
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]