[PATCH] get stack footprint of pathname resolution back to relative sanity
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 23 Feb 2008 15:14:28 +0000 (15:14 +0000)
committerAl Viro <viro@zeniv.linux.org.uk>
Wed, 19 Mar 2008 10:55:46 +0000 (06:55 -0400)
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>
fs/namei.c

index 941c8e8..7346e99 100644 (file)
  * 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;