LINUX: Reduce stack depth on recursive symlink res
authorAndrew Deason <adeason@sinenomine.net>
Fri, 3 Dec 2010 23:20:54 +0000 (17:20 -0600)
committerDerrick Brashear <shadow@dementia.org>
Wed, 22 Dec 2010 05:02:15 +0000 (21:02 -0800)
Instead of calling vfs_follow_link inside afs_linux_follow_link
ourselves, we can just resolve the next step of the symlink resolution
and set the result in nd_set_link(), freeing the string in
.put_link().

For kernels without a usable symlink text cache, this reduces call
depth when resolving a path containing many symlinks by two frames per
layer of indirection, allowing for more deeply-nested symlink paths to
be usable.

Change-Id: I6886c3b67089c8028fd6ad93ab10eb9173bd6fbe
Reviewed-on: http://gerrit.openafs.org/3433
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Simon Wilkinson <sxw@inf.ed.ac.uk>
Reviewed-by: Derrick Brashear <shadow@dementia.org>

src/afs/LINUX/osi_vnodeops.c

index 6b4a791..45098b6 100644 (file)
@@ -1383,16 +1383,21 @@ static int afs_linux_follow_link(struct dentry *dentry, struct nameidata *nd)
     AFS_GUNLOCK();
 
     if (code < 0) {
-       goto out;
+       return code;
     }
 
     name[code] = '\0';
-    code = vfs_follow_link(nd, name);
-
-out:
-    osi_Free(name, PATH_MAX);
+    nd_set_link(nd, name);
+    return 0;
+}
 
-    return code;
+static int
+afs_linux_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+    char *name = nd_get_link(nd);
+    if (name && !IS_ERR(name)) {
+       osi_Free(name, PATH_MAX);
+    }
 }
 
 #endif /* USABLE_KERNEL_PAGE_SYMLINK_CACHE */
@@ -2426,6 +2431,7 @@ static struct inode_operations afs_symlink_iops = {
 #else /* !defined(USABLE_KERNEL_PAGE_SYMLINK_CACHE) */
   .readlink =          afs_linux_readlink,
   .follow_link =       afs_linux_follow_link,
+  .put_link =          afs_linux_put_link,
 #endif /* USABLE_KERNEL_PAGE_SYMLINK_CACHE */
   .setattr =           afs_notify_change,
 };