summaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-10-23 10:22:40 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-23 10:22:40 -0700
commit5ed487bc2c44ca4e9668ef9cb54c830e2a9fac47 (patch)
treeaf19ed28db83e8f52690872ac99336da1cf2fd3b /fs/namespace.c
parent5b34653963de7a6d0d8c783527457d68fddc60fb (diff)
parentfd217f4d70172c526478f2bc76859e909fdfa674 (diff)
downloadlinux-5ed487bc2c44ca4e9668ef9cb54c830e2a9fac47.tar.bz2
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (46 commits) [PATCH] fs: add a sanity check in d_free [PATCH] i_version: remount support [patch] vfs: make security_inode_setattr() calling consistent [patch 1/3] FS_MBCACHE: don't needlessly make it built-in [PATCH] move executable checking into ->permission() [PATCH] fs/dcache.c: update comment of d_validate() [RFC PATCH] touch_mnt_namespace when the mount flags change [PATCH] reiserfs: add missing llseek method [PATCH] fix ->llseek for more directories [PATCH vfs-2.6 6/6] vfs: add LOOKUP_RENAME_TARGET intent [PATCH vfs-2.6 5/6] vfs: remove LOOKUP_PARENT from non LOOKUP_PARENT lookup [PATCH vfs-2.6 4/6] vfs: remove unnecessary fsnotify_d_instantiate() [PATCH vfs-2.6 3/6] vfs: add __d_instantiate() helper [PATCH vfs-2.6 2/6] vfs: add d_ancestor() [PATCH vfs-2.6 1/6] vfs: replace parent == dentry->d_parent by IS_ROOT() [PATCH] get rid of on-stack dentry in udf [PATCH 2/2] anondev: switch to IDA [PATCH 1/2] anondev: init IDR statically [JFFS2] Use d_splice_alias() not d_add() in jffs2_lookup() [PATCH] Optimise NFS readdir hack slightly. ...
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c133
1 files changed, 65 insertions, 68 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 6e283c93b50d..cce46702d33c 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1167,19 +1167,19 @@ asmlinkage long sys_oldumount(char __user * name)
#endif
-static int mount_is_safe(struct nameidata *nd)
+static int mount_is_safe(struct path *path)
{
if (capable(CAP_SYS_ADMIN))
return 0;
return -EPERM;
#ifdef notyet
- if (S_ISLNK(nd->path.dentry->d_inode->i_mode))
+ if (S_ISLNK(path->dentry->d_inode->i_mode))
return -EPERM;
- if (nd->path.dentry->d_inode->i_mode & S_ISVTX) {
- if (current->uid != nd->path.dentry->d_inode->i_uid)
+ if (path->dentry->d_inode->i_mode & S_ISVTX) {
+ if (current->uid != path->dentry->d_inode->i_uid)
return -EPERM;
}
- if (vfs_permission(nd, MAY_WRITE))
+ if (inode_permission(path->dentry->d_inode, MAY_WRITE))
return -EPERM;
return 0;
#endif
@@ -1425,11 +1425,10 @@ out_unlock:
/*
* recursively change the type of the mountpoint.
- * noinline this do_mount helper to save do_mount stack space.
*/
-static noinline int do_change_type(struct nameidata *nd, int flag)
+static int do_change_type(struct path *path, int flag)
{
- struct vfsmount *m, *mnt = nd->path.mnt;
+ struct vfsmount *m, *mnt = path->mnt;
int recurse = flag & MS_REC;
int type = flag & ~MS_REC;
int err = 0;
@@ -1437,7 +1436,7 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (nd->path.dentry != nd->path.mnt->mnt_root)
+ if (path->dentry != path->mnt->mnt_root)
return -EINVAL;
down_write(&namespace_sem);
@@ -1459,40 +1458,39 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
/*
* do loopback mount.
- * noinline this do_mount helper to save do_mount stack space.
*/
-static noinline int do_loopback(struct nameidata *nd, char *old_name,
+static int do_loopback(struct path *path, char *old_name,
int recurse)
{
- struct nameidata old_nd;
+ struct path old_path;
struct vfsmount *mnt = NULL;
- int err = mount_is_safe(nd);
+ int err = mount_is_safe(path);
if (err)
return err;
if (!old_name || !*old_name)
return -EINVAL;
- err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd);
+ err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
if (err)
return err;
down_write(&namespace_sem);
err = -EINVAL;
- if (IS_MNT_UNBINDABLE(old_nd.path.mnt))
+ if (IS_MNT_UNBINDABLE(old_path.mnt))
goto out;
- if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt))
+ if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
goto out;
err = -ENOMEM;
if (recurse)
- mnt = copy_tree(old_nd.path.mnt, old_nd.path.dentry, 0);
+ mnt = copy_tree(old_path.mnt, old_path.dentry, 0);
else
- mnt = clone_mnt(old_nd.path.mnt, old_nd.path.dentry, 0);
+ mnt = clone_mnt(old_path.mnt, old_path.dentry, 0);
if (!mnt)
goto out;
- err = graft_tree(mnt, &nd->path);
+ err = graft_tree(mnt, path);
if (err) {
LIST_HEAD(umount_list);
spin_lock(&vfsmount_lock);
@@ -1503,7 +1501,7 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name,
out:
up_write(&namespace_sem);
- path_put(&old_nd.path);
+ path_put(&old_path);
return err;
}
@@ -1528,33 +1526,37 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
* change filesystem flags. dir should be a physical root of filesystem.
* If you've mounted a non-root directory somewhere and want to do remount
* on it - tough luck.
- * noinline this do_mount helper to save do_mount stack space.
*/
-static noinline int do_remount(struct nameidata *nd, int flags, int mnt_flags,
+static int do_remount(struct path *path, int flags, int mnt_flags,
void *data)
{
int err;
- struct super_block *sb = nd->path.mnt->mnt_sb;
+ struct super_block *sb = path->mnt->mnt_sb;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (!check_mnt(nd->path.mnt))
+ if (!check_mnt(path->mnt))
return -EINVAL;
- if (nd->path.dentry != nd->path.mnt->mnt_root)
+ if (path->dentry != path->mnt->mnt_root)
return -EINVAL;
down_write(&sb->s_umount);
if (flags & MS_BIND)
- err = change_mount_flags(nd->path.mnt, flags);
+ err = change_mount_flags(path->mnt, flags);
else
err = do_remount_sb(sb, flags, data, 0);
if (!err)
- nd->path.mnt->mnt_flags = mnt_flags;
+ path->mnt->mnt_flags = mnt_flags;
up_write(&sb->s_umount);
- if (!err)
- security_sb_post_remount(nd->path.mnt, flags, data);
+ if (!err) {
+ security_sb_post_remount(path->mnt, flags, data);
+
+ spin_lock(&vfsmount_lock);
+ touch_mnt_namespace(path->mnt->mnt_ns);
+ spin_unlock(&vfsmount_lock);
+ }
return err;
}
@@ -1568,90 +1570,85 @@ static inline int tree_contains_unbindable(struct vfsmount *mnt)
return 0;
}
-/*
- * noinline this do_mount helper to save do_mount stack space.
- */
-static noinline int do_move_mount(struct nameidata *nd, char *old_name)
+static int do_move_mount(struct path *path, char *old_name)
{
- struct nameidata old_nd;
- struct path parent_path;
+ struct path old_path, parent_path;
struct vfsmount *p;
int err = 0;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (!old_name || !*old_name)
return -EINVAL;
- err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd);
+ err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
if (err)
return err;
down_write(&namespace_sem);
- while (d_mountpoint(nd->path.dentry) &&
- follow_down(&nd->path.mnt, &nd->path.dentry))
+ while (d_mountpoint(path->dentry) &&
+ follow_down(&path->mnt, &path->dentry))
;
err = -EINVAL;
- if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt))
+ if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
goto out;
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 out1;
- if (!IS_ROOT(nd->path.dentry) && d_unhashed(nd->path.dentry))
+ if (!IS_ROOT(path->dentry) && d_unhashed(path->dentry))
goto out1;
err = -EINVAL;
- if (old_nd.path.dentry != old_nd.path.mnt->mnt_root)
+ if (old_path.dentry != old_path.mnt->mnt_root)
goto out1;
- if (old_nd.path.mnt == old_nd.path.mnt->mnt_parent)
+ if (old_path.mnt == old_path.mnt->mnt_parent)
goto out1;
- if (S_ISDIR(nd->path.dentry->d_inode->i_mode) !=
- S_ISDIR(old_nd.path.dentry->d_inode->i_mode))
+ if (S_ISDIR(path->dentry->d_inode->i_mode) !=
+ S_ISDIR(old_path.dentry->d_inode->i_mode))
goto out1;
/*
* Don't move a mount residing in a shared parent.
*/
- if (old_nd.path.mnt->mnt_parent &&
- IS_MNT_SHARED(old_nd.path.mnt->mnt_parent))
+ if (old_path.mnt->mnt_parent &&
+ IS_MNT_SHARED(old_path.mnt->mnt_parent))
goto out1;
/*
* Don't move a mount tree containing unbindable mounts to a destination
* mount which is shared.
*/
- if (IS_MNT_SHARED(nd->path.mnt) &&
- tree_contains_unbindable(old_nd.path.mnt))
+ if (IS_MNT_SHARED(path->mnt) &&
+ tree_contains_unbindable(old_path.mnt))
goto out1;
err = -ELOOP;
- for (p = nd->path.mnt; p->mnt_parent != p; p = p->mnt_parent)
- if (p == old_nd.path.mnt)
+ for (p = path->mnt; p->mnt_parent != p; p = p->mnt_parent)
+ if (p == old_path.mnt)
goto out1;
- err = attach_recursive_mnt(old_nd.path.mnt, &nd->path, &parent_path);
+ err = attach_recursive_mnt(old_path.mnt, path, &parent_path);
if (err)
goto out1;
/* if the mount is moved, it should no longer be expire
* automatically */
- list_del_init(&old_nd.path.mnt->mnt_expire);
+ list_del_init(&old_path.mnt->mnt_expire);
out1:
- mutex_unlock(&nd->path.dentry->d_inode->i_mutex);
+ mutex_unlock(&path->dentry->d_inode->i_mutex);
out:
up_write(&namespace_sem);
if (!err)
path_put(&parent_path);
- path_put(&old_nd.path);
+ path_put(&old_path);
return err;
}
/*
* create a new mount for userspace and request it to be added into the
* namespace's tree
- * noinline this do_mount helper to save do_mount stack space.
*/
-static noinline int do_new_mount(struct nameidata *nd, char *type, int flags,
+static int do_new_mount(struct path *path, char *type, int flags,
int mnt_flags, char *name, void *data)
{
struct vfsmount *mnt;
@@ -1667,7 +1664,7 @@ static noinline int do_new_mount(struct nameidata *nd, char *type, int flags,
if (IS_ERR(mnt))
return PTR_ERR(mnt);
- return do_add_mount(mnt, &nd->path, mnt_flags, NULL);
+ return do_add_mount(mnt, path, mnt_flags, NULL);
}
/*
@@ -1902,7 +1899,7 @@ int copy_mount_options(const void __user * data, unsigned long *where)
long do_mount(char *dev_name, char *dir_name, char *type_page,
unsigned long flags, void *data_page)
{
- struct nameidata nd;
+ struct path path;
int retval = 0;
int mnt_flags = 0;
@@ -1940,29 +1937,29 @@ long do_mount(char *dev_name, char *dir_name, char *type_page,
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT);
/* ... and get the mountpoint */
- retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd);
+ retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
if (retval)
return retval;
- retval = security_sb_mount(dev_name, &nd.path,
+ retval = security_sb_mount(dev_name, &path,
type_page, flags, data_page);
if (retval)
goto dput_out;
if (flags & MS_REMOUNT)
- retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
+ retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
data_page);
else if (flags & MS_BIND)
- retval = do_loopback(&nd, dev_name, flags & MS_REC);
+ retval = do_loopback(&path, dev_name, flags & MS_REC);
else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
- retval = do_change_type(&nd, flags);
+ retval = do_change_type(&path, flags);
else if (flags & MS_MOVE)
- retval = do_move_mount(&nd, dev_name);
+ retval = do_move_mount(&path, dev_name);
else
- retval = do_new_mount(&nd, type_page, flags, mnt_flags,
+ retval = do_new_mount(&path, type_page, flags, mnt_flags,
dev_name, data_page);
dput_out:
- path_put(&nd.path);
+ path_put(&path);
return retval;
}