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 /fs/namespace.c | |
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>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 153 |
1 files changed, 113 insertions, 40 deletions
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); | ||