Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 368ee9ba authored by Al Viro's avatar Al Viro
Browse files

namei: path_init() calling conventions change



* lift link_path_walk() into callers; moving it down into path_init()
had been a mistake.  Stack footprint, among other things...
* do _not_ call path_cleanup() after path_init() failure; on all failure
exits out of it we have nothing for path_cleanup() to do
* have path_init() return pathname or ERR_PTR(-E...)

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 34a26b99
Loading
Loading
Loading
Loading
+35 −34
Original line number Diff line number Diff line
@@ -1821,11 +1821,11 @@ static int link_path_walk(const char *name, struct nameidata *nd)
		} while (unlikely(*name == '/'));
		if (unlikely(!*name)) {
OK:
			/* called from path_init(), done */
			/* pathname body, done */
			if (!nd->depth)
				return 0;
			name = nd->stack[nd->depth - 1].name;
			/* called from trailing_symlink(), done */
			/* trailing symlink, done */
			if (!name)
				return 0;
			/* last component of nested symlink */
@@ -1862,8 +1862,8 @@ static int link_path_walk(const char *name, struct nameidata *nd)
	return err;
}

static int path_init(int dfd, const struct filename *name, unsigned int flags,
		     struct nameidata *nd)
static const char *path_init(int dfd, const struct filename *name,
			     unsigned int flags, struct nameidata *nd)
{
	int retval = 0;
	const char *s = name->name;
@@ -1871,15 +1871,16 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
	nd->last_type = LAST_ROOT; /* if there are only slashes... */
	nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
	nd->depth = 0;
	nd->total_link_count = 0;
	if (flags & LOOKUP_ROOT) {
		struct dentry *root = nd->root.dentry;
		struct inode *inode = root->d_inode;
		if (*s) {
			if (!d_can_lookup(root))
				return -ENOTDIR;
				return ERR_PTR(-ENOTDIR);
			retval = inode_permission(inode, MAY_EXEC);
			if (retval)
				return retval;
				return ERR_PTR(retval);
		}
		nd->path = nd->root;
		nd->inode = inode;
@@ -1890,7 +1891,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
		} else {
			path_get(&nd->path);
		}
		goto done;
		return s;
	}

	nd->root.mnt = NULL;
@@ -1926,14 +1927,14 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
		struct dentry *dentry;

		if (!f.file)
			return -EBADF;
			return ERR_PTR(-EBADF);

		dentry = f.file->f_path.dentry;

		if (*s) {
			if (!d_can_lookup(dentry)) {
				fdput(f);
				return -ENOTDIR;
				return ERR_PTR(-ENOTDIR);
			}
		}

@@ -1947,21 +1948,18 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
			nd->inode = nd->path.dentry->d_inode;
		}
		fdput(f);
		goto done;
		return s;
	}

	nd->inode = nd->path.dentry->d_inode;
	if (!(flags & LOOKUP_RCU))
		goto done;
		return s;
	if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq)))
		goto done;
		return s;
	if (!(nd->flags & LOOKUP_ROOT))
		nd->root.mnt = NULL;
	rcu_read_unlock();
	return -ECHILD;
done:
	nd->total_link_count = 0;
	return link_path_walk(s, nd);
	return ERR_PTR(-ECHILD);
}

static void path_cleanup(struct nameidata *nd)
@@ -2014,23 +2012,12 @@ static inline int lookup_last(struct nameidata *nd)
static int path_lookupat(int dfd, const struct filename *name,
				unsigned int flags, struct nameidata *nd)
{
	const char *s = path_init(dfd, name, flags, nd);
	int err;

	/*
	 * Path walking is largely split up into 2 different synchronisation
	 * schemes, rcu-walk and ref-walk (explained in
	 * Documentation/filesystems/path-lookup.txt). These share much of the
	 * path walk code, but some things particularly setup, cleanup, and
	 * following mounts are sufficiently divergent that functions are
	 * duplicated. Typically there is a function foo(), and its RCU
	 * analogue, foo_rcu().
	 *
	 * -ECHILD is the error number of choice (just to avoid clashes) that
	 * is returned if some aspect of an rcu-walk fails. Such an error must
	 * be handled by restarting a traditional ref-walk (which will always
	 * be able to complete).
	 */
	err = path_init(dfd, name, flags, nd);
	if (IS_ERR(s))
		return PTR_ERR(s);
	err = link_path_walk(s, nd);
	if (!err) {
		while ((err = lookup_last(nd)) > 0) {
			err = trailing_symlink(nd);
@@ -2075,7 +2062,11 @@ static int filename_lookup(int dfd, struct filename *name,
static int path_parentat(int dfd, const struct filename *name,
				unsigned int flags, struct nameidata *nd)
{
	int err = path_init(dfd, name, flags | LOOKUP_PARENT, nd);
	const char *s = path_init(dfd, name, flags, nd);
	int err;
	if (IS_ERR(s))
		return PTR_ERR(s);
	err = link_path_walk(s, nd);
	if (!err)
		err = complete_walk(nd);
	path_cleanup(nd);
@@ -2406,7 +2397,11 @@ static int
path_mountpoint(int dfd, const struct filename *name, struct path *path,
		struct nameidata *nd, unsigned int flags)
{
	int err = path_init(dfd, name, flags, nd);
	const char *s = path_init(dfd, name, flags, nd);
	int err;
	if (IS_ERR(s))
		return PTR_ERR(s);
	err = link_path_walk(s, nd);
	if (unlikely(err))
		goto out;

@@ -3266,6 +3261,7 @@ static int do_tmpfile(int dfd, struct filename *pathname,
static struct file *path_openat(int dfd, struct filename *pathname,
		struct nameidata *nd, const struct open_flags *op, int flags)
{
	const char *s;
	struct file *file;
	int opened = 0;
	int error;
@@ -3281,7 +3277,12 @@ static struct file *path_openat(int dfd, struct filename *pathname,
		goto out2;
	}

	error = path_init(dfd, pathname, flags, nd);
	s = path_init(dfd, pathname, flags, nd);
	if (IS_ERR(s)) {
		put_filp(file);
		return ERR_CAST(s);
	}
	error = link_path_walk(s, nd);
	if (unlikely(error))
		goto out;