aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/loop.c
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@vrfy.org>2011-07-31 16:21:35 -0400
committerJens Axboe <jaxboe@fusionio.com>2011-07-31 16:21:35 -0400
commit05eb0f252b04aa94ace0794f73d56c6a02351d80 (patch)
tree51c86862b31a5d2361b54658d0b6e14ed03c9afc /drivers/block/loop.c
parentd134b00b9acca3fb054d7c88a5f5d562ecbb42d1 (diff)
loop: fix deadlock when sysfs and LOOP_CLR_FD race against each other
LOOP_CLR_FD takes lo->lo_ctl_mutex and tries to remove the loop sysfs files. Sysfs calls show() and waits for lo->lo_ctl_mutex. LOOP_CLR_FD waits for show() to finish to remove the sysfs file. cat /sys/class/block/loop0/loop/backing_file mutex_lock_nested+0x176/0x350 ? loop_attr_do_show_backing_file+0x2f/0xd0 [loop] ? loop_attr_do_show_backing_file+0x2f/0xd0 [loop] loop_attr_do_show_backing_file+0x2f/0xd0 [loop] dev_attr_show+0x1b/0x60 ? sysfs_read_file+0x86/0x1a0 ? __get_free_pages+0x12/0x50 sysfs_read_file+0xaf/0x1a0 ioctl(LOOP_CLR_FD): wait_for_common+0x12c/0x180 ? try_to_wake_up+0x2a0/0x2a0 wait_for_completion+0x18/0x20 sysfs_deactivate+0x178/0x180 ? sysfs_addrm_finish+0x43/0x70 ? sysfs_addrm_start+0x1d/0x20 sysfs_addrm_finish+0x43/0x70 sysfs_hash_and_remove+0x85/0xa0 sysfs_remove_group+0x59/0x100 loop_clr_fd+0x1dc/0x3f0 [loop] lo_ioctl+0x223/0x7a0 [loop] Instead of taking the lo_ctl_mutex from sysfs code, take the inner lo->lo_lock, to protect the access to the backing_file data. Thanks to Tejun for help debugging and finding a solution. Cc: Milan Broz <mbroz@redhat.com> Cc: Tejun Heo <tj@kernel.org> Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Cc: stable@kernel.org Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'drivers/block/loop.c')
-rw-r--r--drivers/block/loop.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 3defc52f060c..4720c7ade0ae 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -743,10 +743,10 @@ static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf)
743 ssize_t ret; 743 ssize_t ret;
744 char *p = NULL; 744 char *p = NULL;
745 745
746 mutex_lock(&lo->lo_ctl_mutex); 746 spin_lock_irq(&lo->lo_lock);
747 if (lo->lo_backing_file) 747 if (lo->lo_backing_file)
748 p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1); 748 p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1);
749 mutex_unlock(&lo->lo_ctl_mutex); 749 spin_unlock_irq(&lo->lo_lock);
750 750
751 if (IS_ERR_OR_NULL(p)) 751 if (IS_ERR_OR_NULL(p))
752 ret = PTR_ERR(p); 752 ret = PTR_ERR(p);
@@ -1000,7 +1000,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
1000 1000
1001 kthread_stop(lo->lo_thread); 1001 kthread_stop(lo->lo_thread);
1002 1002
1003 spin_lock_irq(&lo->lo_lock);
1003 lo->lo_backing_file = NULL; 1004 lo->lo_backing_file = NULL;
1005 spin_unlock_irq(&lo->lo_lock);
1004 1006
1005 loop_release_xfer(lo); 1007 loop_release_xfer(lo);
1006 lo->transfer = NULL; 1008 lo->transfer = NULL;