From 1f1503ba096d3a394d1454dac77467092ca996e6 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Tue, 11 Oct 2011 15:16:06 -0400 Subject: [PATCH] xen/gntdev: Fix sleep-inside-spinlock BUG: sleeping function called from invalid context at /local/scratch/dariof/linux/kernel/mutex.c:271 in_atomic(): 1, irqs_disabled(): 0, pid: 3256, name: qemu-dm 1 lock held by qemu-dm/3256: #0: (&(&priv->lock)->rlock){......}, at: [] gntdev_ioctl+0x2bd/0x4d5 Pid: 3256, comm: qemu-dm Tainted: G W 3.1.0-rc8+ #5 Call Trace: [] __might_sleep+0x131/0x135 [] mutex_lock_nested+0x25/0x45 [] free_xenballooned_pages+0x20/0xb1 [] gntdev_put_map+0xa8/0xdb [] ? _raw_spin_lock+0x71/0x7a [] ? gntdev_ioctl+0x2bd/0x4d5 [] gntdev_ioctl+0x31f/0x4d5 [] ? check_events+0x12/0x20 [] do_vfs_ioctl+0x488/0x4d7 [] ? xen_restore_fl_direct_reloc+0x4/0x4 [] ? lock_release+0x21c/0x229 [] ? rcu_read_unlock+0x21/0x32 [] sys_ioctl+0x47/0x6a [] system_call_fastpath+0x16/0x1b gntdev_put_map tries to acquire a mutex when freeing pages back to the xenballoon pool, so it cannot be called with a spinlock held. In gntdev_release, the spinlock is not needed as we are freeing the structure later; in the ioctl, only the list manipulation needs to be under the lock. Reported-and-Tested-By: Dario Faggioli Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 3e3603f35242..880798aae2f2 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -492,13 +492,11 @@ static int gntdev_release(struct inode *inode, struct file *flip) pr_debug("priv %p\n", priv); - spin_lock(&priv->lock); while (!list_empty(&priv->maps)) { map = list_entry(priv->maps.next, struct grant_map, next); list_del(&map->next); gntdev_put_map(map); } - spin_unlock(&priv->lock); if (use_ptemod) mmu_notifier_unregister(&priv->mn, priv->mm); @@ -562,10 +560,11 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv, map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count); if (map) { list_del(&map->next); - gntdev_put_map(map); err = 0; } spin_unlock(&priv->lock); + if (map) + gntdev_put_map(map); return err; }