Commit 957dd41d authored by Al Viro's avatar Al Viro
Browse files

move handle_dots(), follow_dotdot() and follow_dotdot_rcu() past step_into()



pure move; we are going to have step_into() called by that bunch.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent c9a0f75d
Loading
Loading
Loading
Loading
+130 −130
Original line number Diff line number Diff line
@@ -1363,70 +1363,6 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
	return ret;
}

static int follow_dotdot_rcu(struct nameidata *nd)
{
	struct dentry *parent = NULL;
	struct inode *inode = nd->inode;
	unsigned seq;

	while (1) {
		if (path_equal(&nd->path, &nd->root))
			break;
		if (nd->path.dentry != nd->path.mnt->mnt_root) {
			struct dentry *old = nd->path.dentry;

			parent = old->d_parent;
			inode = parent->d_inode;
			seq = read_seqcount_begin(&parent->d_seq);
			if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq)))
				return -ECHILD;
			if (unlikely(!path_connected(nd->path.mnt, parent)))
				return -ECHILD;
			break;
		} else {
			struct mount *mnt = real_mount(nd->path.mnt);
			struct mount *mparent = mnt->mnt_parent;
			struct dentry *mountpoint = mnt->mnt_mountpoint;
			struct inode *inode2 = mountpoint->d_inode;
			unsigned seq = read_seqcount_begin(&mountpoint->d_seq);
			if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
				return -ECHILD;
			if (&mparent->mnt == nd->path.mnt)
				break;
			if (unlikely(nd->flags & LOOKUP_NO_XDEV))
				return -ECHILD;
			/* we know that mountpoint was pinned */
			nd->path.dentry = mountpoint;
			nd->path.mnt = &mparent->mnt;
			inode = inode2;
			nd->seq = seq;
		}
	}
	if (unlikely(!parent)) {
		if (unlikely(nd->flags & LOOKUP_BENEATH))
			return -ECHILD;
	} else {
		nd->path.dentry = parent;
		nd->seq = seq;
	}
	while (unlikely(d_mountpoint(nd->path.dentry))) {
		struct mount *mounted;
		mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
		if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
			return -ECHILD;
		if (!mounted)
			break;
		if (unlikely(nd->flags & LOOKUP_NO_XDEV))
			return -ECHILD;
		nd->path.mnt = &mounted->mnt;
		nd->path.dentry = mounted->mnt.mnt_root;
		inode = nd->path.dentry->d_inode;
		nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
	}
	nd->inode = inode;
	return 0;
}

/*
 * Skip to top of mountpoint pile in refwalk mode for follow_dotdot()
 */
@@ -1443,38 +1379,6 @@ static void follow_mount(struct path *path)
	}
}

static int follow_dotdot(struct nameidata *nd)
{
	struct dentry *parent = NULL;
	while (1) {
		if (path_equal(&nd->path, &nd->root))
			break;
		if (nd->path.dentry != nd->path.mnt->mnt_root) {
			/* rare case of legitimate dget_parent()... */
			parent = dget_parent(nd->path.dentry);
			if (unlikely(!path_connected(nd->path.mnt, parent))) {
				dput(parent);
				return -ENOENT;
			}
			break;
		}
		if (!follow_up(&nd->path))
			break;
		if (unlikely(nd->flags & LOOKUP_NO_XDEV))
			return -EXDEV;
	}
	if (unlikely(!parent)) {
		if (unlikely(nd->flags & LOOKUP_BENEATH))
			return -EXDEV;
	} else {
		dput(nd->path.dentry);
		nd->path.dentry = parent;
	}
	follow_mount(&nd->path);
	nd->inode = nd->path.dentry->d_inode;
	return 0;
}

/*
 * This looks up the name in dcache and possibly revalidates the found dentry.
 * NULL is returned if the dentry does not exist in the cache.
@@ -1654,40 +1558,6 @@ static inline int may_lookup(struct nameidata *nd)
	return inode_permission(nd->inode, MAY_EXEC);
}

static inline int handle_dots(struct nameidata *nd, int type)
{
	if (type == LAST_DOTDOT) {
		int error = 0;

		if (!nd->root.mnt) {
			error = set_root(nd);
			if (error)
				return error;
		}
		if (nd->flags & LOOKUP_RCU)
			error = follow_dotdot_rcu(nd);
		else
			error = follow_dotdot(nd);
		if (error)
			return error;

		if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) {
			/*
			 * If there was a racing rename or mount along our
			 * path, then we can't be sure that ".." hasn't jumped
			 * above nd->root (and so userspace should retry or use
			 * some fallback).
			 */
			smp_rmb();
			if (unlikely(__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq)))
				return -EAGAIN;
			if (unlikely(__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq)))
				return -EAGAIN;
		}
	}
	return 0;
}

