diff options
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r-- | fs/btrfs/super.c | 87 |
1 files changed, 33 insertions, 54 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 57080dffdfc6..17ee7fc5e64e 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -197,7 +197,7 @@ static match_table_t tokens = { | |||
197 | {Opt_subvolrootid, "subvolrootid=%d"}, | 197 | {Opt_subvolrootid, "subvolrootid=%d"}, |
198 | {Opt_defrag, "autodefrag"}, | 198 | {Opt_defrag, "autodefrag"}, |
199 | {Opt_inode_cache, "inode_cache"}, | 199 | {Opt_inode_cache, "inode_cache"}, |
200 | {Opt_no_space_cache, "no_space_cache"}, | 200 | {Opt_no_space_cache, "nospace_cache"}, |
201 | {Opt_recovery, "recovery"}, | 201 | {Opt_recovery, "recovery"}, |
202 | {Opt_err, NULL}, | 202 | {Opt_err, NULL}, |
203 | }; | 203 | }; |
@@ -448,6 +448,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags, | |||
448 | token = match_token(p, tokens, args); | 448 | token = match_token(p, tokens, args); |
449 | switch (token) { | 449 | switch (token) { |
450 | case Opt_subvol: | 450 | case Opt_subvol: |
451 | kfree(*subvol_name); | ||
451 | *subvol_name = match_strdup(&args[0]); | 452 | *subvol_name = match_strdup(&args[0]); |
452 | break; | 453 | break; |
453 | case Opt_subvolid: | 454 | case Opt_subvolid: |
@@ -710,7 +711,7 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
710 | if (btrfs_test_opt(root, SPACE_CACHE)) | 711 | if (btrfs_test_opt(root, SPACE_CACHE)) |
711 | seq_puts(seq, ",space_cache"); | 712 | seq_puts(seq, ",space_cache"); |
712 | else | 713 | else |
713 | seq_puts(seq, ",no_space_cache"); | 714 | seq_puts(seq, ",nospace_cache"); |
714 | if (btrfs_test_opt(root, CLEAR_CACHE)) | 715 | if (btrfs_test_opt(root, CLEAR_CACHE)) |
715 | seq_puts(seq, ",clear_cache"); | 716 | seq_puts(seq, ",clear_cache"); |
716 | if (btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED)) | 717 | if (btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED)) |
@@ -824,13 +825,9 @@ static char *setup_root_args(char *args) | |||
824 | static struct dentry *mount_subvol(const char *subvol_name, int flags, | 825 | static struct dentry *mount_subvol(const char *subvol_name, int flags, |
825 | const char *device_name, char *data) | 826 | const char *device_name, char *data) |
826 | { | 827 | { |
827 | struct super_block *s; | ||
828 | struct dentry *root; | 828 | struct dentry *root; |
829 | struct vfsmount *mnt; | 829 | struct vfsmount *mnt; |
830 | struct mnt_namespace *ns_private; | ||
831 | char *newargs; | 830 | char *newargs; |
832 | struct path path; | ||
833 | int error; | ||
834 | 831 | ||
835 | newargs = setup_root_args(data); | 832 | newargs = setup_root_args(data); |
836 | if (!newargs) | 833 | if (!newargs) |
@@ -841,39 +838,17 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags, | |||
841 | if (IS_ERR(mnt)) | 838 | if (IS_ERR(mnt)) |
842 | return ERR_CAST(mnt); | 839 | return ERR_CAST(mnt); |
843 | 840 | ||
844 | ns_private = create_mnt_ns(mnt); | 841 | root = mount_subtree(mnt, subvol_name); |
845 | if (IS_ERR(ns_private)) { | ||
846 | mntput(mnt); | ||
847 | return ERR_CAST(ns_private); | ||
848 | } | ||
849 | |||
850 | /* | ||
851 | * This will trigger the automount of the subvol so we can just | ||
852 | * drop the mnt we have here and return the dentry that we | ||
853 | * found. | ||
854 | */ | ||
855 | error = vfs_path_lookup(mnt->mnt_root, mnt, subvol_name, | ||
856 | LOOKUP_FOLLOW, &path); | ||
857 | put_mnt_ns(ns_private); | ||
858 | if (error) | ||
859 | return ERR_PTR(error); | ||
860 | 842 | ||
861 | if (!is_subvolume_inode(path.dentry->d_inode)) { | 843 | if (!IS_ERR(root) && !is_subvolume_inode(root->d_inode)) { |
862 | path_put(&path); | 844 | struct super_block *s = root->d_sb; |
863 | mntput(mnt); | 845 | dput(root); |
864 | error = -EINVAL; | 846 | root = ERR_PTR(-EINVAL); |
847 | deactivate_locked_super(s); | ||
865 | printk(KERN_ERR "btrfs: '%s' is not a valid subvolume\n", | 848 | printk(KERN_ERR "btrfs: '%s' is not a valid subvolume\n", |
866 | subvol_name); | 849 | subvol_name); |
867 | return ERR_PTR(-EINVAL); | ||
868 | } | 850 | } |
869 | 851 | ||
870 | /* Get a ref to the sb and the dentry we found and return it */ | ||
871 | s = path.mnt->mnt_sb; | ||
872 | atomic_inc(&s->s_active); | ||
873 | root = dget(path.dentry); | ||
874 | path_put(&path); | ||
875 | down_write(&s->s_umount); | ||
876 | |||
877 | return root; | 852 | return root; |
878 | } | 853 | } |
879 | 854 | ||
@@ -890,7 +865,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
890 | struct super_block *s; | 865 | struct super_block *s; |
891 | struct dentry *root; | 866 | struct dentry *root; |
892 | struct btrfs_fs_devices *fs_devices = NULL; | 867 | struct btrfs_fs_devices *fs_devices = NULL; |
893 | struct btrfs_root *tree_root = NULL; | ||
894 | struct btrfs_fs_info *fs_info = NULL; | 868 | struct btrfs_fs_info *fs_info = NULL; |
895 | fmode_t mode = FMODE_READ; | 869 | fmode_t mode = FMODE_READ; |
896 | char *subvol_name = NULL; | 870 | char *subvol_name = NULL; |
@@ -904,8 +878,10 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
904 | error = btrfs_parse_early_options(data, mode, fs_type, | 878 | error = btrfs_parse_early_options(data, mode, fs_type, |
905 | &subvol_name, &subvol_objectid, | 879 | &subvol_name, &subvol_objectid, |
906 | &subvol_rootid, &fs_devices); | 880 | &subvol_rootid, &fs_devices); |
907 | if (error) | 881 | if (error) { |
882 | kfree(subvol_name); | ||
908 | return ERR_PTR(error); | 883 | return ERR_PTR(error); |
884 | } | ||
909 | 885 | ||
910 | if (subvol_name) { | 886 | if (subvol_name) { |
911 | root = mount_subvol(subvol_name, flags, device_name, data); | 887 | root = mount_subvol(subvol_name, flags, device_name, data); |
@@ -917,15 +893,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
917 | if (error) | 893 | if (error) |
918 | return ERR_PTR(error); | 894 | return ERR_PTR(error); |
919 | 895 | ||
920 | error = btrfs_open_devices(fs_devices, mode, fs_type); | ||
921 | if (error) | ||
922 | return ERR_PTR(error); | ||
923 | |||
924 | if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) { | ||
925 | error = -EACCES; | ||
926 | goto error_close_devices; | ||
927 | } | ||
928 | |||
929 | /* | 896 | /* |
930 | * Setup a dummy root and fs_info for test/set super. This is because | 897 | * Setup a dummy root and fs_info for test/set super. This is because |
931 | * we don't actually fill this stuff out until open_ctree, but we need | 898 | * we don't actually fill this stuff out until open_ctree, but we need |
@@ -933,24 +900,36 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
933 | * then open_ctree will properly initialize everything later. | 900 | * then open_ctree will properly initialize everything later. |
934 | */ | 901 | */ |
935 | fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS); | 902 | fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS); |
936 | tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); | 903 | if (!fs_info) |
937 | if (!fs_info || !tree_root) { | 904 | return ERR_PTR(-ENOMEM); |
905 | |||
906 | fs_info->tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); | ||
907 | if (!fs_info->tree_root) { | ||
938 | error = -ENOMEM; | 908 | error = -ENOMEM; |
939 | goto error_close_devices; | 909 | goto error_fs_info; |
940 | } | 910 | } |
941 | fs_info->tree_root = tree_root; | 911 | fs_info->tree_root->fs_info = fs_info; |
942 | fs_info->fs_devices = fs_devices; | 912 | fs_info->fs_devices = fs_devices; |
943 | tree_root->fs_info = fs_info; | ||
944 | 913 | ||
945 | fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); | 914 | fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); |
946 | fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); | 915 | fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); |
947 | if (!fs_info->super_copy || !fs_info->super_for_commit) { | 916 | if (!fs_info->super_copy || !fs_info->super_for_commit) { |
948 | error = -ENOMEM; | 917 | error = -ENOMEM; |
918 | goto error_fs_info; | ||
919 | } | ||
920 | |||
921 | error = btrfs_open_devices(fs_devices, mode, fs_type); | ||
922 | if (error) | ||
923 | goto error_fs_info; | ||
924 | |||
925 | if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) { | ||
926 | error = -EACCES; | ||
949 | goto error_close_devices; | 927 | goto error_close_devices; |
950 | } | 928 | } |
951 | 929 | ||
952 | bdev = fs_devices->latest_bdev; | 930 | bdev = fs_devices->latest_bdev; |
953 | s = sget(fs_type, btrfs_test_super, btrfs_set_super, tree_root); | 931 | s = sget(fs_type, btrfs_test_super, btrfs_set_super, |
932 | fs_info->tree_root); | ||
954 | if (IS_ERR(s)) { | 933 | if (IS_ERR(s)) { |
955 | error = PTR_ERR(s); | 934 | error = PTR_ERR(s); |
956 | goto error_close_devices; | 935 | goto error_close_devices; |
@@ -959,12 +938,12 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
959 | if (s->s_root) { | 938 | if (s->s_root) { |
960 | if ((flags ^ s->s_flags) & MS_RDONLY) { | 939 | if ((flags ^ s->s_flags) & MS_RDONLY) { |
961 | deactivate_locked_super(s); | 940 | deactivate_locked_super(s); |
962 | return ERR_PTR(-EBUSY); | 941 | error = -EBUSY; |
942 | goto error_close_devices; | ||
963 | } | 943 | } |
964 | 944 | ||
965 | btrfs_close_devices(fs_devices); | 945 | btrfs_close_devices(fs_devices); |
966 | free_fs_info(fs_info); | 946 | free_fs_info(fs_info); |
967 | kfree(tree_root); | ||
968 | } else { | 947 | } else { |
969 | char b[BDEVNAME_SIZE]; | 948 | char b[BDEVNAME_SIZE]; |
970 | 949 | ||
@@ -991,8 +970,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
991 | 970 | ||
992 | error_close_devices: | 971 | error_close_devices: |
993 | btrfs_close_devices(fs_devices); | 972 | btrfs_close_devices(fs_devices); |
973 | error_fs_info: | ||
994 | free_fs_info(fs_info); | 974 | free_fs_info(fs_info); |
995 | kfree(tree_root); | ||
996 | return ERR_PTR(error); | 975 | return ERR_PTR(error); |
997 | } | 976 | } |
998 | 977 | ||