mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02: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
					
				
					 3 changed files with 27 additions and 39 deletions
				
			
		| 
						 | 
					@ -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 a new issue