enum {WALK_TRAILING = 1, WALK_MORE = 2, WALK_NOFOLLOW = 4};

static const char *pick_link(struct nameidata *nd, struct path *link,
@@ -1817,6 +1687,136 @@ static const char *step_into(struct nameidata *nd, int flags,
	return pick_link(nd, &path, inode, seq, flags);
}

static int follow_dotdot_rcu(struct nameidata *nd)
{
	struct dentry *parent = NULL;
	struct inode *inode = nd->inode;
	unsigned seq;

	while (1) {
		if (path_equal(&nd->path, &nd->root))
			break;
		if (nd->path.dentry != nd->path.mnt->mnt_root) {
			struct dentry *old = nd->path.dentry;

			parent = old->d_parent;
			inode = parent->d_inode;
			seq = read_seqcount_begin(&parent->d_seq);
			if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq)))
				return -ECHILD;
			if (unlikely(!path_connected(nd->path.mnt, parent)))
				return -ECHILD;
			break;
		} else {
			struct mount *mnt = real_mount(nd->path.mnt);
			struct mount *mparent = mnt->mnt_parent;
			struct dentry *mountpoint = mnt->mnt_mountpoint;
			struct inode *inode2 = mountpoint->d_inode;
			unsigned seq = read_seqcount_begin(&mountpoint->d_seq);
			if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
				return -ECHILD;
			if (&mparent->mnt == nd->path.mnt)
				break;
			if (unlikely(nd->flags & LOOKUP_NO_XDEV))
				return -ECHILD;
			/* we know that mountpoint was pinned */
			nd->path.dentry = mountpoint;
			nd->path.mnt = &mparent->mnt;
			inode = inode2;
			nd->seq = seq;
		}
	}
	if (unlikely(!parent)) {
		if (unlikely(nd->flags & LOOKUP_BENEATH))
			return -ECHILD;
	} else {
		nd->path.dentry = parent;
		nd->seq = seq;
	}
	while (unlikely(d_mountpoint(nd->path.dentry))) {
		struct mount *mounted;
		mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
		if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
			return -ECHILD;
		if (!mounted)
			break;
		if (unlikely(nd->flags & LOOKUP_NO_XDEV))
			return -ECHILD;
		nd->path.mnt = &mounted->mnt;
		nd->path.dentry = mounted->mnt.mnt_root;
		inode = nd->path.dentry->d_inode;
		nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
	}
	nd->inode = inode;
	return 0;
}

static int follow_dotdot(struct nameidata *nd)
{
	struct dentry *parent = NULL;
	while (1) {
		if (path_equal(&nd->path, &nd->root))
			break;
		if (nd->path.dentry != nd->path.mnt->mnt_root) {
			/* rare case of legitimate dget_parent()... */
			parent = dget_parent(nd->path.dentry);
			if (unlikely(!path_connected(nd->path.mnt, parent))) {
				dput(parent);
				return -ENOENT;
			}
			break;
		}
		if (!follow_up(&nd->path))
			break;
		if (unlikely(nd->flags & LOOKUP_NO_XDEV))
			return -EXDEV;
	}
	if (unlikely(!parent)) {
		if (unlikely(nd->flags & LOOKUP_BENEATH))
			return -EXDEV;
	} else {
		dput(nd->path.dentry);
		nd->path.dentry = parent;
	}
	follow_mount(&nd->path);
	nd->inode = nd->path.dentry->d_inode;
	return 0;
}

static inline int handle_dots(struct nameidata *nd, int type)
{
	if (type == LAST_DOTDOT) {
		int error = 0;

		if (!nd->root.mnt) {
			error = set_root(nd);
			if (error)
				return error;
		}
		if (nd->flags & LOOKUP_RCU)
			error = follow_dotdot_rcu(nd);
		else
			error = follow_dotdot(nd);
		if (error)
			return error;

		if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) {
			/*
			 * If there was a racing rename or mount along our
			 * path, then we can't be sure that ".." hasn't jumped
			 * above nd->root (and so userspace should retry or use
			 * some fallback).
			 */
			smp_rmb();
			if (unlikely(__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq)))
				return -EAGAIN;
			if (unlikely(__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq)))
				return -EAGAIN;
		}
	}
	return 0;
}

static const char *walk_component(struct nameidata *nd, int flags)
{
	struct dentry *dentry;