Skip to content

Commit

Permalink
Btrfs: rework error handling in btrfs_mount()
Browse files Browse the repository at this point in the history
Commits 6c41761 and 45ea609 introduced the possibility of NULL pointer
dereference on error paths, also we would leave all devices busy and
leak fs_info with all sub-structures on error when trying to mount an
already mounted fs to a different directory.

Fix this by doing all allocations before trying to open any of the
devices, adjust error path for mount-already-mounted-fs case.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
  • Loading branch information
Ilya Dryomov committed Nov 9, 2011
1 parent 586e46e commit 04d21a2
Showing 1 changed file with 21 additions and 21 deletions.
42 changes: 21 additions & 21 deletions fs/btrfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
struct super_block *s;
struct dentry *root;
struct btrfs_fs_devices *fs_devices = NULL;
struct btrfs_root *tree_root = NULL;
struct btrfs_fs_info *fs_info = NULL;
fmode_t mode = FMODE_READ;
char *subvol_name = NULL;
Expand Down Expand Up @@ -920,44 +919,43 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
if (error)
return ERR_PTR(error);

error = btrfs_open_devices(fs_devices, mode, fs_type);
if (error)
return ERR_PTR(error);

if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
error = -EACCES;
goto error_close_devices;
}

/*
* Setup a dummy root and fs_info for test/set super. This is because
* we don't actually fill this stuff out until open_ctree, but we need
* it for searching for existing supers, so this lets us do that and
* then open_ctree will properly initialize everything later.
*/
fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS);
if (!fs_info) {
error = -ENOMEM;
goto error_close_devices;
}
tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
if (!tree_root) {
if (!fs_info)
return ERR_PTR(-ENOMEM);

fs_info->tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
if (!fs_info->tree_root) {
error = -ENOMEM;
goto error_close_devices;
goto error_fs_info;
}
fs_info->tree_root = tree_root;
fs_info->tree_root->fs_info = fs_info;
fs_info->fs_devices = fs_devices;
tree_root->fs_info = fs_info;

fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
if (!fs_info->super_copy || !fs_info->super_for_commit) {
error = -ENOMEM;
goto error_fs_info;
}

error = btrfs_open_devices(fs_devices, mode, fs_type);
if (error)
goto error_fs_info;

if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
error = -EACCES;
goto error_close_devices;
}

bdev = fs_devices->latest_bdev;
s = sget(fs_type, btrfs_test_super, btrfs_set_super, tree_root);
s = sget(fs_type, btrfs_test_super, btrfs_set_super,
fs_info->tree_root);
if (IS_ERR(s)) {
error = PTR_ERR(s);
goto error_close_devices;
Expand All @@ -966,7 +964,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
if (s->s_root) {
if ((flags ^ s->s_flags) & MS_RDONLY) {
deactivate_locked_super(s);
return ERR_PTR(-EBUSY);
error = -EBUSY;
goto error_close_devices;
}

btrfs_close_devices(fs_devices);
Expand Down Expand Up @@ -997,6 +996,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,

error_close_devices:
btrfs_close_devices(fs_devices);
error_fs_info:
free_fs_info(fs_info);
return ERR_PTR(error);
}
Expand Down

0 comments on commit 04d21a2

Please sign in to comment.