提交 afac7cba 编写于 作者: A Al Viro

vfs: more mnt_parent cleanups

a) mount --move is checking that ->mnt_parent is non-NULL before
looking if that parent happens to be shared; ->mnt_parent is never
NULL and it's not even an misspelled !mnt_has_parent()

b) pivot_root open-codes is_path_reachable(), poorly.

c) so does path_is_under(), while we are at it.
Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
上级 b2dba1af
...@@ -2853,31 +2853,6 @@ int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry) ...@@ -2853,31 +2853,6 @@ int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
return result; return result;
} }
int path_is_under(struct path *path1, struct path *path2)
{
struct vfsmount *mnt = path1->mnt;
struct dentry *dentry = path1->dentry;
int res;
br_read_lock(vfsmount_lock);
if (mnt != path2->mnt) {
for (;;) {
if (!mnt_has_parent(mnt)) {
br_read_unlock(vfsmount_lock);
return 0;
}
if (mnt->mnt_parent == path2->mnt)
break;
mnt = mnt->mnt_parent;
}
dentry = mnt->mnt_mountpoint;
}
res = is_subdir(dentry, path2->dentry);
br_read_unlock(vfsmount_lock);
return res;
}
EXPORT_SYMBOL(path_is_under);
void d_genocide(struct dentry *root) void d_genocide(struct dentry *root)
{ {
struct dentry *this_parent; struct dentry *this_parent;
......
...@@ -1876,8 +1876,7 @@ static int do_move_mount(struct path *path, char *old_name) ...@@ -1876,8 +1876,7 @@ static int do_move_mount(struct path *path, char *old_name)
/* /*
* Don't move a mount residing in a shared parent. * Don't move a mount residing in a shared parent.
*/ */
if (old_path.mnt->mnt_parent && if (IS_MNT_SHARED(old_path.mnt->mnt_parent))
IS_MNT_SHARED(old_path.mnt->mnt_parent))
goto out1; goto out1;
/* /*
* Don't move a mount tree containing unbindable mounts to a destination * Don't move a mount tree containing unbindable mounts to a destination
...@@ -2533,6 +2532,31 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, ...@@ -2533,6 +2532,31 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
return ret; return ret;
} }
/*
* Return true if path is reachable from root
*
* namespace_sem or vfsmount_lock is held
*/
bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry,
const struct path *root)
{
while (mnt != root->mnt && mnt_has_parent(mnt)) {
dentry = mnt->mnt_mountpoint;
mnt = mnt->mnt_parent;
}
return mnt == root->mnt && is_subdir(dentry, root->dentry);
}
int path_is_under(struct path *path1, struct path *path2)
{
int res;
br_read_lock(vfsmount_lock);
res = is_path_reachable(path1->mnt, path1->dentry, path2);
br_read_unlock(vfsmount_lock);
return res;
}
EXPORT_SYMBOL(path_is_under);
/* /*
* pivot_root Semantics: * pivot_root Semantics:
* Moves the root file system of the current process to the directory put_old, * Moves the root file system of the current process to the directory put_old,
...@@ -2561,7 +2585,6 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, ...@@ -2561,7 +2585,6 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
const char __user *, put_old) const char __user *, put_old)
{ {
struct vfsmount *tmp;
struct path new, old, parent_path, root_parent, root; struct path new, old, parent_path, root_parent, root;
int error; int error;
...@@ -2611,18 +2634,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, ...@@ -2611,18 +2634,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
if (!mnt_has_parent(new.mnt)) if (!mnt_has_parent(new.mnt))
goto out4; /* not attached */ goto out4; /* not attached */
/* make sure we can reach put_old from new_root */ /* make sure we can reach put_old from new_root */
tmp = old.mnt; if (!is_path_reachable(old.mnt, old.dentry, &new))
if (tmp != new.mnt) {
for (;;) {
if (!mnt_has_parent(tmp))
goto out4; /* already mounted on put_old */
if (tmp->mnt_parent == new.mnt)
break;
tmp = tmp->mnt_parent;
}
if (!is_subdir(tmp->mnt_mountpoint, new.dentry))
goto out4;
} else if (!is_subdir(old.dentry, new.dentry))
goto out4; goto out4;
br_write_lock(vfsmount_lock); br_write_lock(vfsmount_lock);
detach_mnt(new.mnt, &parent_path); detach_mnt(new.mnt, &parent_path);
......
...@@ -28,21 +28,6 @@ static inline struct vfsmount *next_slave(struct vfsmount *p) ...@@ -28,21 +28,6 @@ static inline struct vfsmount *next_slave(struct vfsmount *p)
return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave);
} }
/*
* Return true if path is reachable from root
*
* namespace_sem is held, and mnt is attached
*/
static bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry,
const struct path *root)
{
while (mnt != root->mnt && mnt_has_parent(mnt)) {
dentry = mnt->mnt_mountpoint;
mnt = mnt->mnt_parent;
}
return mnt == root->mnt && is_subdir(dentry, root->dentry);
}
static struct vfsmount *get_peer_under_root(struct vfsmount *mnt, static struct vfsmount *get_peer_under_root(struct vfsmount *mnt,
struct mnt_namespace *ns, struct mnt_namespace *ns,
const struct path *root) const struct path *root)
......
...@@ -42,4 +42,6 @@ void mnt_set_mountpoint(struct vfsmount *, struct dentry *, ...@@ -42,4 +42,6 @@ void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
void release_mounts(struct list_head *); void release_mounts(struct list_head *);
void umount_tree(struct vfsmount *, int, struct list_head *); void umount_tree(struct vfsmount *, int, struct list_head *);
struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);
bool is_path_reachable(struct vfsmount *, struct dentry *,
const struct path *root);
#endif /* _LINUX_PNODE_H */ #endif /* _LINUX_PNODE_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册