From 6d59e7f582ef1c1988542d0fc3b36d0087b757ce Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 22 Mar 2008 15:48:17 -0400 Subject: [PATCH] move a bunch of declarations to fs/internal.h Signed-off-by: Al Viro --- fs/internal.h | 11 +++++++++++ fs/pnode.c | 1 + fs/super.c | 1 + include/linux/dcache.h | 1 - include/linux/fs.h | 6 ------ include/linux/mount.h | 2 -- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/fs/internal.h b/fs/internal.h index 392e8ccd6fc4..80aa9a023372 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -43,3 +43,14 @@ extern void __init chrdev_init(void); * namespace.c */ extern int copy_mount_options(const void __user *, unsigned long *); + +extern void free_vfsmnt(struct vfsmount *); +extern struct vfsmount *alloc_vfsmnt(const char *); +extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); +extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, + struct vfsmount *); +extern void release_mounts(struct list_head *); +extern void umount_tree(struct vfsmount *, int, struct list_head *); +extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); + +extern void __init mnt_init(void); diff --git a/fs/pnode.c b/fs/pnode.c index 1d8f5447f3f7..a9e0d6fadbcd 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -9,6 +9,7 @@ #include #include #include +#include "internal.h" #include "pnode.h" /* return the next shared peer mount of @p */ diff --git a/fs/super.c b/fs/super.c index 1f8f05ede437..4798350b2bc9 100644 --- a/fs/super.c +++ b/fs/super.c @@ -39,6 +39,7 @@ #include #include #include +#include "internal.h" LIST_HEAD(super_blocks); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 6bd646096fa6..fabd16d03a27 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -359,7 +359,6 @@ static inline int d_mountpoint(struct dentry *dentry) } extern struct vfsmount *lookup_mnt(struct vfsmount *, struct dentry *); -extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); extern struct dentry *lookup_create(struct nameidata *nd, int is_dir); extern int sysctl_vfs_cache_pressure; diff --git a/include/linux/fs.h b/include/linux/fs.h index 0c609e71c379..cc2be2cf7d41 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -305,7 +305,6 @@ struct vfsmount; extern void __init inode_init(void); extern void __init inode_init_early(void); -extern void __init mnt_init(void); extern void __init files_init(unsigned long); struct buffer_head; @@ -1536,12 +1535,7 @@ extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data); #define kern_mount(type) kern_mount_data(type, NULL) extern int may_umount_tree(struct vfsmount *); extern int may_umount(struct vfsmount *); -extern void umount_tree(struct vfsmount *, int, struct list_head *); -extern void release_mounts(struct list_head *); extern long do_mount(char *, char *, char *, unsigned long, void *); -extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); -extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, - struct vfsmount *); extern struct vfsmount *collect_mounts(struct vfsmount *, struct dentry *); extern void drop_collected_mounts(struct vfsmount *); diff --git a/include/linux/mount.h b/include/linux/mount.h index d6600e3f7e45..87b24cea1863 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -94,8 +94,6 @@ static inline void mntput(struct vfsmount *mnt) } } -extern void free_vfsmnt(struct vfsmount *mnt); -extern struct vfsmount *alloc_vfsmnt(const char *name); extern struct vfsmount *do_kern_mount(const char *fstype, int flags, const char *name, void *data); -- cgit v1.2.3 From 1a60a280778ff90270fc7390d9ec102f713a5a29 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 22 Mar 2008 16:19:49 -0400 Subject: [PATCH] lock exclusively in collect_mounts() and drop_collected_mounts() Taking namespace_sem shared there isn't worth the trouble, especially with vfsmount ID allocation about to be added. That way we know that umount_tree(), copy_tree() and clone_mnt() are _always_ serialized by namespace_sem. umount_tree() still needs vfsmount_lock (it manipulates hash chains, among other things), but that's a separate story. Signed-off-by: Al Viro --- fs/namespace.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 678f7ce060f2..af2fb3707d0a 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1091,20 +1091,20 @@ Enomem: struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry) { struct vfsmount *tree; - down_read(&namespace_sem); + down_write(&namespace_sem); tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE); - up_read(&namespace_sem); + up_write(&namespace_sem); return tree; } void drop_collected_mounts(struct vfsmount *mnt) { LIST_HEAD(umount_list); - down_read(&namespace_sem); + down_write(&namespace_sem); spin_lock(&vfsmount_lock); umount_tree(mnt, 0, &umount_list); spin_unlock(&vfsmount_lock); - up_read(&namespace_sem); + up_write(&namespace_sem); release_mounts(&umount_list); } -- cgit v1.2.3 From b5266eb4c8d1a2887a19aaec8144ee4ad1b054c3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 22 Mar 2008 17:48:24 -0400 Subject: [PATCH] switch a bunch of LSM hooks from nameidata to path Namely, ones from namespace.c Signed-off-by: Al Viro --- fs/namespace.c | 11 +++++----- include/linux/security.h | 52 +++++++++++++++++++++++----------------------- security/dummy.c | 10 ++++----- security/security.c | 20 +++++++++--------- security/selinux/hooks.c | 8 +++---- security/smack/smack_lsm.c | 4 ++-- 6 files changed, 53 insertions(+), 52 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index af2fb3707d0a..87d2d82010bb 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1220,7 +1220,7 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) if (IS_DEADDIR(nd->path.dentry->d_inode)) goto out_unlock; - err = security_sb_check_sb(mnt, nd); + err = security_sb_check_sb(mnt, &nd->path); if (err) goto out_unlock; @@ -1230,7 +1230,7 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) out_unlock: mutex_unlock(&nd->path.dentry->d_inode->i_mutex); if (!err) - security_sb_post_addmount(mnt, nd); + security_sb_post_addmount(mnt, &nd->path); return err; } @@ -1746,7 +1746,8 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, if (retval) return retval; - retval = security_sb_mount(dev_name, &nd, type_page, flags, data_page); + retval = security_sb_mount(dev_name, &nd.path, + type_page, flags, data_page); if (retval) goto dput_out; @@ -2007,7 +2008,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root, if (error) goto out1; - error = security_sb_pivotroot(&old_nd, &new_nd); + error = security_sb_pivotroot(&old_nd.path, &new_nd.path); if (error) { path_put(&old_nd.path); goto out1; @@ -2070,7 +2071,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root, touch_mnt_namespace(current->nsproxy->mnt_ns); spin_unlock(&vfsmount_lock); chroot_fs_refs(&user_nd.path, &new_nd.path); - security_sb_post_pivotroot(&user_nd, &new_nd); + security_sb_post_pivotroot(&user_nd.path, &new_nd.path); error = 0; path_put(&root_parent); path_put(&parent_path); diff --git a/include/linux/security.h b/include/linux/security.h index fea1f4aa4dd5..53a34539382a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -230,7 +230,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * loopback/bind mount (@flags & MS_BIND), @dev_name identifies the * pathname of the object being mounted. * @dev_name contains the name for object being mounted. - * @nd contains the nameidata structure for mount point object. + * @path contains the path for mount point object. * @type contains the filesystem type. * @flags contains the mount flags. * @data contains the filesystem-specific data. @@ -249,7 +249,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Check permission before the device with superblock @mnt->sb is mounted * on the mount point named by @nd. * @mnt contains the vfsmount for device being mounted. - * @nd contains the nameidata object for the mount point. + * @path contains the path for the mount point. * Return 0 if permission is granted. * @sb_umount: * Check permission before the @mnt file system is unmounted. @@ -278,16 +278,16 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * This hook is called any time a mount is successfully grafetd to * the tree. * @mnt contains the mounted filesystem. - * @mountpoint_nd contains the nameidata structure for the mount point. + * @mountpoint contains the path for the mount point. * @sb_pivotroot: * Check permission before pivoting the root filesystem. - * @old_nd contains the nameidata structure for the new location of the current root (put_old). - * @new_nd contains the nameidata structure for the new root (new_root). + * @old_path contains the path for the new location of the current root (put_old). + * @new_path contains the path for the new root (new_root). * Return 0 if permission is granted. * @sb_post_pivotroot: * Update module state after a successful pivot. - * @old_nd contains the nameidata structure for the old root. - * @new_nd contains the nameidata structure for the new root. + * @old_path contains the path for the old root. + * @new_path contains the path for the new root. * @sb_get_mnt_opts: * Get the security relevant mount options used for a superblock * @sb the superblock to get security mount options from @@ -1315,20 +1315,20 @@ struct security_operations { int (*sb_copy_data)(char *orig, char *copy); int (*sb_kern_mount) (struct super_block *sb, void *data); int (*sb_statfs) (struct dentry *dentry); - int (*sb_mount) (char *dev_name, struct nameidata * nd, + int (*sb_mount) (char *dev_name, struct path *path, char *type, unsigned long flags, void *data); - int (*sb_check_sb) (struct vfsmount * mnt, struct nameidata * nd); + int (*sb_check_sb) (struct vfsmount * mnt, struct path *path); int (*sb_umount) (struct vfsmount * mnt, int flags); void (*sb_umount_close) (struct vfsmount * mnt); void (*sb_umount_busy) (struct vfsmount * mnt); void (*sb_post_remount) (struct vfsmount * mnt, unsigned long flags, void *data); void (*sb_post_addmount) (struct vfsmount * mnt, - struct nameidata * mountpoint_nd); - int (*sb_pivotroot) (struct nameidata * old_nd, - struct nameidata * new_nd); - void (*sb_post_pivotroot) (struct nameidata * old_nd, - struct nameidata * new_nd); + struct path *mountpoint); + int (*sb_pivotroot) (struct path *old_path, + struct path *new_path); + void (*sb_post_pivotroot) (struct path *old_path, + struct path *new_path); int (*sb_get_mnt_opts) (const struct super_block *sb, struct security_mnt_opts *opts); int (*sb_set_mnt_opts) (struct super_block *sb, @@ -1593,16 +1593,16 @@ void security_sb_free(struct super_block *sb); int security_sb_copy_data(char *orig, char *copy); int security_sb_kern_mount(struct super_block *sb, void *data); int security_sb_statfs(struct dentry *dentry); -int security_sb_mount(char *dev_name, struct nameidata *nd, +int security_sb_mount(char *dev_name, struct path *path, char *type, unsigned long flags, void *data); -int security_sb_check_sb(struct vfsmount *mnt, struct nameidata *nd); +int security_sb_check_sb(struct vfsmount *mnt, struct path *path); int security_sb_umount(struct vfsmount *mnt, int flags); void security_sb_umount_close(struct vfsmount *mnt); void security_sb_umount_busy(struct vfsmount *mnt); void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *data); -void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata *mountpoint_nd); -int security_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd); -void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd); +void security_sb_post_addmount(struct vfsmount *mnt, struct path *mountpoint); +int security_sb_pivotroot(struct path *old_path, struct path *new_path); +void security_sb_post_pivotroot(struct path *old_path, struct path *new_path); int security_sb_get_mnt_opts(const struct super_block *sb, struct security_mnt_opts *opts); int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts); @@ -1872,7 +1872,7 @@ static inline int security_sb_statfs (struct dentry *dentry) return 0; } -static inline int security_sb_mount (char *dev_name, struct nameidata *nd, +static inline int security_sb_mount (char *dev_name, struct path *path, char *type, unsigned long flags, void *data) { @@ -1880,7 +1880,7 @@ static inline int security_sb_mount (char *dev_name, struct nameidata *nd, } static inline int security_sb_check_sb (struct vfsmount *mnt, - struct nameidata *nd) + struct path *path) { return 0; } @@ -1901,17 +1901,17 @@ static inline void security_sb_post_remount (struct vfsmount *mnt, { } static inline void security_sb_post_addmount (struct vfsmount *mnt, - struct nameidata *mountpoint_nd) + struct path *mountpoint) { } -static inline int security_sb_pivotroot (struct nameidata *old_nd, - struct nameidata *new_nd) +static inline int security_sb_pivotroot (struct path *old_path, + struct path *new_path) { return 0; } -static inline void security_sb_post_pivotroot (struct nameidata *old_nd, - struct nameidata *new_nd) +static inline void security_sb_post_pivotroot (struct path *old_path, + struct path *new_path) { } static inline int security_sb_get_mnt_opts(const struct super_block *sb, struct security_mnt_opts *opts) diff --git a/security/dummy.c b/security/dummy.c index 98d5f969cdc8..b0232bbf427b 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -196,13 +196,13 @@ static int dummy_sb_statfs (struct dentry *dentry) return 0; } -static int dummy_sb_mount (char *dev_name, struct nameidata *nd, char *type, +static int dummy_sb_mount (char *dev_name, struct path *path, char *type, unsigned long flags, void *data) { return 0; } -static int dummy_sb_check_sb (struct vfsmount *mnt, struct nameidata *nd) +static int dummy_sb_check_sb (struct vfsmount *mnt, struct path *path) { return 0; } @@ -229,17 +229,17 @@ static void dummy_sb_post_remount (struct vfsmount *mnt, unsigned long flags, } -static void dummy_sb_post_addmount (struct vfsmount *mnt, struct nameidata *nd) +static void dummy_sb_post_addmount (struct vfsmount *mnt, struct path *path) { return; } -static int dummy_sb_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +static int dummy_sb_pivotroot (struct path *old_path, struct path *new_path) { return 0; } -static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +static void dummy_sb_post_pivotroot (struct path *old_path, struct path *new_path) { return; } diff --git a/security/security.c b/security/security.c index 2e250c7028eb..8a285c7b9962 100644 --- a/security/security.c +++ b/security/security.c @@ -296,15 +296,15 @@ int security_sb_statfs(struct dentry *dentry) return security_ops->sb_statfs(dentry); } -int security_sb_mount(char *dev_name, struct nameidata *nd, +int security_sb_mount(char *dev_name, struct path *path, char *type, unsigned long flags, void *data) { - return security_ops->sb_mount(dev_name, nd, type, flags, data); + return security_ops->sb_mount(dev_name, path, type, flags, data); } -int security_sb_check_sb(struct vfsmount *mnt, struct nameidata *nd) +int security_sb_check_sb(struct vfsmount *mnt, struct path *path) { - return security_ops->sb_check_sb(mnt, nd); + return security_ops->sb_check_sb(mnt, path); } int security_sb_umount(struct vfsmount *mnt, int flags) @@ -327,19 +327,19 @@ void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *d security_ops->sb_post_remount(mnt, flags, data); } -void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata *mountpoint_nd) +void security_sb_post_addmount(struct vfsmount *mnt, struct path *mountpoint) { - security_ops->sb_post_addmount(mnt, mountpoint_nd); + security_ops->sb_post_addmount(mnt, mountpoint); } -int security_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd) +int security_sb_pivotroot(struct path *old_path, struct path *new_path) { - return security_ops->sb_pivotroot(old_nd, new_nd); + return security_ops->sb_pivotroot(old_path, new_path); } -void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd) +void security_sb_post_pivotroot(struct path *old_path, struct path *new_path) { - security_ops->sb_post_pivotroot(old_nd, new_nd); + security_ops->sb_post_pivotroot(old_path, new_path); } int security_sb_get_mnt_opts(const struct super_block *sb, diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 1bf2543ea942..38fbb168dbed 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2392,22 +2392,22 @@ static int selinux_sb_statfs(struct dentry *dentry) } static int selinux_mount(char *dev_name, - struct nameidata *nd, + struct path *path, char *type, unsigned long flags, void *data) { int rc; - rc = secondary_ops->sb_mount(dev_name, nd, type, flags, data); + rc = secondary_ops->sb_mount(dev_name, path, type, flags, data); if (rc) return rc; if (flags & MS_REMOUNT) - return superblock_has_perm(current, nd->path.mnt->mnt_sb, + return superblock_has_perm(current, path->mnt->mnt_sb, FILESYSTEM__REMOUNT, NULL); else - return dentry_has_perm(current, nd->path.mnt, nd->path.dentry, + return dentry_has_perm(current, path->mnt, path->dentry, FILE__MOUNTON); } diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 93f5b0ce662a..4215971434e6 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -315,10 +315,10 @@ static int smack_sb_statfs(struct dentry *dentry) * Returns 0 if current can write the floor of the filesystem * being mounted on, an error code otherwise. */ -static int smack_sb_mount(char *dev_name, struct nameidata *nd, +static int smack_sb_mount(char *dev_name, struct path *path, char *type, unsigned long flags, void *data) { - struct superblock_smack *sbp = nd->path.mnt->mnt_sb->s_security; + struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; return smk_curacc(sbp->smk_floor, MAY_WRITE); } -- cgit v1.2.3 From 8c3ee42e80ccead805806b3cb50b9855ceb957a2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 22 Mar 2008 18:00:39 -0400 Subject: [PATCH] get rid of more nameidata passing in namespace.c Further reduction of stack footprint (sys_pivot_root()); lose useless BKL in there, while we are at it. Signed-off-by: Al Viro --- fs/namespace.c | 53 +++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 87d2d82010bb..1bf302d0478b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1205,32 +1205,32 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, return 0; } -static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) +static int graft_tree(struct vfsmount *mnt, struct path *path) { int err; if (mnt->mnt_sb->s_flags & MS_NOUSER) return -EINVAL; - if (S_ISDIR(nd->path.dentry->d_inode->i_mode) != + if (S_ISDIR(path->dentry->d_inode->i_mode) != S_ISDIR(mnt->mnt_root->d_inode->i_mode)) return -ENOTDIR; err = -ENOENT; - mutex_lock(&nd->path.dentry->d_inode->i_mutex); - if (IS_DEADDIR(nd->path.dentry->d_inode)) + mutex_lock(&path->dentry->d_inode->i_mutex); + if (IS_DEADDIR(path->dentry->d_inode)) goto out_unlock; - err = security_sb_check_sb(mnt, &nd->path); + err = security_sb_check_sb(mnt, path); if (err) goto out_unlock; err = -ENOENT; - if (IS_ROOT(nd->path.dentry) || !d_unhashed(nd->path.dentry)) - err = attach_recursive_mnt(mnt, &nd->path, NULL); + if (IS_ROOT(path->dentry) || !d_unhashed(path->dentry)) + err = attach_recursive_mnt(mnt, path, NULL); out_unlock: - mutex_unlock(&nd->path.dentry->d_inode->i_mutex); + mutex_unlock(&path->dentry->d_inode->i_mutex); if (!err) - security_sb_post_addmount(mnt, &nd->path); + security_sb_post_addmount(mnt, path); return err; } @@ -1294,7 +1294,7 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name, if (!mnt) goto out; - err = graft_tree(mnt, nd); + err = graft_tree(mnt, &nd->path); if (err) { LIST_HEAD(umount_list); spin_lock(&vfsmount_lock); @@ -1501,7 +1501,7 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, goto unlock; newmnt->mnt_flags = mnt_flags; - if ((err = graft_tree(newmnt, nd))) + if ((err = graft_tree(newmnt, &nd->path))) goto unlock; if (fslist) /* add to the specified expiration list */ @@ -1987,15 +1987,13 @@ asmlinkage long sys_pivot_root(const char __user * new_root, const char __user * put_old) { struct vfsmount *tmp; - struct nameidata new_nd, old_nd, user_nd; - struct path parent_path, root_parent; + struct nameidata new_nd, old_nd; + struct path parent_path, root_parent, root; int error; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - lock_kernel(); - error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &new_nd); if (error) @@ -2015,7 +2013,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root, } read_lock(¤t->fs->lock); - user_nd.path = current->fs->root; + root = current->fs->root; path_get(¤t->fs->root); read_unlock(¤t->fs->lock); down_write(&namespace_sem); @@ -2023,9 +2021,9 @@ asmlinkage long sys_pivot_root(const char __user * new_root, error = -EINVAL; if (IS_MNT_SHARED(old_nd.path.mnt) || IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || - IS_MNT_SHARED(user_nd.path.mnt->mnt_parent)) + IS_MNT_SHARED(root.mnt->mnt_parent)) goto out2; - if (!check_mnt(user_nd.path.mnt)) + if (!check_mnt(root.mnt)) goto out2; error = -ENOENT; if (IS_DEADDIR(new_nd.path.dentry->d_inode)) @@ -2035,13 +2033,13 @@ asmlinkage long sys_pivot_root(const char __user * new_root, if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) goto out2; error = -EBUSY; - if (new_nd.path.mnt == user_nd.path.mnt || - old_nd.path.mnt == user_nd.path.mnt) + if (new_nd.path.mnt == root.mnt || + old_nd.path.mnt == root.mnt) goto out2; /* loop, on the same file system */ error = -EINVAL; - if (user_nd.path.mnt->mnt_root != user_nd.path.dentry) + if (root.mnt->mnt_root != root.dentry) goto out2; /* not a mountpoint */ - if (user_nd.path.mnt->mnt_parent == user_nd.path.mnt) + if (root.mnt->mnt_parent == root.mnt) goto out2; /* not attached */ if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) goto out2; /* not a mountpoint */ @@ -2063,27 +2061,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root, } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) goto out3; detach_mnt(new_nd.path.mnt, &parent_path); - detach_mnt(user_nd.path.mnt, &root_parent); + detach_mnt(root.mnt, &root_parent); /* mount old root on put_old */ - attach_mnt(user_nd.path.mnt, &old_nd.path); + attach_mnt(root.mnt, &old_nd.path); /* mount new_root on / */ attach_mnt(new_nd.path.mnt, &root_parent); touch_mnt_namespace(current->nsproxy->mnt_ns); spin_unlock(&vfsmount_lock); - chroot_fs_refs(&user_nd.path, &new_nd.path); - security_sb_post_pivotroot(&user_nd.path, &new_nd.path); + chroot_fs_refs(&root, &new_nd.path); + security_sb_post_pivotroot(&root, &new_nd.path); error = 0; path_put(&root_parent); path_put(&parent_path); out2: mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); up_write(&namespace_sem); - path_put(&user_nd.path); + path_put(&root); path_put(&old_nd.path); out1: path_put(&new_nd.path); out0: - unlock_kernel(); return error; out3: spin_unlock(&vfsmount_lock); -- cgit v1.2.3 From 4e1b36fb485dd81b0818ef1bc8fb5c0f2923a283 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 24 Mar 2008 00:16:03 -0400 Subject: [PATCH] umount_tree() will unhash everything itself Signed-off-by: Al Viro --- fs/pnode.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/pnode.c b/fs/pnode.c index a9e0d6fadbcd..f968e35d9785 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -212,8 +212,7 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, out: spin_lock(&vfsmount_lock); while (!list_empty(&tmp_list)) { - child = list_entry(tmp_list.next, struct vfsmount, mnt_hash); - list_del_init(&child->mnt_hash); + child = list_first_entry(&tmp_list, struct vfsmount, mnt_hash); umount_tree(child, 0, &umount_list); } spin_unlock(&vfsmount_lock); -- cgit v1.2.3 From 521b5d0c40386f4a9805cdec7bd979fc96a86aeb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 28 Mar 2008 00:46:41 -0400 Subject: [PATCH] teach seq_file to discard entries Allow ->show() return SEQ_SKIP; that will discard all output from that element and move on. Signed-off-by: Al Viro --- fs/pnode.h | 1 + fs/seq_file.c | 16 ++++++++++++---- include/linux/seq_file.h | 2 ++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/fs/pnode.h b/fs/pnode.h index f249be2fee7a..973c3f825e7d 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -35,4 +35,5 @@ int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *, struct list_head *); int propagate_umount(struct list_head *); int propagate_mount_busy(struct vfsmount *, int); +void mnt_release_group_id(struct vfsmount *); #endif /* _LINUX_PNODE_H */ diff --git a/fs/seq_file.c b/fs/seq_file.c index 853770274f20..bf2bcfd4bcfb 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -25,6 +25,7 @@ * into the buffer. In case of error ->start() and ->next() return * ERR_PTR(error). In the end of sequence they return %NULL. ->show() * returns 0 in case of success and negative number in case of error. + * Returning SEQ_SKIP means "discard this element and move on". */ int seq_open(struct file *file, const struct seq_operations *op) { @@ -114,8 +115,10 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) if (!p || IS_ERR(p)) break; err = m->op->show(m, p); - if (err) + if (err < 0) break; + if (unlikely(err)) + m->count = 0; if (m->count < m->size) goto Fill; m->op->stop(m, p); @@ -140,9 +143,10 @@ Fill: break; } err = m->op->show(m, p); - if (err || m->count == m->size) { + if (m->count == m->size || err) { m->count = offs; - break; + if (likely(err <= 0)) + break; } pos = next; } @@ -199,8 +203,12 @@ static int traverse(struct seq_file *m, loff_t offset) if (IS_ERR(p)) break; error = m->op->show(m, p); - if (error) + if (error < 0) break; + if (unlikely(error)) { + error = 0; + m->count = 0; + } if (m->count == m->size) goto Eoverflow; if (pos + m->count > offset) { diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 1da1e6208a0a..d65796dc26d9 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -30,6 +30,8 @@ struct seq_operations { int (*show) (struct seq_file *m, void *v); }; +#define SEQ_SKIP 1 + int seq_open(struct file *, const struct seq_operations *); ssize_t seq_read(struct file *, char __user *, size_t, loff_t *); loff_t seq_lseek(struct file *, loff_t, int); -- cgit v1.2.3 From ed1524371716466e9c762808b02601d0d0276a92 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 22 Apr 2008 19:51:27 -0400 Subject: [PATCH] double-free of inode on alloc_file() failure exit in create_write_pipe() Duh... Fortunately, the bug is quite recent (post-2.6.25) and, embarrassingly, mine ;-/ Signed-off-by: Al Viro --- fs/pipe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/pipe.c b/fs/pipe.c index 8be381bbcb54..f73492b6817e 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -988,7 +988,10 @@ struct file *create_write_pipe(void) return f; err_dentry: + free_pipe_info(inode); dput(dentry); + return ERR_PTR(err); + err_inode: free_pipe_info(inode); iput(inode); -- cgit v1.2.3 From 9b4f526cdc0f95f635607dfba6ac788b3deca188 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 22 Apr 2008 01:32:44 -0400 Subject: [PATCH] proc_readfd_common() race fix Since we drop the rcu_read_lock inside the loop, we can't assume that files->fdt will remain unchanged (and not freed) between iterations. Signed-off-by: Al Viro --- fs/proc/base.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 81d7d145292a..7313c62e3e9d 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1626,7 +1626,6 @@ static int proc_readfd_common(struct file * filp, void * dirent, unsigned int fd, ino; int retval; struct files_struct * files; - struct fdtable *fdt; retval = -ENOENT; if (!p) @@ -1649,9 +1648,8 @@ static int proc_readfd_common(struct file * filp, void * dirent, if (!files) goto out; rcu_read_lock(); - fdt = files_fdtable(files); for (fd = filp->f_pos-2; - fd < fdt->max_fds; + fd < files_fdtable(files)->max_fds; fd++, filp->f_pos++) { char name[PROC_NUMBUF]; int len; -- cgit v1.2.3 From 1ec7f1ddbe5ba49f7b10c3b129d6d5c90c43526c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 22 Apr 2008 05:35:42 -0400 Subject: [PATCH] get rid of __exit_files(), __exit_fs() and __put_fs_struct() The only reason to have separated __...() for those was to keep them inlined for local users in exit.c. Since Alexey removed the inline on those, there's no reason whatsoever to keep them around; just collapse with normal variants. Signed-off-by: Al Viro --- kernel/exit.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/kernel/exit.c b/kernel/exit.c index 073005b1cfb2..cece89f80ab4 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -521,7 +521,7 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files) } EXPORT_SYMBOL(reset_files_struct); -static void __exit_files(struct task_struct *tsk) +void exit_files(struct task_struct *tsk) { struct files_struct * files = tsk->files; @@ -533,12 +533,7 @@ static void __exit_files(struct task_struct *tsk) } } -void exit_files(struct task_struct *tsk) -{ - __exit_files(tsk); -} - -static void __put_fs_struct(struct fs_struct *fs) +void put_fs_struct(struct fs_struct *fs) { /* No need to hold fs->lock if we are killing it */ if (atomic_dec_and_test(&fs->count)) { @@ -550,12 +545,7 @@ static void __put_fs_struct(struct fs_struct *fs) } } -void put_fs_struct(struct fs_struct *fs) -{ - __put_fs_struct(fs); -} - -static void __exit_fs(struct task_struct *tsk) +void exit_fs(struct task_struct *tsk) { struct fs_struct * fs = tsk->fs; @@ -563,15 +553,10 @@ static void __exit_fs(struct task_struct *tsk) task_lock(tsk); tsk->fs = NULL; task_unlock(tsk); - __put_fs_struct(fs); + put_fs_struct(fs); } } -void exit_fs(struct task_struct *tsk) -{ - __exit_fs(tsk); -} - EXPORT_SYMBOL_GPL(exit_fs); /* @@ -967,8 +952,8 @@ NORET_TYPE void do_exit(long code) if (group_dead) acct_process(); exit_sem(tsk); - __exit_files(tsk); - __exit_fs(tsk); + exit_files(tsk); + exit_fs(tsk); check_stack_usage(); exit_thread(); cgroup_exit(tsk, 1); -- cgit v1.2.3