Commit afac7cba authored by Al Viro's avatar 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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent b2dba1af
......@@ -2853,31 +2853,6 @@ int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
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)
{
struct dentry *this_parent;
......
......@@ -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.
*/
if (old_path.mnt->mnt_parent &&
IS_MNT_SHARED(old_path.mnt->mnt_parent))
if (IS_MNT_SHARED(old_path.mnt->mnt_parent))
goto out1;
/*
* 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,
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:
* 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,
SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
const char __user *, put_old)
{
struct vfsmount *tmp;
struct path new, old, parent_path, root_parent, root;
int error;
......@@ -2611,18 +2634,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
if (!mnt_has_parent(new.mnt))
goto out4; /* not attached */
/* make sure we can reach put_old from new_root */
tmp = old.mnt;
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))
if (!is_path_reachable(old.mnt, old.dentry, &new))
goto out4;
br_write_lock(vfsmount_lock);
detach_mnt(new.mnt, &parent_path);
......
......@@ -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 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,
struct mnt_namespace *ns,
const struct path *root)
......
......@@ -42,4 +42,6 @@ void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
void release_mounts(struct list_head *);
void umount_tree(struct vfsmount *, int, struct list_head *);
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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment