diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-17 22:08:28 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-17 22:10:41 -0400 |
| commit | 9d412a43c3b26e1e549319e5eec26f0829f9f74d (patch) | |
| tree | b6522b693564fed172e9f8aee2e42aa2fdd95c8a | |
| parent | fbe0aa1f3d16fac5b641c0c1697371dcbe45b569 (diff) | |
vfs: split off vfsmount-related parts of vfs_kern_mount()
new function: mount_fs(). Does all work done by vfs_kern_mount()
except the allocation and filling of vfsmount; returns root dentry
or ERR_PTR().
vfs_kern_mount() switched to using it and taken to fs/namespace.c,
along with its wrappers.
alloc_vfsmnt()/free_vfsmnt() made static.
functions in namespace.c slightly reordered.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -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); | ||
