Skip to content

Commit 990e781

Browse files
Christoph Hellwigaxboe
authored andcommitted
block: loop: fix deadlock between open and remove
Commit c76f48e ("block: take bd_mutex around delete_partitions in del_gendisk") adds disk->part0->bd_mutex in del_gendisk(), this way causes the following AB/BA deadlock between removing loop and opening loop: 1) loop_control_ioctl(LOOP_CTL_REMOVE) -> mutex_lock(&loop_ctl_mutex) -> del_gendisk -> mutex_lock(&disk->part0->bd_mutex) 2) blkdev_get_by_dev -> mutex_lock(&disk->part0->bd_mutex) -> lo_open -> mutex_lock(&loop_ctl_mutex) Add a new Lo_deleting state to remove the need for clearing ->private_data and thus holding loop_ctl_mutex in the ioctl LOOP_CTL_REMOVE path. Based on an analysis and earlier patch from Ming Lei <[email protected]>. Reported-by: Colin Ian King <[email protected]> Fixes: c76f48e ("block: take bd_mutex around delete_partitions in del_gendisk") Signed-off-by: Christoph Hellwig <[email protected]> Tested-by: Colin Ian King <[email protected]> Reviewed-by: Ming Lei <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 41fe8d0 commit 990e781

File tree

2 files changed

+8
-18
lines changed

2 files changed

+8
-18
lines changed

drivers/block/loop.c

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,29 +1878,18 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
18781878

18791879
static int lo_open(struct block_device *bdev, fmode_t mode)
18801880
{
1881-
struct loop_device *lo;
1881+
struct loop_device *lo = bdev->bd_disk->private_data;
18821882
int err;
18831883

1884-
/*
1885-
* take loop_ctl_mutex to protect lo pointer from race with
1886-
* loop_control_ioctl(LOOP_CTL_REMOVE), however, to reduce contention
1887-
* release it prior to updating lo->lo_refcnt.
1888-
*/
1889-
err = mutex_lock_killable(&loop_ctl_mutex);
1890-
if (err)
1891-
return err;
1892-
lo = bdev->bd_disk->private_data;
1893-
if (!lo) {
1894-
mutex_unlock(&loop_ctl_mutex);
1895-
return -ENXIO;
1896-
}
18971884
err = mutex_lock_killable(&lo->lo_mutex);
1898-
mutex_unlock(&loop_ctl_mutex);
18991885
if (err)
19001886
return err;
1901-
atomic_inc(&lo->lo_refcnt);
1887+
if (lo->lo_state == Lo_deleting)
1888+
err = -ENXIO;
1889+
else
1890+
atomic_inc(&lo->lo_refcnt);
19021891
mutex_unlock(&lo->lo_mutex);
1903-
return 0;
1892+
return err;
19041893
}
19051894

19061895
static void lo_release(struct gendisk *disk, fmode_t mode)
@@ -2284,7 +2273,7 @@ static long loop_control_ioctl(struct file *file, unsigned int cmd,
22842273
mutex_unlock(&lo->lo_mutex);
22852274
break;
22862275
}
2287-
lo->lo_disk->private_data = NULL;
2276+
lo->lo_state = Lo_deleting;
22882277
mutex_unlock(&lo->lo_mutex);
22892278
idr_remove(&loop_index_idr, lo->lo_number);
22902279
loop_remove(lo);

drivers/block/loop.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum {
2222
Lo_unbound,
2323
Lo_bound,
2424
Lo_rundown,
25+
Lo_deleting,
2526
};
2627

2728
struct loop_func_table;

0 commit comments

Comments
 (0)