Commit 2aa38470 authored by Al Viro's avatar Al Viro
Browse files

non-RCU analogue of the previous commit



new helper: choose_mountpoint().  Wrapper around choose_mountpoint_rcu(),
similar to lookup_mnt() vs. __lookup_mnt().  follow_dotdot() switched to
it.  Now we don't grab mount_lock exclusive anymore; note that the
primitive used non-RCU mount traversals in other direction (lookup_mnt())
doesn't bother with that either - it uses mount_lock seqcount instead.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 7ef482fa
Loading
Loading
Loading
Loading
+39 −17
Original line number Original line Diff line number Diff line
@@ -605,10 +605,9 @@ static void terminate_walk(struct nameidata *nd)
}
}


/* path_put is needed afterwards regardless of success or failure */
/* path_put is needed afterwards regardless of success or failure */
static bool legitimize_path(struct nameidata *nd,
static bool __legitimize_path(struct path *path, unsigned seq, unsigned mseq)
			    struct path *path, unsigned seq)
{
{
	int res = __legitimize_mnt(path->mnt, nd->m_seq);
	int res = __legitimize_mnt(path->mnt, mseq);
	if (unlikely(res)) {
	if (unlikely(res)) {
		if (res > 0)
		if (res > 0)
			path->mnt = NULL;
			path->mnt = NULL;
@@ -622,6 +621,12 @@ static bool legitimize_path(struct nameidata *nd,
	return !read_seqcount_retry(&path->dentry->d_seq, seq);
	return !read_seqcount_retry(&path->dentry->d_seq, seq);
}
}


static inline bool legitimize_path(struct nameidata *nd,
			    struct path *path, unsigned seq)
{
	return __legitimize_path(path, nd->m_seq, seq);
}

static bool legitimize_links(struct nameidata *nd)
static bool legitimize_links(struct nameidata *nd)
{
{
	int i;
	int i;
@@ -1154,6 +1159,31 @@ static bool choose_mountpoint_rcu(struct mount *m, const struct path *root,
	return false;
	return false;
}
}


static bool choose_mountpoint(struct mount *m, const struct path *root,
			      struct path *path)
{
	bool found;

	rcu_read_lock();
	while (1) {
		unsigned seq, mseq = read_seqbegin(&mount_lock);

		found = choose_mountpoint_rcu(m, root, path, &seq);
		if (unlikely(!found)) {
			if (!read_seqretry(&mount_lock, mseq))
				break;
		} else {
			if (likely(__legitimize_path(path, seq, mseq)))
				break;
			rcu_read_unlock();
			path_put(path);
			rcu_read_lock();
		}
	}
	rcu_read_unlock();
	return found;
}

/*
/*
 * Perform an automount
 * Perform an automount
 * - return -EISDIR to tell follow_managed() to stop and return the path we
 * - return -EISDIR to tell follow_managed() to stop and return the path we
@@ -1756,22 +1786,14 @@ static struct dentry *follow_dotdot(struct nameidata *nd,
	if (path_equal(&nd->path, &nd->root))
	if (path_equal(&nd->path, &nd->root))
		goto in_root;
		goto in_root;
	if (unlikely(nd->path.dentry == nd->path.mnt->mnt_root)) {
	if (unlikely(nd->path.dentry == nd->path.mnt->mnt_root)) {
		struct path path = nd->path;
		struct path path;
		path_get(&path);

		while (1) {
		if (!choose_mountpoint(real_mount(nd->path.mnt),
			if (!follow_up(&path)) {
				       &nd->root, &path))
				path_put(&path);
				goto in_root;
			}
			if (path_equal(&path, &nd->root)) {
				path_put(&path);
			goto in_root;
			goto in_root;
			}
			if (path.dentry != nd->path.mnt->mnt_root)
				break;
		}
		path_put(&nd->path);
		path_put(&nd->path);
		nd->path = path;
		nd->path = path;
		nd->inode = path.dentry->d_inode;
		if (unlikely(nd->flags & LOOKUP_NO_XDEV))
		if (unlikely(nd->flags & LOOKUP_NO_XDEV))
			return ERR_PTR(-EXDEV);
			return ERR_PTR(-EXDEV);
	}
	}