mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
copy_tree(): don't link the mounts via mnt_list
The only place that really needs to be adjusted is commit_tree() - there we need to iterate through the copy and we might as well use next_mnt() for that. However, in case when our tree has been slid under something already mounted (propagation to a mountpoint that already has something mounted on it or a 'beneath' move_mount) we need to take care not to walk into the overmounting tree. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
dd5a4e1d64
commit
663206854f
@ -193,7 +193,7 @@ static inline bool mnt_ns_empty(const struct mnt_namespace *ns)
|
|||||||
return RB_EMPTY_ROOT(&ns->mounts);
|
return RB_EMPTY_ROOT(&ns->mounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void move_from_ns(struct mount *mnt, struct list_head *dt_list)
|
static inline void move_from_ns(struct mount *mnt)
|
||||||
{
|
{
|
||||||
struct mnt_namespace *ns = mnt->mnt_ns;
|
struct mnt_namespace *ns = mnt->mnt_ns;
|
||||||
WARN_ON(!mnt_ns_attached(mnt));
|
WARN_ON(!mnt_ns_attached(mnt));
|
||||||
@ -203,7 +203,6 @@ static inline void move_from_ns(struct mount *mnt, struct list_head *dt_list)
|
|||||||
ns->mnt_first_node = rb_next(&mnt->mnt_node);
|
ns->mnt_first_node = rb_next(&mnt->mnt_node);
|
||||||
rb_erase(&mnt->mnt_node, &ns->mounts);
|
rb_erase(&mnt->mnt_node, &ns->mounts);
|
||||||
RB_CLEAR_NODE(&mnt->mnt_node);
|
RB_CLEAR_NODE(&mnt->mnt_node);
|
||||||
list_add_tail(&mnt->mnt_list, dt_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_locked_children(struct mount *mnt, struct dentry *dentry);
|
bool has_locked_children(struct mount *mnt, struct dentry *dentry);
|
||||||
|
@ -1161,34 +1161,6 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt)
|
|||||||
mnt_notify_add(mnt);
|
mnt_notify_add(mnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* vfsmount lock must be held for write
|
|
||||||
*/
|
|
||||||
static void commit_tree(struct mount *mnt)
|
|
||||||
{
|
|
||||||
struct mount *parent = mnt->mnt_parent;
|
|
||||||
struct mount *m;
|
|
||||||
LIST_HEAD(head);
|
|
||||||
struct mnt_namespace *n = parent->mnt_ns;
|
|
||||||
|
|
||||||
BUG_ON(parent == mnt);
|
|
||||||
|
|
||||||
if (!mnt_ns_attached(mnt)) {
|
|
||||||
list_add_tail(&head, &mnt->mnt_list);
|
|
||||||
while (!list_empty(&head)) {
|
|
||||||
m = list_first_entry(&head, typeof(*m), mnt_list);
|
|
||||||
list_del(&m->mnt_list);
|
|
||||||
|
|
||||||
mnt_add_to_ns(n, m);
|
|
||||||
}
|
|
||||||
n->nr_mounts += n->pending_mounts;
|
|
||||||
n->pending_mounts = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
make_visible(mnt);
|
|
||||||
touch_mnt_namespace(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mount *next_mnt(struct mount *p, struct mount *root)
|
static struct mount *next_mnt(struct mount *p, struct mount *root)
|
||||||
{
|
{
|
||||||
struct list_head *next = p->mnt_mounts.next;
|
struct list_head *next = p->mnt_mounts.next;
|
||||||
@ -1215,6 +1187,27 @@ static struct mount *skip_mnt_tree(struct mount *p)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vfsmount lock must be held for write
|
||||||
|
*/
|
||||||
|
static void commit_tree(struct mount *mnt)
|
||||||
|
{
|
||||||
|
struct mnt_namespace *n = mnt->mnt_parent->mnt_ns;
|
||||||
|
|
||||||
|
if (!mnt_ns_attached(mnt)) {
|
||||||
|
for (struct mount *m = mnt; m; m = next_mnt(m, mnt))
|
||||||
|
if (unlikely(mnt_ns_attached(m)))
|
||||||
|
m = skip_mnt_tree(m);
|
||||||
|
else
|
||||||
|
mnt_add_to_ns(n, m);
|
||||||
|
n->nr_mounts += n->pending_mounts;
|
||||||
|
n->pending_mounts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
make_visible(mnt);
|
||||||
|
touch_mnt_namespace(n);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vfs_create_mount - Create a mount for a configured superblock
|
* vfs_create_mount - Create a mount for a configured superblock
|
||||||
* @fc: The configuration context with the superblock attached
|
* @fc: The configuration context with the superblock attached
|
||||||
@ -1831,9 +1824,8 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
|
|||||||
for (p = mnt; p; p = next_mnt(p, mnt)) {
|
for (p = mnt; p; p = next_mnt(p, mnt)) {
|
||||||
p->mnt.mnt_flags |= MNT_UMOUNT;
|
p->mnt.mnt_flags |= MNT_UMOUNT;
|
||||||
if (mnt_ns_attached(p))
|
if (mnt_ns_attached(p))
|
||||||
move_from_ns(p, &tmp_list);
|
move_from_ns(p);
|
||||||
else
|
list_add_tail(&p->mnt_list, &tmp_list);
|
||||||
list_move(&p->mnt_list, &tmp_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hide the mounts from mnt_mounts */
|
/* Hide the mounts from mnt_mounts */
|
||||||
@ -2270,7 +2262,6 @@ struct mount *copy_tree(struct mount *src_root, struct dentry *dentry,
|
|||||||
list_add(&dst_mnt->mnt_expire,
|
list_add(&dst_mnt->mnt_expire,
|
||||||
&src_mnt->mnt_expire);
|
&src_mnt->mnt_expire);
|
||||||
}
|
}
|
||||||
list_add_tail(&dst_mnt->mnt_list, &res->mnt_list);
|
|
||||||
attach_mnt(dst_mnt, dst_parent, src_parent->mnt_mp);
|
attach_mnt(dst_mnt, dst_parent, src_parent->mnt_mp);
|
||||||
unlock_mount_hash();
|
unlock_mount_hash();
|
||||||
}
|
}
|
||||||
@ -2686,12 +2677,9 @@ static int attach_recursive_mnt(struct mount *source_mnt,
|
|||||||
list_del_init(&source_mnt->mnt_expire);
|
list_del_init(&source_mnt->mnt_expire);
|
||||||
} else {
|
} else {
|
||||||
if (source_mnt->mnt_ns) {
|
if (source_mnt->mnt_ns) {
|
||||||
LIST_HEAD(head);
|
|
||||||
|
|
||||||
/* move from anon - the caller will destroy */
|
/* move from anon - the caller will destroy */
|
||||||
for (p = source_mnt; p; p = next_mnt(p, source_mnt))
|
for (p = source_mnt; p; p = next_mnt(p, source_mnt))
|
||||||
move_from_ns(p, &head);
|
move_from_ns(p);
|
||||||
list_del_init(&head);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,7 +449,8 @@ static void umount_one(struct mount *m, struct list_head *to_umount)
|
|||||||
{
|
{
|
||||||
m->mnt.mnt_flags |= MNT_UMOUNT;
|
m->mnt.mnt_flags |= MNT_UMOUNT;
|
||||||
list_del_init(&m->mnt_child);
|
list_del_init(&m->mnt_child);
|
||||||
move_from_ns(m, to_umount);
|
move_from_ns(m);
|
||||||
|
list_add_tail(&m->mnt_list, to_umount);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_from_candidate_list(struct mount *m)
|
static void remove_from_candidate_list(struct mount *m)
|
||||||
|
Loading…
Reference in New Issue
Block a user