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 f3d15de44b1..17191546d52 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -12,6 +12,7 @@ #include <linux/lglock.h> struct super_block; +struct file_system_type; struct linux_binprm; struct path; @@ -61,8 +62,6 @@ extern int check_unsafe_exec(struct linux_binprm *); extern int copy_mount_options(const void __user *, unsigned long *); extern int copy_mount_string(const void __user *, char **); -extern void free_vfsmnt(struct vfsmount *); -extern struct vfsmount *alloc_vfsmnt(const char *); extern unsigned int mnt_get_count(struct vfsmount *mnt); extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, @@ -99,6 +98,8 @@ extern struct file *get_empty_filp(void); extern int do_remount_sb(struct super_block *, int, void *, int); extern void __put_super(struct super_block *sb); extern void put_super(struct super_block *sb); +extern struct dentry *mount_fs(struct file_system_type *, + int, const char *, void *); /* * open.c diff --git a/fs/namespace.c b/fs/namespace.c index a2a01a104ab..453529f72df 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -196,7 +196,7 @@ unsigned int mnt_get_count(struct vfsmount *mnt) #endif } -struct vfsmount *alloc_vfsmnt(const char *name) +static struct vfsmount *alloc_vfsmnt(const char *name) { struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); if (mnt) { @@ -466,7 +466,7 @@ static void __mnt_unmake_readonly(struct vfsmount *mnt) br_write_unlock(vfsmount_lock); } -void free_vfsmnt(struct vfsmount *mnt) +static void free_vfsmnt(struct vfsmount *mnt) { kfree(mnt->mnt_devname); mnt_free_id(mnt); @@ -670,6 +670,36 @@ static struct vfsmount *skip_mnt_tree(struct vfsmount *p) return p; } +struct vfsmount * +vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) +{ + struct vfsmount *mnt; + struct dentry *root; + + if (!type) + return ERR_PTR(-ENODEV); + + mnt = alloc_vfsmnt(name); + if (!mnt) + return ERR_PTR(-ENOMEM); + + if (flags & MS_KERNMOUNT) + mnt->mnt_flags = MNT_INTERNAL; + + root = mount_fs(type, flags, name, data); + if (IS_ERR(root)) { + free_vfsmnt(mnt); + return ERR_CAST(root); + } + + mnt->mnt_root = root; + mnt->mnt_sb = root->d_sb; + mnt->mnt_mountpoint = mnt->mnt_root; + mnt->mnt_parent = mnt; + return mnt; +} +EXPORT_SYMBOL_GPL(vfs_kern_mount); + static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, int flag) { @@ -1905,7 +1935,81 @@ out: return err; } -static int do_add_mount(struct vfsmount *, struct path *, int); +static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) +{ + int err; + const char *subtype = strchr(fstype, '.'); + if (subtype) { + subtype++; + err = -EINVAL; + if (!subtype[0]) + goto err; + } else + subtype = ""; + + mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL); + err = -ENOMEM; + if (!mnt->mnt_sb->s_subtype) + goto err; + return mnt; + + err: + mntput(mnt); + return ERR_PTR(err); +} + +struct vfsmount * +do_kern_mount(const char *fstype, int flags, const char *name, void *data) +{ + struct file_system_type *type = get_fs_type(fstype); + struct vfsmount *mnt; + if (!type) + return ERR_PTR(-ENODEV); + mnt = vfs_kern_mount(type, flags, name, data); + if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && + !mnt->mnt_sb->s_subtype) + mnt = fs_set_subtype(mnt, fstype); + put_filesystem(type); + return mnt; +} +EXPORT_SYMBOL_GPL(do_kern_mount); + +/* + * add a mount into a namespace's mount tree + */ +static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) +{ + int err; + + mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL); + + down_write(&namespace_sem); + /* Something was mounted here while we slept */ + err = follow_down(path, true); + if (err < 0) + goto unlock; + + err = -EINVAL; + if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) + goto unlock; + + /* Refuse the same filesystem on the same mount point */ + err = -EBUSY; + if (path->mnt->mnt_sb == newmnt->mnt_sb && + path->mnt->mnt_root == path->dentry) + goto unlock; + + err = -EINVAL; + if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode)) + goto unlock; + + newmnt->mnt_flags = mnt_flags; + err = graft_tree(newmnt, path); + +unlock: + up_write(&namespace_sem); + return err; +} /* * create a new mount for userspace and request it to be added into the @@ -1965,43 +2069,6 @@ fail: return err; } -/* - * add a mount into a namespace's mount tree - */ -static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) -{ - int err; - - mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL); - - down_write(&namespace_sem); - /* Something was mounted here while we slept */ - err = follow_down(path, true); - if (err < 0) - goto unlock; - - err = -EINVAL; - if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) - goto unlock; - - /* Refuse the same filesystem on the same mount point */ - err = -EBUSY; - if (path->mnt->mnt_sb == newmnt->mnt_sb && - path->mnt->mnt_root == path->dentry) - goto unlock; - - err = -EINVAL; - if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode)) - goto unlock; - - newmnt->mnt_flags = mnt_flags; - err = graft_tree(newmnt, path); - -unlock: - up_write(&namespace_sem); - return err; -} - /** * mnt_set_expiry - Put a mount on an expiration list * @mnt: The mount to list. @@ -2660,3 +2727,9 @@ void put_mnt_ns(struct mnt_namespace *ns) kfree(ns); } EXPORT_SYMBOL(put_mnt_ns); + +struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) +{ + return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data); +} +EXPORT_SYMBOL_GPL(kern_mount_data); diff --git a/fs/super.c b/fs/super.c index 4bae0ef6110..e8486490826 100644 --- a/fs/super.c +++ b/fs/super.c @@ -910,29 +910,18 @@ struct dentry *mount_single(struct file_system_type *fs_type, } EXPORT_SYMBOL(mount_single); -struct vfsmount * -vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) +struct dentry * +mount_fs(struct file_system_type *type, int flags, const char *name, void *data) { - struct vfsmount *mnt; struct dentry *root; + struct super_block *sb; char *secdata = NULL; - int error; - - if (!type) - return ERR_PTR(-ENODEV); - - error = -ENOMEM; - mnt = alloc_vfsmnt(name); - if (!mnt) - goto out; - - if (flags & MS_KERNMOUNT) - mnt->mnt_flags = MNT_INTERNAL; + int error = -ENOMEM; if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) { secdata = alloc_secdata(); if (!secdata) - goto out_mnt; + goto out; error = security_sb_copy_data(data, secdata); if (error) @@ -944,13 +933,12 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void error = PTR_ERR(root); goto out_free_secdata; } - mnt->mnt_root = root; - mnt->mnt_sb = root->d_sb; - BUG_ON(!mnt->mnt_sb); - WARN_ON(!mnt->mnt_sb->s_bdi); - mnt->mnt_sb->s_flags |= MS_BORN; + sb = root->d_sb; + BUG_ON(!sb); + WARN_ON(!sb->s_bdi); + sb->s_flags |= MS_BORN; - error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); + error = security_sb_kern_mount(sb, flags, secdata); if (error) goto out_sb; @@ -961,27 +949,21 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void * violate this rule. This warning should be either removed or * converted to a BUG() in 2.6.34. */ - WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to " - "negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes); + WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to " + "negative value (%lld)\n", type->name, sb->s_maxbytes); - mnt->mnt_mountpoint = mnt->mnt_root; - mnt->mnt_parent = mnt; - up_write(&mnt->mnt_sb->s_umount); + up_write(&sb->s_umount); free_secdata(secdata); - return mnt; + return root; out_sb: - dput(mnt->mnt_root); - deactivate_locked_super(mnt->mnt_sb); + dput(root); + deactivate_locked_super(sb); out_free_secdata: free_secdata(secdata); -out_mnt: - free_vfsmnt(mnt); out: return ERR_PTR(error); } -EXPORT_SYMBOL_GPL(vfs_kern_mount); - /** * freeze_super - lock the filesystem and force it into a consistent state * @sb: the super to lock @@ -1071,49 +1053,3 @@ out: return 0; } EXPORT_SYMBOL(thaw_super); - -static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) -{ - int err; - const char *subtype = strchr(fstype, '.'); - if (subtype) { - subtype++; - err = -EINVAL; - if (!subtype[0]) - goto err; - } else - subtype = ""; - - mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL); - err = -ENOMEM; - if (!mnt->mnt_sb->s_subtype) - goto err; - return mnt; - - err: - mntput(mnt); - return ERR_PTR(err); -} - -struct vfsmount * -do_kern_mount(const char *fstype, int flags, const char *name, void *data) -{ - struct file_system_type *type = get_fs_type(fstype); - struct vfsmount *mnt; - if (!type) - return ERR_PTR(-ENODEV); - mnt = vfs_kern_mount(type, flags, name, data); - if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && - !mnt->mnt_sb->s_subtype) - mnt = fs_set_subtype(mnt, fstype); - put_filesystem(type); - return mnt; -} -EXPORT_SYMBOL_GPL(do_kern_mount); - -struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) -{ - return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data); -} - -EXPORT_SYMBOL_GPL(kern_mount_data); |