block: Initialize bd_bdi on inode initialization
Subsystems (2)
Jan Kara
reviewerPATCH 1/1 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 <[email protected]>
Fixes b1d2dc5659b41741f5a29b2ade76ffb4e5bb13d8
Signed-off-by Jan Kara <[email protected]>
--- fs/block_dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/block_dev.c +4 -2
@@ -870,6 +870,7 @@ static void init_once(void *foo)#ifdef CONFIG_SYSFS INIT_LIST_HEAD (&bdev->bd_holder_disks);#endif + bdev->bd_bdi = &noop_backing_dev_info;inode_init_once (&ei->vfs_inode);/* Initialize mutex for freeze. */ mutex_init (&bdev->bd_fsfreeze_mutex);
@@ -884,8 +885,10 @@ static void bdev_evict_inode(struct inode *inode)spin_lock (&bdev_lock);list_del_init (&bdev->bd_list);spin_unlock (&bdev_lock); -if (bdev->bd_bdi != &noop_backing_dev_info) +if (bdev->bd_bdi != &noop_backing_dev_info) {bdi_put (bdev->bd_bdi); + bdev->bd_bdi = &noop_backing_dev_info; + } }static const struct super_operations bdev_sops = {
@@ -988,7 +991,6 @@ struct block_device *bdget(dev_t dev) bdev->bd_contains =NULL ; bdev->bd_super =NULL ; bdev->bd_inode = inode; - bdev->bd_bdi = &noop_backing_dev_info; bdev->bd_block_size =i_blocksize (inode); bdev->bd_part_count =0 ; bdev->bd_invalidated =0 ;
Signature · 1 line
2.10.2