Skip to content

Commit b491255

Browse files
OGAWAHirofumiaxboe
authored andcommitted
loop: Fix ABBA locking race
Current loop calls vfs_statfs() while holding the q->limits_lock. If FS takes some locking in vfs_statfs callback, this may lead to ABBA locking bug (at least, FAT fs has this issue actually). So this patch calls vfs_statfs() outside q->limits_locks instead, because looks like no reason to hold q->limits_locks while getting discord configs. Chain exists of: &sbi->fat_lock --> &q->q_usage_counter(io)#17 --> &q->limits_lock Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&q->limits_lock); lock(&q->q_usage_counter(io)#17); lock(&q->limits_lock); lock(&sbi->fat_lock); *** DEADLOCK *** Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=a5d8c609c02f508672cc Reviewed-by: Ming Lei <[email protected]> Signed-off-by: OGAWA Hirofumi <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 46fd48a commit b491255

File tree

1 file changed

+15
-15
lines changed

1 file changed

+15
-15
lines changed

drivers/block/loop.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -770,12 +770,11 @@ static void loop_sysfs_exit(struct loop_device *lo)
770770
&loop_attribute_group);
771771
}
772772

773-
static void loop_config_discard(struct loop_device *lo,
774-
struct queue_limits *lim)
773+
static void loop_get_discard_config(struct loop_device *lo,
774+
u32 *granularity, u32 *max_discard_sectors)
775775
{
776776
struct file *file = lo->lo_backing_file;
777777
struct inode *inode = file->f_mapping->host;
778-
u32 granularity = 0, max_discard_sectors = 0;
779778
struct kstatfs sbuf;
780779

781780
/*
@@ -788,24 +787,17 @@ static void loop_config_discard(struct loop_device *lo,
788787
if (S_ISBLK(inode->i_mode)) {
789788
struct block_device *bdev = I_BDEV(inode);
790789

791-
max_discard_sectors = bdev_write_zeroes_sectors(bdev);
792-
granularity = bdev_discard_granularity(bdev);
790+
*max_discard_sectors = bdev_write_zeroes_sectors(bdev);
791+
*granularity = bdev_discard_granularity(bdev);
793792

794793
/*
795794
* We use punch hole to reclaim the free space used by the
796795
* image a.k.a. discard.
797796
*/
798797
} else if (file->f_op->fallocate && !vfs_statfs(&file->f_path, &sbuf)) {
799-
max_discard_sectors = UINT_MAX >> 9;
800-
granularity = sbuf.f_bsize;
798+
*max_discard_sectors = UINT_MAX >> 9;
799+
*granularity = sbuf.f_bsize;
801800
}
802-
803-
lim->max_hw_discard_sectors = max_discard_sectors;
804-
lim->max_write_zeroes_sectors = max_discard_sectors;
805-
if (max_discard_sectors)
806-
lim->discard_granularity = granularity;
807-
else
808-
lim->discard_granularity = 0;
809801
}
810802

811803
struct loop_worker {
@@ -991,6 +983,7 @@ static int loop_reconfigure_limits(struct loop_device *lo, unsigned int bsize)
991983
struct inode *inode = file->f_mapping->host;
992984
struct block_device *backing_bdev = NULL;
993985
struct queue_limits lim;
986+
u32 granularity = 0, max_discard_sectors = 0;
994987

995988
if (S_ISBLK(inode->i_mode))
996989
backing_bdev = I_BDEV(inode);
@@ -1000,6 +993,8 @@ static int loop_reconfigure_limits(struct loop_device *lo, unsigned int bsize)
1000993
if (!bsize)
1001994
bsize = loop_default_blocksize(lo, backing_bdev);
1002995

996+
loop_get_discard_config(lo, &granularity, &max_discard_sectors);
997+
1003998
lim = queue_limits_start_update(lo->lo_queue);
1004999
lim.logical_block_size = bsize;
10051000
lim.physical_block_size = bsize;
@@ -1009,7 +1004,12 @@ static int loop_reconfigure_limits(struct loop_device *lo, unsigned int bsize)
10091004
lim.features |= BLK_FEAT_WRITE_CACHE;
10101005
if (backing_bdev && !bdev_nonrot(backing_bdev))
10111006
lim.features |= BLK_FEAT_ROTATIONAL;
1012-
loop_config_discard(lo, &lim);
1007+
lim.max_hw_discard_sectors = max_discard_sectors;
1008+
lim.max_write_zeroes_sectors = max_discard_sectors;
1009+
if (max_discard_sectors)
1010+
lim.discard_granularity = granularity;
1011+
else
1012+
lim.discard_granularity = 0;
10131013
return queue_limits_commit_update(lo->lo_queue, &lim);
10141014
}
10151015

0 commit comments

Comments
 (0)