diff --git a/fs/namespace.c b/fs/namespace.c index fa0f30d862c689b71d2c1e02ef7279f1b9891427..211455e2cd174912c22b8c302b7889dd387dde4e 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -687,17 +687,17 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void } EXPORT_SYMBOL_GPL(vfs_kern_mount); -static struct mount *clone_mnt(struct vfsmount *old, struct dentry *root, +static struct mount *clone_mnt(struct mount *old, struct dentry *root, int flag) { - struct super_block *sb = old->mnt_sb; - struct mount *mnt = alloc_vfsmnt(old->mnt_devname); + struct super_block *sb = old->mnt.mnt_sb; + struct mount *mnt = alloc_vfsmnt(old->mnt.mnt_devname); if (mnt) { if (flag & (CL_SLAVE | CL_PRIVATE)) mnt->mnt.mnt_group_id = 0; /* not a peer of original */ else - mnt->mnt.mnt_group_id = old->mnt_group_id; + mnt->mnt.mnt_group_id = old->mnt.mnt_group_id; if ((flag & CL_MAKE_SHARED) && !mnt->mnt.mnt_group_id) { int err = mnt_alloc_group_id(mnt); @@ -705,7 +705,7 @@ static struct mount *clone_mnt(struct vfsmount *old, struct dentry *root, goto out_free; } - mnt->mnt.mnt_flags = old->mnt_flags & ~MNT_WRITE_HOLD; + mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; atomic_inc(&sb->s_active); mnt->mnt.mnt_sb = sb; mnt->mnt.mnt_root = dget(root); @@ -713,15 +713,15 @@ static struct mount *clone_mnt(struct vfsmount *old, struct dentry *root, mnt->mnt.mnt_parent = &mnt->mnt; if (flag & CL_SLAVE) { - list_add(&mnt->mnt.mnt_slave, &old->mnt_slave_list); - mnt->mnt.mnt_master = old; + list_add(&mnt->mnt.mnt_slave, &old->mnt.mnt_slave_list); + mnt->mnt.mnt_master = &old->mnt; CLEAR_MNT_SHARED(&mnt->mnt); } else if (!(flag & CL_PRIVATE)) { - if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old)) - list_add(&mnt->mnt.mnt_share, &old->mnt_share); - if (IS_MNT_SLAVE(old)) - list_add(&mnt->mnt.mnt_slave, &old->mnt_slave); - mnt->mnt.mnt_master = old->mnt_master; + if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(&old->mnt)) + list_add(&mnt->mnt.mnt_share, &old->mnt.mnt_share); + if (IS_MNT_SLAVE(&old->mnt)) + list_add(&mnt->mnt.mnt_slave, &old->mnt.mnt_slave); + mnt->mnt.mnt_master = old->mnt.mnt_master; } if (flag & CL_MAKE_SHARED) set_mnt_shared(mnt); @@ -729,8 +729,8 @@ static struct mount *clone_mnt(struct vfsmount *old, struct dentry *root, /* stick the duplicate mount on the same expiry list * as the original if that was on one */ if (flag & CL_EXPIRE) { - if (!list_empty(&old->mnt_expire)) - list_add(&mnt->mnt.mnt_expire, &old->mnt_expire); + if (!list_empty(&old->mnt.mnt_expire)) + list_add(&mnt->mnt.mnt_expire, &old->mnt.mnt_expire); } } return mnt; @@ -1408,23 +1408,23 @@ static int mount_is_safe(struct path *path) #endif } -struct mount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, +struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, int flag) { - struct mount *res, *q; - struct vfsmount *p, *r; + struct mount *res, *p, *q; + struct vfsmount *r; struct path path; - if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) + if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(&mnt->mnt)) return NULL; res = q = clone_mnt(mnt, dentry, flag); if (!q) goto Enomem; - q->mnt.mnt_mountpoint = mnt->mnt_mountpoint; + q->mnt.mnt_mountpoint = mnt->mnt.mnt_mountpoint; p = mnt; - list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) { + list_for_each_entry(r, &mnt->mnt.mnt_mounts, mnt_child) { struct mount *s; if (!is_subdir(r->mnt_mountpoint, dentry)) continue; @@ -1434,14 +1434,14 @@ struct mount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, s = skip_mnt_tree(s); continue; } - while (p != s->mnt.mnt_parent) { - p = p->mnt_parent; + while (p != real_mount(s->mnt.mnt_parent)) { + p = real_mount(p->mnt.mnt_parent); q = real_mount(q->mnt.mnt_parent); } - p = &s->mnt; + p = s; path.mnt = &q->mnt; - path.dentry = p->mnt_mountpoint; - q = clone_mnt(p, p->mnt_root, flag); + path.dentry = p->mnt.mnt_mountpoint; + q = clone_mnt(p, p->mnt.mnt_root, flag); if (!q) goto Enomem; br_write_lock(vfsmount_lock); @@ -1466,7 +1466,8 @@ struct vfsmount *collect_mounts(struct path *path) { struct mount *tree; down_write(&namespace_sem); - tree = copy_tree(path->mnt, path->dentry, CL_COPY_ALL | CL_PRIVATE); + tree = copy_tree(real_mount(path->mnt), path->dentry, + CL_COPY_ALL | CL_PRIVATE); up_write(&namespace_sem); return tree ? &tree->mnt : NULL; } @@ -1740,7 +1741,7 @@ static int do_loopback(struct path *path, char *old_name, { LIST_HEAD(umount_list); struct path old_path; - struct mount *mnt = NULL; + struct mount *mnt = NULL, *old; int err = mount_is_safe(path); if (err) return err; @@ -1754,6 +1755,8 @@ static int do_loopback(struct path *path, char *old_name, if (err) goto out; + old = real_mount(old_path.mnt); + err = -EINVAL; if (IS_MNT_UNBINDABLE(old_path.mnt)) goto out2; @@ -1763,9 +1766,9 @@ static int do_loopback(struct path *path, char *old_name, err = -ENOMEM; if (recurse) - mnt = copy_tree(old_path.mnt, old_path.dentry, 0); + mnt = copy_tree(old, old_path.dentry, 0); else - mnt = clone_mnt(old_path.mnt, old_path.dentry, 0); + mnt = clone_mnt(old, old_path.dentry, 0); if (!mnt) goto out2; @@ -2394,7 +2397,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, down_write(&namespace_sem); /* First pass: copy the tree topology */ - new = copy_tree(mnt_ns->root, mnt_ns->root->mnt_root, + new = copy_tree(real_mount(mnt_ns->root), mnt_ns->root->mnt_root, CL_COPY_ALL | CL_EXPIRE); if (!new) { up_write(&namespace_sem); diff --git a/fs/pnode.c b/fs/pnode.c index efbe0c0d3f0d5f264baac9e1c0d3b32a680513d0..5d79f38e3e8a3f7f3ee3160bf6d5a7a49d9f4635 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -239,7 +239,7 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, source = get_source(m, prev_dest_mnt, prev_src_mnt, &type); - if (!(child = copy_tree(source, source->mnt_root, type))) { + if (!(child = copy_tree(real_mount(source), source->mnt_root, type))) { ret = -ENOMEM; list_splice(tree_list, tmp_list.prev); goto out; diff --git a/fs/pnode.h b/fs/pnode.h index 3f9ab4f4e0e5bc389e807cdbf73d4bd78b4a2b90..609ec008d5ced891b99cc14437abb675ff5c9095 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -41,7 +41,7 @@ void mnt_set_mountpoint(struct vfsmount *, struct dentry *, struct vfsmount *); void release_mounts(struct list_head *); void umount_tree(struct mount *, int, struct list_head *); -struct mount *copy_tree(struct vfsmount *, struct dentry *, int); +struct mount *copy_tree(struct mount *, struct dentry *, int); bool is_path_reachable(struct vfsmount *, struct dentry *, const struct path *root); #endif /* _LINUX_PNODE_H */