mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									b2dba1af3c
								
							
						
					
					
						commit
						afac7cba7e
					
				
					 4 changed files with 29 additions and 55 deletions
				
			
		
							
								
								
									
										25
									
								
								fs/dcache.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								fs/dcache.c
									
									
									
									
									
								
							| 
						 | 
					@ -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)
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * 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,
 | 
				
			||||||
	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,
 | 
				
			||||||
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,
 | 
				
			||||||
	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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								fs/pnode.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								fs/pnode.c
									
									
									
									
									
								
							| 
						 | 
					@ -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 *,
 | 
				
			||||||
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 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue