diff options
-rw-r--r-- | fs/internal.h | 5 | ||||
-rw-r--r-- | fs/namespace.c | 153 | ||||
-rw-r--r-- | fs/super.c | 96 |
3 files changed, 132 insertions, 122 deletions
diff --git a/fs/internal.h b/fs/internal.h index f3d15de44b15..17191546d527 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/lglock.h> | 12 | #include <linux/lglock.h> |
13 | 13 | ||
14 | struct super_block; | 14 | struct super_block; |
15 | struct file_system_type; | ||
15 | struct linux_binprm; | 16 | struct linux_binprm; |
16 | struct path; | 17 | struct path; |
17 | 18 | ||
@@ -61,8 +62,6 @@ extern int check_unsafe_exec(struct linux_binprm *); | |||
61 | extern int copy_mount_options(const void __user *, unsigned long *); | 62 | extern int copy_mount_options(const void __user *, unsigned long *); |
62 | extern int copy_mount_string(const void __user *, char **); | 63 | extern int copy_mount_string(const void __user *, char **); |
63 | 64 | ||
64 | extern void free_vfsmnt(struct vfsmount *); | ||
65 | extern struct vfsmount *alloc_vfsmnt(const char *); | ||
66 | extern unsigned int mnt_get_count(struct vfsmount *mnt); | 65 | extern unsigned int mnt_get_count(struct vfsmount *mnt); |
67 | extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); | 66 | extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); |
68 | extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, | 67 | extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, |
@@ -99,6 +98,8 @@ extern struct file *get_empty_filp(void); | |||
99 | extern int do_remount_sb(struct super_block *, int, void *, int); | 98 | extern int do_remount_sb(struct super_block *, int, void *, int); |
100 | extern void __put_super(struct super_block *sb); | 99 | extern void __put_super(struct super_block *sb); |
101 | extern void put_super(struct super_block *sb); | 100 | extern void put_super(struct super_block *sb); |
101 | extern struct dentry *mount_fs(struct file_system_type *, | ||
102 | int, const char *, void *); | ||
102 | 103 | ||
103 | /* | 104 | /* |
104 | * open.c | 105 | * open.c |
diff --git a/fs/namespace.c b/fs/namespace.c index a2a01a104ab0..453529f72dff 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -196,7 +196,7 @@ unsigned int mnt_get_count(struct vfsmount *mnt) | |||
196 | #endif | 196 | #endif |
197 | } | 197 | } |
198 | 198 | ||
199 | struct vfsmount *alloc_vfsmnt(const char *name) | 199 | static struct vfsmount *alloc_vfsmnt(const char *name) |
200 | { | 200 | { |
201 | struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); | 201 | struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); |
202 | if (mnt) { | 202 | if (mnt) { |
@@ -466,7 +466,7 @@ static void __mnt_unmake_readonly(struct vfsmount *mnt) | |||
466 | br_write_unlock(vfsmount_lock); | 466 | br_write_unlock(vfsmount_lock); |
467 | } | 467 | } |
468 | 468 | ||
469 | void free_vfsmnt(struct vfsmount *mnt) | 469 | static void free_vfsmnt(struct vfsmount *mnt) |
470 | { | 470 | { |
471 | kfree(mnt->mnt_devname); | 471 | kfree(mnt->mnt_devname); |
472 | mnt_free_id(mnt); | 472 | mnt_free_id(mnt); |
@@ -670,6 +670,36 @@ static struct vfsmount *skip_mnt_tree(struct vfsmount *p) | |||
670 | return p; | 670 | return p; |
671 | } | 671 | } |
672 | 672 | ||
673 | struct vfsmount * | ||
674 | vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) | ||
675 | { | ||
676 | struct vfsmount *mnt; | ||
677 | struct dentry *root; | ||
678 | |||
679 | if (!type) | ||
680 | return ERR_PTR(-ENODEV); | ||
681 | |||
682 | mnt = alloc_vfsmnt(name); | ||
683 | if (!mnt) | ||
684 | return ERR_PTR(-ENOMEM); | ||
685 | |||
686 | if (flags & MS_KERNMOUNT) | ||
687 | mnt->mnt_flags = MNT_INTERNAL; | ||
688 | |||
689 | root = mount_fs(type, flags, name, data); | ||
690 | if (IS_ERR(root)) { | ||
691 | free_vfsmnt(mnt); | ||
692 | return ERR_CAST(root); | ||
693 | } | ||
694 | |||
695 | mnt->mnt_root = root; | ||
696 | mnt->mnt_sb = root->d_sb; | ||
697 | mnt->mnt_mountpoint = mnt->mnt_root; | ||
698 | mnt->mnt_parent = mnt; | ||
699 | return mnt; | ||
700 | } | ||
701 | EXPORT_SYMBOL_GPL(vfs_kern_mount); | ||
702 | |||
673 | static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, | 703 | static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, |
674 | int flag) | 704 | int flag) |
675 | { | 705 | { |
@@ -1905,7 +1935,81 @@ out: | |||
1905 | return err; | 1935 | return err; |
1906 | } | 1936 | } |
1907 | 1937 | ||
1908 | static int do_add_mount(struct vfsmount *, struct path *, int); | 1938 | static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) |
1939 | { | ||
1940 | int err; | ||
1941 | const char *subtype = strchr(fstype, '.'); | ||
1942 | if (subtype) { | ||
1943 | subtype++; | ||
1944 | err = -EINVAL; | ||
1945 | if (!subtype[0]) | ||
1946 | goto err; | ||
1947 | } else | ||
1948 | subtype = ""; | ||
1949 | |||
1950 | mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL); | ||
1951 | err = -ENOMEM; | ||
1952 | if (!mnt->mnt_sb->s_subtype) | ||
1953 | goto err; | ||
1954 | return mnt; | ||
1955 | |||
1956 | err: | ||
1957 | mntput(mnt); | ||
1958 | return ERR_PTR(err); | ||
1959 | } | ||
1960 | |||
1961 | struct vfsmount * | ||
1962 | do_kern_mount(const char *fstype, int flags, const char *name, void *data) | ||
1963 | { | ||
1964 | struct file_system_type *type = get_fs_type(fstype); | ||
1965 | struct vfsmount *mnt; | ||
1966 | if (!type) | ||
1967 | return ERR_PTR(-ENODEV); | ||
1968 | mnt = vfs_kern_mount(type, flags, name, data); | ||
1969 | if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && | ||
1970 | !mnt->mnt_sb->s_subtype) | ||
1971 | mnt = fs_set_subtype(mnt, fstype); | ||
1972 | put_filesystem(type); | ||
1973 | return mnt; | ||
1974 | } | ||
1975 | EXPORT_SYMBOL_GPL(do_kern_mount); | ||
1976 | |||
1977 | /* | ||
1978 | * add a mount into a namespace's mount tree | ||
1979 | */ | ||
1980 | static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) | ||
1981 | { | ||
1982 | int err; | ||
1983 | |||
1984 | mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL); | ||
1985 | |||
1986 | down_write(&namespace_sem); | ||
1987 | /* Something was mounted here while we slept */ | ||
1988 | err = follow_down(path, true); | ||
1989 | if (err < 0) | ||
1990 | goto unlock; | ||
1991 | |||
1992 | err = -EINVAL; | ||
1993 | if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) | ||
1994 | goto unlock; | ||
1995 | |||
1996 | /* Refuse the same filesystem on the same mount point */ | ||
1997 | err = -EBUSY; | ||
1998 | if (path->mnt->mnt_sb == newmnt->mnt_sb && | ||
1999 | path->mnt->mnt_root == path->dentry) | ||
2000 | goto unlock; | ||
2001 | |||
2002 | err = -EINVAL; | ||
2003 | if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode)) | ||
2004 | goto unlock; | ||
2005 | |||
2006 | newmnt->mnt_flags = mnt_flags; | ||
2007 | err = graft_tree(newmnt, path); | ||
2008 | |||
2009 | unlock: | ||
2010 | up_write(&namespace_sem); | ||
2011 | return err; | ||
2012 | } | ||
1909 | 2013 | ||
1910 | /* | 2014 | /* |
1911 | * create a new mount for userspace and request it to be added into the | 2015 | * create a new mount for userspace and request it to be added into the |
@@ -1965,43 +2069,6 @@ fail: | |||
1965 | return err; | 2069 | return err; |
1966 | } | 2070 | } |
1967 | 2071 | ||
1968 | /* | ||
1969 | * add a mount into a namespace's mount tree | ||
1970 | */ | ||
1971 | static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) | ||
1972 | { | ||
1973 | int err; | ||
1974 | |||
1975 | mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL); | ||
1976 | |||
1977 | down_write(&namespace_sem); | ||
1978 | /* Something was mounted here while we slept */ | ||
1979 | err = follow_down(path, true); | ||
1980 | if (err < 0) | ||
1981 | goto unlock; | ||
1982 | |||
1983 | err = -EINVAL; | ||
1984 | if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) | ||
1985 | goto unlock; | ||
1986 | |||
1987 | /* Refuse the same filesystem on the same mount point */ | ||
1988 | err = -EBUSY; | ||
1989 | if (path->mnt->mnt_sb == newmnt->mnt_sb && | ||
1990 | path->mnt->mnt_root == path->dentry) | ||
1991 | goto unlock; | ||
1992 | |||
1993 | err = -EINVAL; | ||
1994 | if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode)) | ||
1995 | goto unlock; | ||
1996 | |||
1997 | newmnt->mnt_flags = mnt_flags; | ||
1998 | err = graft_tree(newmnt, path); | ||
1999 | |||
2000 | unlock: | ||
2001 | up_write(&namespace_sem); | ||
2002 | return err; | ||
2003 | } | ||
2004 | |||
2005 | /** | 2072 | /** |
2006 | * mnt_set_expiry - Put a mount on an expiration list | 2073 | * mnt_set_expiry - Put a mount on an expiration list |
2007 | * @mnt: The mount to list. | 2074 | * @mnt: The mount to list. |
@@ -2660,3 +2727,9 @@ void put_mnt_ns(struct mnt_namespace *ns) | |||
2660 | kfree(ns); | 2727 | kfree(ns); |
2661 | } | 2728 | } |
2662 | EXPORT_SYMBOL(put_mnt_ns); | 2729 | EXPORT_SYMBOL(put_mnt_ns); |
2730 | |||
2731 | struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) | ||
2732 | { | ||
2733 | return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data); | ||
2734 | } | ||
2735 | EXPORT_SYMBOL_GPL(kern_mount_data); | ||
diff --git a/fs/super.c b/fs/super.c index 4bae0ef6110e..e84864908264 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -910,29 +910,18 @@ struct dentry *mount_single(struct file_system_type *fs_type, | |||
910 | } | 910 | } |
911 | EXPORT_SYMBOL(mount_single); | 911 | EXPORT_SYMBOL(mount_single); |
912 | 912 | ||
913 | struct vfsmount * | 913 | struct dentry * |
914 | vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) | 914 | mount_fs(struct file_system_type *type, int flags, const char *name, void *data) |
915 | { | 915 | { |
916 | struct vfsmount *mnt; | ||
917 | struct dentry *root; | 916 | struct dentry *root; |
917 | struct super_block *sb; | ||
918 | char *secdata = NULL; | 918 | char *secdata = NULL; |
919 | int error; | 919 | int error = -ENOMEM; |
920 | |||
921 | if (!type) | ||
922 | return ERR_PTR(-ENODEV); | ||
923 | |||
924 | error = -ENOMEM; | ||
925 | mnt = alloc_vfsmnt(name); | ||
926 | if (!mnt) | ||
927 | goto out; | ||
928 | |||
929 | if (flags & MS_KERNMOUNT) | ||
930 | mnt->mnt_flags = MNT_INTERNAL; | ||
931 | 920 | ||
932 | if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) { | 921 | if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) { |
933 | secdata = alloc_secdata(); | 922 | secdata = alloc_secdata(); |
934 | if (!secdata) | 923 | if (!secdata) |
935 | goto out_mnt; | 924 | goto out; |
936 | 925 | ||
937 | error = security_sb_copy_data(data, secdata); | 926 | error = security_sb_copy_data(data, secdata); |
938 | if (error) | 927 | if (error) |
@@ -944,13 +933,12 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void | |||
944 | error = PTR_ERR(root); | 933 | error = PTR_ERR(root); |
945 | goto out_free_secdata; | 934 | goto out_free_secdata; |
946 | } | 935 | } |
947 | mnt->mnt_root = root; | 936 | sb = root->d_sb; |
948 | mnt->mnt_sb = root->d_sb; | 937 | BUG_ON(!sb); |
949 | BUG_ON(!mnt->mnt_sb); | 938 | WARN_ON(!sb->s_bdi); |
950 | WARN_ON(!mnt->mnt_sb->s_bdi); | 939 | sb->s_flags |= MS_BORN; |
951 | mnt->mnt_sb->s_flags |= MS_BORN; | ||
952 | 940 | ||
953 | error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); | 941 | error = security_sb_kern_mount(sb, flags, secdata); |
954 | if (error) | 942 | if (error) |
955 | goto out_sb; | 943 | goto out_sb; |
956 | 944 | ||
@@ -961,27 +949,21 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void | |||
961 | * violate this rule. This warning should be either removed or | 949 | * violate this rule. This warning should be either removed or |
962 | * converted to a BUG() in 2.6.34. | 950 | * converted to a BUG() in 2.6.34. |
963 | */ | 951 | */ |
964 | WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to " | 952 | WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to " |
965 | "negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes); | 953 | "negative value (%lld)\n", type->name, sb->s_maxbytes); |
966 | 954 | ||
967 | mnt->mnt_mountpoint = mnt->mnt_root; | 955 | up_write(&sb->s_umount); |
968 | mnt->mnt_parent = mnt; | ||
969 | up_write(&mnt->mnt_sb->s_umount); | ||
970 | free_secdata(secdata); | 956 | free_secdata(secdata); |
971 | return mnt; | 957 | return root; |
972 | out_sb: | 958 | out_sb: |
973 | dput(mnt->mnt_root); | 959 | dput(root); |
974 | deactivate_locked_super(mnt->mnt_sb); | 960 | deactivate_locked_super(sb); |
975 | out_free_secdata: | 961 | out_free_secdata: |
976 | free_secdata(secdata); | 962 | free_secdata(secdata); |
977 | out_mnt: | ||
978 | free_vfsmnt(mnt); | ||
979 | out: | 963 | out: |
980 | return ERR_PTR(error); | 964 | return ERR_PTR(error); |
981 | } | 965 | } |
982 | 966 | ||
983 | EXPORT_SYMBOL_GPL(vfs_kern_mount); | ||
984 | |||
985 | /** | 967 | /** |
986 | * freeze_super - lock the filesystem and force it into a consistent state | 968 | * freeze_super - lock the filesystem and force it into a consistent state |
987 | * @sb: the super to lock | 969 | * @sb: the super to lock |
@@ -1071,49 +1053,3 @@ out: | |||
1071 | return 0; | 1053 | return 0; |
1072 | } | 1054 | } |
1073 | EXPORT_SYMBOL(thaw_super); | 1055 | EXPORT_SYMBOL(thaw_super); |
1074 | |||
1075 | static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) | ||
1076 | { | ||
1077 | int err; | ||
1078 | const char *subtype = strchr(fstype, '.'); | ||
1079 | if (subtype) { | ||
1080 | subtype++; | ||
1081 | err = -EINVAL; | ||
1082 | if (!subtype[0]) | ||
1083 | goto err; | ||
1084 | } else | ||
1085 | subtype = ""; | ||
1086 | |||
1087 | mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL); | ||
1088 | err = -ENOMEM; | ||
1089 | if (!mnt->mnt_sb->s_subtype) | ||
1090 | goto err; | ||
1091 | return mnt; | ||
1092 | |||
1093 | err: | ||
1094 | mntput(mnt); | ||
1095 | return ERR_PTR(err); | ||
1096 | } | ||
1097 | |||
1098 | struct vfsmount * | ||
1099 | do_kern_mount(const char *fstype, int flags, const char *name, void *data) | ||
1100 | { | ||
1101 | struct file_system_type *type = get_fs_type(fstype); | ||
1102 | struct vfsmount *mnt; | ||
1103 | if (!type) | ||
1104 | return ERR_PTR(-ENODEV); | ||
1105 | mnt = vfs_kern_mount(type, flags, name, data); | ||
1106 | if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && | ||
1107 | !mnt->mnt_sb->s_subtype) | ||
1108 | mnt = fs_set_subtype(mnt, fstype); | ||
1109 | put_filesystem(type); | ||
1110 | return mnt; | ||
1111 | } | ||
1112 | EXPORT_SYMBOL_GPL(do_kern_mount); | ||
1113 | |||
1114 | struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) | ||
1115 | { | ||
1116 | return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data); | ||
1117 | } | ||
1118 | |||
1119 | EXPORT_SYMBOL_GPL(kern_mount_data); | ||