From 7c3999e05c928991d22e3eeae2c69e5759c6ea4a Mon Sep 17 00:00:00 2001
From: Marc Dionne <marc.c.dionne@gmail.com>
Date: Wed, 2 Feb 2011 21:55:27 -0500
Subject: [PATCH 8/8] Linux: 2.6.38: dentry->d_count is not an atomic

d_count is now an int protected by the dentry's d_lock.
Take the lock when we use it, instead of using an atomic_*
function.

Reviewed-on: http://gerrit.openafs.org/3883
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
(cherry picked from commit 281f5bf5fbb0a546edcce62ef4e097ae9bbdbf73)

Change-Id: Id6b17d9cfe18d348a66df02f6b309fc53b00da86
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
Reviewed-on: http://gerrit.openafs.org/3999
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Russ Allbery <rra@stanford.edu>
Reviewed-on: http://gerrit.openafs.org/4044
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>
---
 acinclude.m4                 |    1 +
 src/afs/LINUX/osi_vnodeops.c |    9 +++++++++
 src/cf/linux-test4.m4        |   12 ++++++++++++
 3 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/acinclude.m4 b/acinclude.m4
index 655fb11..c3f5e15 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -818,6 +818,7 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*)
 		 LINUX_INIT_WORK_HAS_DATA
 		 LINUX_REGISTER_SYSCTL_TABLE_NOFLAG
 		 LINUX_HAVE_DCACHE_LOCK
+		 LINUX_D_COUNT_IS_INT
 		 LINUX_SYSCTL_TABLE_CHECKING
 		 LINUX_STRUCT_CTL_TABLE_HAS_CTL_NAME
 		 LINUX_HAVE_IGET
diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c
index e2a3e28..3118ec7 100644
--- a/src/afs/LINUX/osi_vnodeops.c
+++ b/src/afs/LINUX/osi_vnodeops.c
@@ -1396,9 +1396,18 @@ afs_linux_rename(struct inode *oldip, struct dentry *olddp,
 #endif
 
 #if defined(AFS_LINUX24_ENV)
+#if defined(D_COUNT_INT)
+    spin_lock(&olddp->d_lock);
+    if (olddp->d_count > 1) {
+	spin_unlock(&olddp->d_lock);
+	shrink_dcache_parent(olddp);
+    } else
+	spin_unlock(&olddp->d_lock);
+#else
     if (atomic_read(&olddp->d_count) > 1)
 	shrink_dcache_parent(olddp);
 #endif
+#endif
 
     AFS_GLOCK();
     code = afs_rename(VTOAFS(oldip), oldname, VTOAFS(newip), newname, credp);
diff --git a/src/cf/linux-test4.m4 b/src/cf/linux-test4.m4
index 2f426ce..b428f37 100644
--- a/src/cf/linux-test4.m4
+++ b/src/cf/linux-test4.m4
@@ -1327,3 +1327,15 @@ AC_DEFUN([LINUX_HAVE_DCACHE_LOCK], [
 			[])
 ])
 
+
+AC_DEFUN([LINUX_D_COUNT_IS_INT], [
+  AC_CHECK_LINUX_BUILD([if dentry->d_count is an int],
+			[ac_cv_linux_d_count_int],
+			[#include <linux/dcache.h> ],
+			[struct dentry _d;
+			dget(&_d);
+			_d.d_count = 1;],
+			[D_COUNT_INT],
+			[define if dentry->d_count is an int],
+			[-Werror])
+])
-- 
1.7.3.4

