Linux: d_splice_alias may drop inode reference on error

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]

Change-Id: Id1786ac2227b4d8e0ae801fe59c15a0ecd975bed
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>
This commit is contained in:
Marc Dionne 2014-12-18 08:43:22 -05:00 committed by Jeffrey Altman
parent b9d86a12d1
commit 15260c7fdc
2 changed files with 52 additions and 3 deletions

View File

@ -251,6 +251,26 @@ AC_ARG_ENABLE([linux-syscall-probing],
[enable Linux syscall probing (defaults to autodetect)])],
[],
[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([crosstools-dir],
[AS_HELP_STRING([--with-crosstools-dir=path],
[use path for native versions of rxgen, compile_et and config])
@ -989,6 +1009,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);])
@ -1179,6 +1202,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

View File

@ -1550,6 +1550,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:
@ -1563,14 +1574,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