From b1f23baecb2de72b44cda8bba27615c012a445f1 Mon Sep 17 00:00:00 2001 From: Marc Dionne Date: Thu, 18 Dec 2014 08:43:22 -0500 Subject: [PATCH] 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. Change-Id: Id1786ac2227b4d8e0ae801fe59c15a0ecd975bed --- acinclude.m4 | 3 +++ src/afs/LINUX/osi_vnodeops.c | 29 ++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 96adde0..19f7092 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -984,6 +984,9 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*) AC_CHECK_LINUX_FUNC([hlist_unhashed], [#include ], [hlist_unhashed(0);]) + AC_CHECK_LINUX_FUNC([ihold], + [#include ], + [ihold(NULL);]) AC_CHECK_LINUX_FUNC([i_size_read], [#include ], [i_size_read(NULL);]) diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index b2ab9d5..cedfef6 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -1612,6 +1612,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: @@ -1625,14 +1636,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 -- 2.2.1