[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:
parent
b4d232e65f
commit
a02f76c34d
1 changed files with 32 additions and 31 deletions
63
fs/namei.c
63
fs/namei.c
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue