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

Commit 806b681c authored by Al Viro's avatar Al Viro
Browse files

Turn do_link spaghetty into a normal loop



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 10fa8e62
Loading
Loading
Loading
Loading
+38 −45
Original line number Diff line number Diff line
@@ -1844,39 +1844,20 @@ struct file *do_filp_open(int dfd, const char *pathname,
	if (open_flag & O_EXCL)
		nd.flags |= LOOKUP_EXCL;
	filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
	if (!filp)
		goto do_link;
	goto out;

exit_dput:
	path_put_conditional(&path, &nd);
	if (!IS_ERR(nd.intent.open.file))
		release_open_intent(&nd);
exit_parent:
	path_put(&nd.path);
	filp = ERR_PTR(error);
out:
	if (nd.root.mnt)
		path_put(&nd.root);
	if (filp == ERR_PTR(-ESTALE) && !force_reval) {
		force_reval = 1;
		goto reval;
	}
	return filp;

do_link:
	while (unlikely(!filp)) { /* trailing symlink */
		error = -ELOOP;
		if ((open_flag & O_NOFOLLOW) || count++ == 32)
			goto exit_dput;
		/*
	 * This is subtle. Instead of calling do_follow_link() we do the
	 * thing by hands. The reason is that this way we have zero link_count
	 * and path_walk() (called from ->follow_link) honoring LOOKUP_PARENT.
	 * After that we have the parent and last component, i.e.
	 * we are in the same situation as after the first path_walk().
	 * Well, almost - if the last component is normal we get its copy
	 * stored in nd->last.name and we will have to putname() it when we
	 * are done. Procfs-like symlinks just set LAST_BIND.
		 * This is subtle. Instead of calling do_follow_link() we do
		 * the thing by hands. The reason is that this way we have zero
		 * link_count and path_walk() (called from ->follow_link)
		 * honoring LOOKUP_PARENT.  After that we have the parent and
		 * last component, i.e. we are in the same situation as after
		 * the first path_walk().  Well, almost - if the last component
		 * is normal we get its copy stored in nd->last.name and we will
		 * have to putname() it when we are done. Procfs-like symlinks
		 * just set LAST_BIND.
		 */
		nd.flags |= LOOKUP_PARENT;
		error = security_inode_follow_link(path.dentry, &nd);
@@ -1885,10 +1866,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
		error = __do_follow_link(&path, &nd);
		path_put(&path);
		if (error) {
		/* Does someone understand code flow here? Or it is only
		 * me so stupid? Anathema to whoever designed this non-sense
		 * with "intent.open".
		 */
			/* nd.path had been dropped */
			release_open_intent(&nd);
			filp = ERR_PTR(error);
			goto out;
@@ -1897,8 +1875,23 @@ struct file *do_filp_open(int dfd, const char *pathname,
		filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
		if (nd.last_type == LAST_NORM)
			__putname(nd.last.name);
	if (!filp)
		goto do_link;
	}
out:
	if (nd.root.mnt)
		path_put(&nd.root);
	if (filp == ERR_PTR(-ESTALE) && !force_reval) {
		force_reval = 1;
		goto reval;
	}
	return filp;

exit_dput:
	path_put_conditional(&path, &nd);
	if (!IS_ERR(nd.intent.open.file))
		release_open_intent(&nd);
exit_parent:
	path_put(&nd.path);
	filp = ERR_PTR(error);
	goto out;
}