forked from Minki/linux
[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
63
fs/namei.c
63
fs/namei.c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user