aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-03-02 10:50:13 -0500
committerJens Axboe <axboe@fb.com>2017-03-02 10:56:59 -0500
commita5a79d00017c9eee68a9bcb40d5dfd6f45f17461 (patch)
treedc1803bee107865dbea5c4434bad158a15a66ced /fs
parente02898b423802b1f3a3aaa7f16e896da069ba8f7 (diff)
block: Initialize bd_bdi on inode initialization
So far we initialized bd_bdi only in bdget(). That is fine for normal bdev inodes however for the special case of the root inode of blockdev_superblock that function is never called and thus bd_bdi is left uninitialized. As a result bdev_evict_inode() may oops doing bdi_put(root->bd_bdi) on that inode as can be seen when doing: mount -t bdev none /mnt Fix the problem by initializing bd_bdi when first allocating the inode and then reinitializing bd_bdi in bdev_evict_inode(). Thanks to syzkaller team for finding the problem. Reported-by: Dmitry Vyukov <dvyukov@google.com> Fixes: b1d2dc5659b4 ("block: Make blk_get_backing_dev_info() safe without open bdev") Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/block_dev.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 77c30f15a02c..2eca00ec4370 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -870,6 +870,7 @@ static void init_once(void *foo)
870#ifdef CONFIG_SYSFS 870#ifdef CONFIG_SYSFS
871 INIT_LIST_HEAD(&bdev->bd_holder_disks); 871 INIT_LIST_HEAD(&bdev->bd_holder_disks);
872#endif 872#endif
873 bdev->bd_bdi = &noop_backing_dev_info;
873 inode_init_once(&ei->vfs_inode); 874 inode_init_once(&ei->vfs_inode);
874 /* Initialize mutex for freeze. */ 875 /* Initialize mutex for freeze. */
875 mutex_init(&bdev->bd_fsfreeze_mutex); 876 mutex_init(&bdev->bd_fsfreeze_mutex);
@@ -884,8 +885,10 @@ static void bdev_evict_inode(struct inode *inode)
884 spin_lock(&bdev_lock); 885 spin_lock(&bdev_lock);
885 list_del_init(&bdev->bd_list); 886 list_del_init(&bdev->bd_list);
886 spin_unlock(&bdev_lock); 887 spin_unlock(&bdev_lock);
887 if (bdev->bd_bdi != &noop_backing_dev_info) 888 if (bdev->bd_bdi != &noop_backing_dev_info) {
888 bdi_put(bdev->bd_bdi); 889 bdi_put(bdev->bd_bdi);
890 bdev->bd_bdi = &noop_backing_dev_info;
891 }
889} 892}
890 893
891static const struct super_operations bdev_sops = { 894static const struct super_operations bdev_sops = {
@@ -988,7 +991,6 @@ struct block_device *bdget(dev_t dev)
988 bdev->bd_contains = NULL; 991 bdev->bd_contains = NULL;
989 bdev->bd_super = NULL; 992 bdev->bd_super = NULL;
990 bdev->bd_inode = inode; 993 bdev->bd_inode = inode;
991 bdev->bd_bdi = &noop_backing_dev_info;
992 bdev->bd_block_size = i_blocksize(inode); 994 bdev->bd_block_size = i_blocksize(inode);
993 bdev->bd_part_count = 0; 995 bdev->bd_part_count = 0;
994 bdev->bd_invalidated = 0; 996 bdev->bd_invalidated = 0;