summaryrefslogtreecommitdiff
path: root/fs/block_dev.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-02-02 15:56:52 +0100
committerRitesh Harjani <riteshh@codeaurora.org>2017-10-18 12:05:44 +0530
commit9c197e78d2888e51936f5794ae9356ef42aca160 (patch)
treefe2a1e8670db1d0327e9d32f6f512f879f980e5c /fs/block_dev.c
parentb56ec58cde8aa78d30f0af2f71c5ffcbe5def4ce (diff)
block: Make blk_get_backing_dev_info() safe without open bdev
Currenly blk_get_backing_dev_info() is not safe to be called when the block device is not open as bdev->bd_disk is NULL in that case. However inode_to_bdi() uses this function and may be call called from flusher worker or other writeback related functions without bdev being open which leads to crashes such as: [113031.075540] Unable to handle kernel paging request for data at address 0x00000000 [113031.075614] Faulting instruction address: 0xc0000000003692e0 0:mon> t [c0000000fb65f900] c00000000036cb6c writeback_sb_inodes+0x30c/0x590 [c0000000fb65fa10] c00000000036ced4 __writeback_inodes_wb+0xe4/0x150 [c0000000fb65fa70] c00000000036d33c wb_writeback+0x30c/0x450 [c0000000fb65fb40] c00000000036e198 wb_workfn+0x268/0x580 [c0000000fb65fc50] c0000000000f3470 process_one_work+0x1e0/0x590 [c0000000fb65fce0] c0000000000f38c8 worker_thread+0xa8/0x660 [c0000000fb65fd80] c0000000000fc4b0 kthread+0x110/0x130 [c0000000fb65fe30] c0000000000098f0 ret_from_kernel_thread+0x5c/0x6c Signed-off-by: Jens Axboe <axboe@fb.com> Change-Id: I26955b919bd05fe34dc60aab1797ea2739ad5fd7 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git Git-commit: b1d2dc5659b41741f5a29b2ade76ffb4e5bb13d8 [riteshh@codeaurora.org: resolved merge conflicts] Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r--fs/block_dev.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c
index d180449f07ce..49533c903467 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -557,6 +557,8 @@ static void bdev_evict_inode(struct inode *inode)
}
list_del_init(&bdev->bd_list);
spin_unlock(&bdev_lock);
+ if (bdev->bd_bdi != &noop_backing_dev_info)
+ bdi_put(bdev->bd_bdi);
}
static const struct super_operations bdev_sops = {
@@ -655,6 +657,7 @@ 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 = (1 << inode->i_blkbits);
bdev->bd_part_count = 0;
bdev->bd_invalidated = 0;
@@ -1216,6 +1219,9 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
bdev->bd_disk = disk;
bdev->bd_queue = disk->queue;
bdev->bd_contains = bdev;
+ if (bdev->bd_bdi == &noop_backing_dev_info)
+ bdev->bd_bdi = bdi_get(disk->queue->backing_dev_info);
+
bdev->bd_inode->i_flags = disk->fops->direct_access ? S_DAX : 0;
if (!partno) {
ret = -ENXIO;
@@ -1317,6 +1323,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
bdev->bd_disk = NULL;
bdev->bd_part = NULL;
bdev->bd_queue = NULL;
+ bdi_put(bdev->bd_bdi);
+ bdev->bd_bdi = &noop_backing_dev_info;
if (bdev != bdev->bd_contains)
__blkdev_put(bdev->bd_contains, mode, 1);
bdev->bd_contains = NULL;