Skip to content

Commit 322c429

Browse files
Tetsuo Handaaxboe
authored andcommitted
loop: make autoclear operation asynchronous
syzbot is reporting circular locking problem at __loop_clr_fd() [1], for commit 87579e9 ("loop: use worker per cgroup instead of kworker") is calling destroy_workqueue() with disk->open_mutex held. This circular dependency cannot be broken unless we call __loop_clr_fd() without holding disk->open_mutex. Therefore, defer __loop_clr_fd() from lo_release() to a WQ context. Link: https://syzkaller.appspot.com/bug?extid=643e4ce4b6ad1347d372 [1] Reported-by: syzbot <[email protected]> Suggested-by: Christoph Hellwig <[email protected]> Cc: Jan Kara <[email protected]> Tested-by: [email protected] Signed-off-by: Tetsuo Handa <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent c5eafd7 commit 322c429

File tree

2 files changed

+37
-29
lines changed

2 files changed

+37
-29
lines changed

drivers/block/loop.c

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
10821082
return error;
10831083
}
10841084

1085-
static void __loop_clr_fd(struct loop_device *lo, bool release)
1085+
static void __loop_clr_fd(struct loop_device *lo)
10861086
{
10871087
struct file *filp;
10881088
gfp_t gfp = lo->old_gfp_mask;
@@ -1144,53 +1144,59 @@ static void __loop_clr_fd(struct loop_device *lo, bool release)
11441144
/* let user-space know about this change */
11451145
kobject_uevent(&disk_to_dev(lo->lo_disk)->kobj, KOBJ_CHANGE);
11461146
mapping_set_gfp_mask(filp->f_mapping, gfp);
1147-
/* This is safe: open() is still holding a reference. */
1148-
module_put(THIS_MODULE);
11491147
blk_mq_unfreeze_queue(lo->lo_queue);
11501148

11511149
disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE);
11521150

11531151
if (lo->lo_flags & LO_FLAGS_PARTSCAN) {
11541152
int err;
11551153

1156-
/*
1157-
* open_mutex has been held already in release path, so don't
1158-
* acquire it if this function is called in such case.
1159-
*
1160-
* If the reread partition isn't from release path, lo_refcnt
1161-
* must be at least one and it can only become zero when the
1162-
* current holder is released.
1163-
*/
1164-
if (!release)
1165-
mutex_lock(&lo->lo_disk->open_mutex);
1154+
mutex_lock(&lo->lo_disk->open_mutex);
11661155
err = bdev_disk_changed(lo->lo_disk, false);
1167-
if (!release)
1168-
mutex_unlock(&lo->lo_disk->open_mutex);
1156+
mutex_unlock(&lo->lo_disk->open_mutex);
11691157
if (err)
11701158
pr_warn("%s: partition scan of loop%d failed (rc=%d)\n",
11711159
__func__, lo->lo_number, err);
11721160
/* Device is gone, no point in returning error */
11731161
}
11741162

1175-
/*
1176-
* lo->lo_state is set to Lo_unbound here after above partscan has
1177-
* finished. There cannot be anybody else entering __loop_clr_fd() as
1178-
* Lo_rundown state protects us from all the other places trying to
1179-
* change the 'lo' device.
1180-
*/
11811163
lo->lo_flags = 0;
11821164
if (!part_shift)
11831165
lo->lo_disk->flags |= GENHD_FL_NO_PART;
1166+
1167+
fput(filp);
1168+
}
1169+
1170+
static void loop_rundown_completed(struct loop_device *lo)
1171+
{
11841172
mutex_lock(&lo->lo_mutex);
11851173
lo->lo_state = Lo_unbound;
11861174
mutex_unlock(&lo->lo_mutex);
1175+
module_put(THIS_MODULE);
1176+
}
11871177

1188-
/*
1189-
* Need not hold lo_mutex to fput backing file. Calling fput holding
1190-
* lo_mutex triggers a circular lock dependency possibility warning as
1191-
* fput can take open_mutex which is usually taken before lo_mutex.
1192-
*/
1193-
fput(filp);
1178+
static void loop_rundown_workfn(struct work_struct *work)
1179+
{
1180+
struct loop_device *lo = container_of(work, struct loop_device,
1181+
rundown_work);
1182+
struct block_device *bdev = lo->lo_device;
1183+
struct gendisk *disk = lo->lo_disk;
1184+
1185+
__loop_clr_fd(lo);
1186+
kobject_put(&bdev->bd_device.kobj);
1187+
module_put(disk->fops->owner);
1188+
loop_rundown_completed(lo);
1189+
}
1190+
1191+
static void loop_schedule_rundown(struct loop_device *lo)
1192+
{
1193+
struct block_device *bdev = lo->lo_device;
1194+
struct gendisk *disk = lo->lo_disk;
1195+
1196+
__module_get(disk->fops->owner);
1197+
kobject_get(&bdev->bd_device.kobj);
1198+
INIT_WORK(&lo->rundown_work, loop_rundown_workfn);
1199+
queue_work(system_long_wq, &lo->rundown_work);
11941200
}
11951201

11961202
static int loop_clr_fd(struct loop_device *lo)
@@ -1222,7 +1228,8 @@ static int loop_clr_fd(struct loop_device *lo)
12221228
lo->lo_state = Lo_rundown;
12231229
mutex_unlock(&lo->lo_mutex);
12241230

1225-
__loop_clr_fd(lo, false);
1231+
__loop_clr_fd(lo);
1232+
loop_rundown_completed(lo);
12261233
return 0;
12271234
}
12281235

@@ -1747,7 +1754,7 @@ static void lo_release(struct gendisk *disk, fmode_t mode)
17471754
* In autoclear mode, stop the loop thread
17481755
* and remove configuration after last close.
17491756
*/
1750-
__loop_clr_fd(lo, true);
1757+
loop_schedule_rundown(lo);
17511758
return;
17521759
} else if (lo->lo_state == Lo_bound) {
17531760
/*

drivers/block/loop.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct loop_device {
5656
struct gendisk *lo_disk;
5757
struct mutex lo_mutex;
5858
bool idr_visible;
59+
struct work_struct rundown_work;
5960
};
6061

6162
struct loop_cmd {

0 commit comments

Comments
 (0)