diff options
| author | Ilya Dryomov <idryomov@gmail.com> | 2011-11-09 00:08:15 +0200 | 
|---|---|---|
| committer | Ilya Dryomov <idryomov@gmail.com> | 2011-11-09 22:53:38 +0200 | 
| commit | 4d34b2789538befa45a68a191dc12e0886a69f7d (patch) | |
| tree | 83f8e67439f0562ee9d4aa51cf1a3a0166d78f99 /fs/btrfs/disk-io.c | |
| parent | f23c8af8ca2789eeb0ab9ea90c214f9694d96cc5 (diff) | |
| download | olio-linux-3.10-4d34b2789538befa45a68a191dc12e0886a69f7d.tar.xz olio-linux-3.10-4d34b2789538befa45a68a191dc12e0886a69f7d.zip  | |
Btrfs: avoid null dereference and leaks when bailing from open_ctree()
Fix bugs introduced by 6c41761f.  Firstly, after failing to allocate any
of the tree roots (first 'goto fail' in open_ctree()) we would
dereference a NULL fs_info pointer in free_fs_info().  Secondly, after
failures from init_srcu_struct(), setup_bdi() and new_inode() we would
leak all earlier allocated roots: fs_info fields haven't been
initialized yet so free_fs_info() is rendered useless.
Fix this by initializing fs_info pointer and fs_info fields before any
allocations happen.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
| -rw-r--r-- | fs/btrfs/disk-io.c | 35 | 
1 files changed, 15 insertions, 20 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e53a5bb8567..91db90b526c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1890,31 +1890,32 @@ struct btrfs_root *open_ctree(struct super_block *sb,  	u64 features;  	struct btrfs_key location;  	struct buffer_head *bh; -	struct btrfs_root *extent_root = kzalloc(sizeof(struct btrfs_root), -						 GFP_NOFS); -	struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root), -						 GFP_NOFS); +	struct btrfs_super_block *disk_super;  	struct btrfs_root *tree_root = btrfs_sb(sb); -	struct btrfs_fs_info *fs_info = NULL; -	struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root), -						GFP_NOFS); -	struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root), -					      GFP_NOFS); +	struct btrfs_fs_info *fs_info = tree_root->fs_info; +	struct btrfs_root *extent_root; +	struct btrfs_root *csum_root; +	struct btrfs_root *chunk_root; +	struct btrfs_root *dev_root;  	struct btrfs_root *log_tree_root; -  	int ret;  	int err = -EINVAL;  	int num_backups_tried = 0;  	int backup_index = 0; -	struct btrfs_super_block *disk_super; +	extent_root = fs_info->extent_root = +		kzalloc(sizeof(struct btrfs_root), GFP_NOFS); +	csum_root = fs_info->csum_root = +		kzalloc(sizeof(struct btrfs_root), GFP_NOFS); +	chunk_root = fs_info->chunk_root = +		kzalloc(sizeof(struct btrfs_root), GFP_NOFS); +	dev_root = fs_info->dev_root = +		kzalloc(sizeof(struct btrfs_root), GFP_NOFS); -	if (!extent_root || !tree_root || !tree_root->fs_info || -	    !chunk_root || !dev_root || !csum_root) { +	if (!extent_root || !csum_root || !chunk_root || !dev_root) {  		err = -ENOMEM;  		goto fail;  	} -	fs_info = tree_root->fs_info;  	ret = init_srcu_struct(&fs_info->subvol_srcu);  	if (ret) { @@ -1954,12 +1955,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,  	mutex_init(&fs_info->reloc_mutex);  	init_completion(&fs_info->kobj_unregister); -	fs_info->tree_root = tree_root; -	fs_info->extent_root = extent_root; -	fs_info->csum_root = csum_root; -	fs_info->chunk_root = chunk_root; -	fs_info->dev_root = dev_root; -	fs_info->fs_devices = fs_devices;  	INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);  	INIT_LIST_HEAD(&fs_info->space_info);  	btrfs_mapping_init(&fs_info->mapping_tree);  |