aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorIlya Dryomov <idryomov@gmail.com>2011-11-09 07:41:22 -0500
committerIlya Dryomov <idryomov@gmail.com>2011-11-09 15:53:39 -0500
commit04d21a244fdf79d0ac892eaaa9a46b682467277c (patch)
treeda0cadb86766bbf34f30c4b3efddde01e3d6d677 /fs
parent586e46e2813c589d26258a599580421fb6fb576b (diff)
Btrfs: rework error handling in btrfs_mount()
Commits 6c41761f and 45ea6095 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>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/super.c42
1 files changed, 21 insertions, 21 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 58e9492230ce..629281c65ff5 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -891,7 +891,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
891 struct super_block *s; 891 struct super_block *s;
892 struct dentry *root; 892 struct dentry *root;
893 struct btrfs_fs_devices *fs_devices = NULL; 893 struct btrfs_fs_devices *fs_devices = NULL;
894 struct btrfs_root *tree_root = NULL;
895 struct btrfs_fs_info *fs_info = NULL; 894 struct btrfs_fs_info *fs_info = NULL;
896 fmode_t mode = FMODE_READ; 895 fmode_t mode = FMODE_READ;
897 char *subvol_name = NULL; 896 char *subvol_name = NULL;
@@ -920,15 +919,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
920 if (error) 919 if (error)
921 return ERR_PTR(error); 920 return ERR_PTR(error);
922 921
923 error = btrfs_open_devices(fs_devices, mode, fs_type);
924 if (error)
925 return ERR_PTR(error);
926
927 if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
928 error = -EACCES;
929 goto error_close_devices;
930 }
931
932 /* 922 /*
933 * Setup a dummy root and fs_info for test/set super. This is because 923 * Setup a dummy root and fs_info for test/set super. This is because
934 * we don't actually fill this stuff out until open_ctree, but we need 924 * we don't actually fill this stuff out until open_ctree, but we need
@@ -936,28 +926,36 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
936 * then open_ctree will properly initialize everything later. 926 * then open_ctree will properly initialize everything later.
937 */ 927 */
938 fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS); 928 fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS);
939 if (!fs_info) { 929 if (!fs_info)
940 error = -ENOMEM; 930 return ERR_PTR(-ENOMEM);
941 goto error_close_devices; 931
942 } 932 fs_info->tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
943 tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); 933 if (!fs_info->tree_root) {
944 if (!tree_root) {
945 error = -ENOMEM; 934 error = -ENOMEM;
946 goto error_close_devices; 935 goto error_fs_info;
947 } 936 }
948 fs_info->tree_root = tree_root; 937 fs_info->tree_root->fs_info = fs_info;
949 fs_info->fs_devices = fs_devices; 938 fs_info->fs_devices = fs_devices;
950 tree_root->fs_info = fs_info;
951 939
952 fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); 940 fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
953 fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); 941 fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
954 if (!fs_info->super_copy || !fs_info->super_for_commit) { 942 if (!fs_info->super_copy || !fs_info->super_for_commit) {
955 error = -ENOMEM; 943 error = -ENOMEM;
944 goto error_fs_info;
945 }
946
947 error = btrfs_open_devices(fs_devices, mode, fs_type);
948 if (error)
949 goto error_fs_info;
950
951 if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
952 error = -EACCES;
956 goto error_close_devices; 953 goto error_close_devices;
957 } 954 }
958 955
959 bdev = fs_devices->latest_bdev; 956 bdev = fs_devices->latest_bdev;
960 s = sget(fs_type, btrfs_test_super, btrfs_set_super, tree_root); 957 s = sget(fs_type, btrfs_test_super, btrfs_set_super,
958 fs_info->tree_root);
961 if (IS_ERR(s)) { 959 if (IS_ERR(s)) {
962 error = PTR_ERR(s); 960 error = PTR_ERR(s);
963 goto error_close_devices; 961 goto error_close_devices;
@@ -966,7 +964,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
966 if (s->s_root) { 964 if (s->s_root) {
967 if ((flags ^ s->s_flags) & MS_RDONLY) { 965 if ((flags ^ s->s_flags) & MS_RDONLY) {
968 deactivate_locked_super(s); 966 deactivate_locked_super(s);
969 return ERR_PTR(-EBUSY); 967 error = -EBUSY;
968 goto error_close_devices;
970 } 969 }
971 970
972 btrfs_close_devices(fs_devices); 971 btrfs_close_devices(fs_devices);
@@ -997,6 +996,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
997 996
998error_close_devices: 997error_close_devices:
999 btrfs_close_devices(fs_devices); 998 btrfs_close_devices(fs_devices);
999error_fs_info:
1000 free_fs_info(fs_info); 1000 free_fs_info(fs_info);
1001 return ERR_PTR(error); 1001 return ERR_PTR(error);
1002} 1002}