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

Commit a02f76c3 authored by Al Viro's avatar Al Viro
Browse files

[PATCH] get stack footprint of pathname resolution back to relative sanity



Somebody had put struct nameidata in stack frame of link_path_walk().
Unfortunately, there are certain realities to deal with:
	* It's in the middle of recursion.  Depth is equal to the nesting
depth of symlinks, i.e. up to 8.
	* struct namiedata is, even if one discards the intent junk,
at least 12 pointers + 5 ints.
	* moreover, adding a stack frame is not free in that situation.
	* there are fs methods called on top of that, and they also have
stack footprint.
	* kernel stack is not infinite.

The thing is, even if one chooses to deal with -ESTALE that way (and it's
one hell of an overkill), the only thing that needs to be preserved is
vfsmount + dentry, not the entire struct nameidata.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent b4d232e6
Loading
Loading
Loading
Loading
+32 −31
Original line number Diff line number Diff line
@@ -106,7 +106,7 @@
 * any extra contention...
 */

static int link_path_walk(const char *name, struct nameidata *nd);
static int __link_path_walk(const char *name, struct nameidata *nd);

/* In order to reduce some races, while at the same time doing additional
 * checking and hopefully speeding things up, we copy filenames to the
@@ -563,6 +563,37 @@ walk_init_root(const char *name, struct nameidata *nd)
	return 1;
}

/*
 * Wrapper to retry pathname resolution whenever the underlying
 * file system returns an ESTALE.
 *
 * Retry the whole path once, forcing real lookup requests
 * instead of relying on the dcache.
 */
static __always_inline int link_path_walk(const char *name, struct nameidata *nd)
{
	struct path save = nd->path;
	int result;

	/* make sure the stuff we saved doesn't go away */
	dget(save.dentry);
	mntget(save.mnt);

	result = __link_path_walk(name, nd);
	if (result == -ESTALE) {
		/* nd->path had been dropped */
		nd->path = save;
		dget(nd->path.dentry);
		mntget(nd->path.mnt);
		nd->flags |= LOOKUP_REVAL;
		result = __link_path_walk(name, nd);
	}

	path_put(&save);

	return result;
}

static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{
	int res = 0;
@@ -1020,36 +1051,6 @@ return_err:
	return err;
}

/*
 * Wrapper to retry pathname resolution whenever the underlying
 * file system returns an ESTALE.
 *
 * Retry the whole path once, forcing real lookup requests
 * instead of relying on the dcache.
 */
static int link_path_walk(const char *name, struct nameidata *nd)
{
	struct nameidata save = *nd;
	int result;

	/* make sure the stuff we saved doesn't go away */
	dget(save.path.dentry);
	mntget(save.path.mnt);

	result = __link_path_walk(name, nd);
	if (result == -ESTALE) {
		*nd = save;
		dget(nd->path.dentry);
		mntget(nd->path.mnt);
		nd->flags |= LOOKUP_REVAL;
		result = __link_path_walk(name, nd);
	}

	path_put(&save.path);

	return result;
}

static int path_walk(const char *name, struct nameidata *nd)
{
	current->total_link_count = 0;