[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: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2008-02-23 15:14:28 +00:00
parent b4d232e65f
commit a02f76c34d

View file

@ -106,7 +106,7 @@
* any extra contention... * 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 /* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the * 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; 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) static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{ {
int res = 0; int res = 0;
@ -1020,36 +1051,6 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
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) static int path_walk(const char *name, struct nameidata *nd)
{ {
current->total_link_count = 0; current->total_link_count = 0;