Skip to content

Commit 7ccd079

Browse files
jankaraaxboe
authored andcommitted
loop: Push loop_ctl_mutex down into loop_clr_fd()
loop_clr_fd() has a weird locking convention that is expects loop_ctl_mutex held, releases it on success and keeps it on failure. Untangle the mess by moving locking of loop_ctl_mutex into loop_clr_fd(). Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent a2505b7 commit 7ccd079

File tree

1 file changed

+29
-20
lines changed

1 file changed

+29
-20
lines changed

drivers/block/loop.c

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,15 +1027,22 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer,
10271027

10281028
static int __loop_clr_fd(struct loop_device *lo)
10291029
{
1030-
struct file *filp = lo->lo_backing_file;
1030+
struct file *filp = NULL;
10311031
gfp_t gfp = lo->old_gfp_mask;
10321032
struct block_device *bdev = lo->lo_device;
1033+
int err = 0;
10331034

1034-
if (WARN_ON_ONCE(lo->lo_state != Lo_rundown))
1035-
return -ENXIO;
1035+
mutex_lock(&loop_ctl_mutex);
1036+
if (WARN_ON_ONCE(lo->lo_state != Lo_rundown)) {
1037+
err = -ENXIO;
1038+
goto out_unlock;
1039+
}
10361040

1037-
if (filp == NULL)
1038-
return -EINVAL;
1041+
filp = lo->lo_backing_file;
1042+
if (filp == NULL) {
1043+
err = -EINVAL;
1044+
goto out_unlock;
1045+
}
10391046

10401047
/* freeze request queue during the transition */
10411048
blk_mq_freeze_queue(lo->lo_queue);
@@ -1082,21 +1089,30 @@ static int __loop_clr_fd(struct loop_device *lo)
10821089
if (!part_shift)
10831090
lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN;
10841091
loop_unprepare_queue(lo);
1092+
out_unlock:
10851093
mutex_unlock(&loop_ctl_mutex);
10861094
/*
10871095
* Need not hold loop_ctl_mutex to fput backing file.
10881096
* Calling fput holding loop_ctl_mutex triggers a circular
10891097
* lock dependency possibility warning as fput can take
10901098
* bd_mutex which is usually taken before loop_ctl_mutex.
10911099
*/
1092-
fput(filp);
1093-
return 0;
1100+
if (filp)
1101+
fput(filp);
1102+
return err;
10941103
}
10951104

10961105
static int loop_clr_fd(struct loop_device *lo)
10971106
{
1098-
if (lo->lo_state != Lo_bound)
1107+
int err;
1108+
1109+
err = mutex_lock_killable_nested(&loop_ctl_mutex, 1);
1110+
if (err)
1111+
return err;
1112+
if (lo->lo_state != Lo_bound) {
1113+
mutex_unlock(&loop_ctl_mutex);
10991114
return -ENXIO;
1115+
}
11001116
/*
11011117
* If we've explicitly asked to tear down the loop device,
11021118
* and it has an elevated reference count, set it for auto-teardown when
@@ -1113,6 +1129,7 @@ static int loop_clr_fd(struct loop_device *lo)
11131129
return 0;
11141130
}
11151131
lo->lo_state = Lo_rundown;
1132+
mutex_unlock(&loop_ctl_mutex);
11161133

11171134
return __loop_clr_fd(lo);
11181135
}
@@ -1447,14 +1464,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
14471464
mutex_unlock(&loop_ctl_mutex);
14481465
break;
14491466
case LOOP_CLR_FD:
1450-
err = mutex_lock_killable_nested(&loop_ctl_mutex, 1);
1451-
if (err)
1452-
return err;
1453-
/* loop_clr_fd would have unlocked loop_ctl_mutex on success */
1454-
err = loop_clr_fd(lo);
1455-
if (err)
1456-
mutex_unlock(&loop_ctl_mutex);
1457-
break;
1467+
return loop_clr_fd(lo);
14581468
case LOOP_SET_STATUS:
14591469
err = -EPERM;
14601470
if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) {
@@ -1690,7 +1700,6 @@ static int lo_open(struct block_device *bdev, fmode_t mode)
16901700
static void lo_release(struct gendisk *disk, fmode_t mode)
16911701
{
16921702
struct loop_device *lo;
1693-
int err;
16941703

16951704
mutex_lock(&loop_ctl_mutex);
16961705
lo = disk->private_data;
@@ -1701,13 +1710,13 @@ static void lo_release(struct gendisk *disk, fmode_t mode)
17011710
if (lo->lo_state != Lo_bound)
17021711
goto out_unlock;
17031712
lo->lo_state = Lo_rundown;
1713+
mutex_unlock(&loop_ctl_mutex);
17041714
/*
17051715
* In autoclear mode, stop the loop thread
17061716
* and remove configuration after last close.
17071717
*/
1708-
err = __loop_clr_fd(lo);
1709-
if (!err)
1710-
return;
1718+
__loop_clr_fd(lo);
1719+
return;
17111720
} else if (lo->lo_state == Lo_bound) {
17121721
/*
17131722
* Otherwise keep thread (if running) and config,

0 commit comments

Comments
 (0)