]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
Linux: d_splice_alias may drop inode reference on error
authorMarc Dionne <marc.dionne@your-file-system.com>
Thu, 18 Dec 2014 13:43:22 +0000 (08:43 -0500)
committerStephan Wiesand <stephan.wiesand@desy.de>
Fri, 13 Feb 2015 10:17:36 +0000 (05:17 -0500)
d_splice_alias now drops the inode reference on error, so we
need to grab an extra one to make sure that the inode doesn't
go away, and release it when done if there was no error.

For kernels that may not drop the reference, provide an
additional iput() within an ifdef.  This could be hooked up
to a configure option to allow building a module for a kernel
that is known not to drop the reference on error.  That hook
is not provided here.  Affected kernels should be the early
3.17 ones (3.17 - 3.17.2); 3.16 and older kernels should not
return errors here.

[kaduk@mit.edu add configure option to control behavior, which
is mandatory on non-buildbot linux systems]

Reviewed-on: http://gerrit.openafs.org/11643
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Michael Laß <lass@mail.uni-paderborn.de>
Reviewed-by: Jeffrey Altman <jaltman@your-file-system.com>
(cherry picked from commit 15260c7fdc5ac8fe9fb1797c8e383c665e9e0ccd)

Change-Id: I288eb66c38386fcd6bae0da111d97e211cc5c995
Reviewed-on: http://gerrit.openafs.org/11694
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Stephan Wiesand <stephan.wiesand@desy.de>
acinclude.m4
src/afs/LINUX/osi_vnodeops.c

index 11e88e26d2f4f5f2c655ce74a61bab93f248c7d4..e7b7ae98d894c529704b22e8ce8aac5869b7ada4 100644 (file)
@@ -232,6 +232,26 @@ AC_ARG_ENABLE([linux-syscall-probing],
     ,
     [enable_linux_syscall_probing="maybe"])
     
+AC_ARG_ENABLE([linux-d_splice_alias-extra-iput],
+    [AS_HELP_STRING([--enable-linux-d_splice_alias-extra-iput],
+       [Linux has introduced an incompatible behavior change in the
+        d_splice_alias function with no reliable way to determine which
+        behavior will be produced.  If Linux commit
+        51486b900ee92856b977eacfc5bfbe6565028070 (or equivalent) has been
+        applied to your kernel, disable this option.  If that commit is
+        not present in your kernel, enable this option.  We apologize
+        that you are required to know this about your running kernel.])],
+    [],
+    [case $system in
+    *-linux*)
+       AS_IF([test "x$LOGNAME" != "xbuildslave" &&
+           test "x$LOGNAME" != "xbuildbot"],
+           [AC_ERROR([Linux users must specify either
+               --enable-linux-d_splice_alias-extra-iput or
+               --disable-linux-d_splice_alias-extra-iput])],
+           [enable_linux_d_splice_alias_extra_iput="no"])
+     esac
+    ])
 AC_ARG_WITH([xslt-processor],
        AS_HELP_STRING([--with-xslt-processor=ARG],
        [which XSLT processor to use (possible choices are: libxslt, saxon, xalan-j, xsltproc)]),
@@ -925,6 +945,9 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*)
                 AC_CHECK_LINUX_FUNC([hlist_unhashed],
                                     [#include <linux/list.h>],
                                     [hlist_unhashed(0);])
+                AC_CHECK_LINUX_FUNC([ihold],
+                                    [#include <linux/fs.h>],
+                                    [ihold(NULL);])
                 AC_CHECK_LINUX_FUNC([i_size_read],
                                     [#include <linux/fs.h>],
                                     [i_size_read(NULL);])
@@ -1116,6 +1139,9 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*)
                 fi
                 :
                fi
+               if test "x$enable_linux_d_splice_alias_extra_iput" = xyes; then
+                   AC_DEFINE(D_SPLICE_ALIAS_LEAK_ON_ERROR, 1, [for internal use])
+               fi
 dnl Linux-only, but just enable always.
                AC_DEFINE(AFS_CACHE_BYPASS, 1, [define to activate cache bypassing Unix client])
 esac
index 216b4e2926f4b98fba50ec1e426b3120192f875b..f3ca4e35c90cf7c5faebc9a672ef2d26081b49ec 100644 (file)
@@ -1548,6 +1548,17 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
        ip->i_flags |= S_AUTOMOUNT;
 #endif
     }
+    /*
+     * Take an extra reference so the inode doesn't go away if
+     * d_splice_alias drops our reference on error.
+     */
+    if (ip)
+#ifdef HAVE_LINUX_IHOLD
+       ihold(ip);
+#else
+       igrab(ip);
+#endif
+
     newdp = d_splice_alias(ip, dp);
 
  done:
@@ -1561,14 +1572,26 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
         * d_splice_alias can return an error (EIO) if there is an existing
         * connected directory alias for this dentry.
         */
-       if (!IS_ERR(newdp))
+       if (!IS_ERR(newdp)) {
+           iput(ip);
            return newdp;
-       else {
+       else {
            d_add(dp, ip);
+           /*
+            * Depending on the kernel version, d_splice_alias may or may
+            * not drop the inode reference on error.  If it didn't, do it
+            * here.
+            */
+#if defined(D_SPLICE_ALIAS_LEAK_ON_ERROR)
+           iput(ip);
+#endif
            return NULL;
        }
-    } else
+    } else {
+       if (ip)
+           iput(ip);
        return ERR_PTR(afs_convert_code(code));
+    }
 }
 
 static int