From 2c9bc3ec349ae550bf60d0c46f15bdabe2b0fd9e Mon Sep 17 00:00:00 2001
From: Marc Dionne <marc.dionne@your-file-system.com>
Date: Thu, 18 Dec 2014 06:57:22 -0500
Subject: [PATCH 1/2] Linux: Move code to reset the root to afs/LINUX

Move the Linux specific bit of code to reset the root to
afs/LINUX platform specific files.  Things that play with
the Linux vfs internals should not be exposed here.

No functional change, but this helps cleanup some ifdef
mess.

Change-Id: Ia27fca3d8052ead45783cb2332c04fe6e99e5d9f
---
 src/afs/LINUX/osi_prototypes.h   |  3 ++
 src/afs/LINUX/osi_vcache.c       | 61 ++++++++++++++++++++++++++++++++++++
 src/afs/LINUX24/osi_prototypes.h |  3 ++
 src/afs/LINUX24/osi_vcache.c     | 36 +++++++++++++++++++++
 src/afs/afs_daemons.c            | 67 +++-------------------------------------
 5 files changed, 108 insertions(+), 62 deletions(-)

diff --git a/src/afs/LINUX/osi_prototypes.h b/src/afs/LINUX/osi_prototypes.h
index 277b50a..5002af1 100644
--- a/src/afs/LINUX/osi_prototypes.h
+++ b/src/afs/LINUX/osi_prototypes.h
@@ -82,6 +82,9 @@ extern void osi_VM_FlushPages(struct vcache *avc, afs_ucred_t *credp);
 extern void osi_VM_Truncate(struct vcache *avc, int alen,
 			    afs_ucred_t *acred);
 
+/* osi_vcache.c */
+extern void osi_ResetRootVCache(afs_uint32 volid);
+
 /* osi_vfsops.c */
 extern void vattr2inode(struct inode *ip, struct vattr *vp);
 extern int afs_init_inodecache(void);
diff --git a/src/afs/LINUX/osi_vcache.c b/src/afs/LINUX/osi_vcache.c
index 1d0db82..391e7d4 100644
--- a/src/afs/LINUX/osi_vcache.c
+++ b/src/afs/LINUX/osi_vcache.c
@@ -143,3 +143,64 @@ osi_PostPopulateVCache(struct vcache *avc) {
     vSetType(avc, VREG);
 }
 
+/**
+ * osi_ResetRootVCache - Reset the root vcache
+ * Reset the dentry associated with the afs root.
+ * Called from afs_CheckRootVolume when we notice that
+ * the root volume ID has changed.
+ *
+ * @volid: volume ID for the afs root
+ */
+void
+osi_ResetRootVCache(afs_uint32 volid)
+{
+    struct vrequest *treq = NULL;
+    struct vattr vattr;
+    cred_t *credp;
+    struct dentry *dp;
+    struct vcache *vcp;
+    struct inode *root = AFSTOV(afs_globalVp);
+
+    afs_rootFid.Fid.Volume = volid;
+    afs_rootFid.Fid.Vnode = 1;
+    afs_rootFid.Fid.Unique = 1;
+
+    credp = crref();
+    if (afs_CreateReq(&treq, credp))
+	goto out;
+    vcp = afs_GetVCache(&afs_rootFid, treq, NULL, NULL);
+    if (!vcp)
+	goto out;
+    afs_getattr(vcp, &vattr, credp);
+    afs_fill_inode(AFSTOV(vcp), &vattr);
+
+    dp = d_find_alias(root);
+
+#if defined(HAVE_DCACHE_LOCK)
+    spin_lock(&dcache_lock);
+#else
+    spin_lock(&AFSTOV(vcp)->i_lock);
+#endif
+    spin_lock(&dp->d_lock);
+#if defined(D_ALIAS_IS_HLIST)
+    hlist_del_init(&dp->d_alias);
+    hlist_add_head(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
+#else
+    list_del_init(&dp->d_alias);
+    list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
+#endif
+    dp->d_inode = AFSTOV(vcp);
+    spin_unlock(&dp->d_lock);
+#if defined(HAVE_DCACHE_LOCK)
+    spin_unlock(&dcache_lock);
+#else
+    spin_unlock(&AFSTOV(vcp)->i_lock);
+#endif
+    dput(dp);
+
+    AFS_RELE(root);
+    afs_globalVp = vcp;
+out:
+    crfree(credp);
+    afs_DestroyReq(treq);
+}
diff --git a/src/afs/LINUX24/osi_prototypes.h b/src/afs/LINUX24/osi_prototypes.h
index cb4bee1..cd748f1 100644
--- a/src/afs/LINUX24/osi_prototypes.h
+++ b/src/afs/LINUX24/osi_prototypes.h
@@ -69,6 +69,9 @@ extern void osi_syscall_clean(void);
 extern int osi_sysctl_init(void);
 extern void osi_sysctl_clean(void);
 
+/* osi_vcache.c */
+extern void osi_ResetRootVCache(afs_uint32 volid);
+
 /* osi_vm.c */
 extern int osi_VM_FlushVCache(struct vcache *avc);
 extern void osi_VM_TryToSmush(struct vcache *avc, afs_ucred_t *acred,
diff --git a/src/afs/LINUX24/osi_vcache.c b/src/afs/LINUX24/osi_vcache.c
index bbaf5ce..853a357 100644
--- a/src/afs/LINUX24/osi_vcache.c
+++ b/src/afs/LINUX24/osi_vcache.c
@@ -119,3 +119,39 @@ osi_PostPopulateVCache(struct vcache *avc) {
     vSetType(avc, VREG);
 }
 
+void
+osi_ResetRootVCache(afs_uint32 volid)
+{
+    struct vrequest *treq = NULL;
+    struct vattr vattr;
+    cred_t *credp;
+    struct dentry *dp;
+    struct vcache *vcp;
+
+    afs_rootFid.Fid.Volume = volid;
+    afs_rootFid.Fid.Vnode = 1;
+    afs_rootFid.Fid.Unique = 1;
+
+    credp = crref();
+    if (afs_CreateReq(&treq, credp))
+	goto out;
+    vcp = afs_GetVCache(&afs_rootFid, treq, NULL, NULL);
+    if (!vcp)
+	goto out;
+    afs_getattr(vcp, &vattr, credp);
+    afs_fill_inode(AFSTOV(vcp), &vattr);
+
+    dp = d_find_alias(AFSTOV(afs_globalVp));
+    spin_lock(&dcache_lock);
+    list_del_init(&dp->d_alias);
+    list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
+    dp->d_inode = AFSTOV(vcp);
+    spin_unlock(&dcache_lock);
+    dput(dp);
+
+    AFS_FAST_RELE(afs_globalVp);
+    afs_globalVp = vcp;
+out:
+    crfree(credp);
+    afs_DestroyReq(treq);
+}
diff --git a/src/afs/afs_daemons.c b/src/afs/afs_daemons.c
index a78aaaa..dd943a7 100644
--- a/src/afs/afs_daemons.c
+++ b/src/afs/afs_daemons.c
@@ -351,71 +351,14 @@ afs_CheckRootVolume(void)
 		 * count to zero and fs checkv is executed when the current
 		 * directory is /afs.
 		 */
-#ifdef AFS_LINUX20_ENV
-		{
-		    struct vrequest *treq = NULL;
-		    struct vattr vattr;
-		    cred_t *credp;
-		    struct dentry *dp;
-		    struct vcache *vcp;
-
-		    afs_rootFid.Fid.Volume = volid;
-		    afs_rootFid.Fid.Vnode = 1;
-		    afs_rootFid.Fid.Unique = 1;
-
-		    credp = crref();
-		    if (afs_CreateReq(&treq, credp))
-			goto out;
-		    vcp = afs_GetVCache(&afs_rootFid, treq, NULL, NULL);
-		    if (!vcp)
-			goto out;
-		    afs_getattr(vcp, &vattr, credp);
-		    afs_fill_inode(AFSTOV(vcp), &vattr);
-
-		    dp = d_find_alias(AFSTOV(afs_globalVp));
-
-#if defined(AFS_LINUX24_ENV)
-#if defined(HAVE_DCACHE_LOCK)
-		    spin_lock(&dcache_lock);
-#else
-		    spin_lock(&AFSTOV(vcp)->i_lock);
-#endif
-#if defined(AFS_LINUX26_ENV)
-		    spin_lock(&dp->d_lock);
-#endif
-#endif
-#if defined(D_ALIAS_IS_HLIST)
-		    hlist_del_init(&dp->d_alias);
-		    hlist_add_head(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
-#else
-		    list_del_init(&dp->d_alias);
-		    list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
-#endif
-		    dp->d_inode = AFSTOV(vcp);
-#if defined(AFS_LINUX24_ENV)
-#if defined(AFS_LINUX26_ENV)
-		    spin_unlock(&dp->d_lock);
-#endif
-#if defined(HAVE_DCACHE_LOCK)
-		    spin_unlock(&dcache_lock);
-#else
-		    spin_unlock(&AFSTOV(vcp)->i_lock);
-#endif
-#endif
-		    dput(dp);
-
-		    AFS_FAST_RELE(afs_globalVp);
-		    afs_globalVp = vcp;
-		out:
-		    crfree(credp);
-		    afs_DestroyReq(treq);
-		}
+#ifdef AFS_LINUX22_ENV
+		osi_ResetRootVCache(volid);
 #else
-#ifdef AFS_DARWIN80_ENV
+# ifdef AFS_DARWIN80_ENV
 		afs_PutVCache(afs_globalVp);
-#else
+# else
 		AFS_FAST_RELE(afs_globalVp);
-#endif
+# endif
 		afs_globalVp = 0;
 #endif
 	    }
-- 
2.2.1


From 4ba5cbd90e96edd63bd0178df8ce615c1efe1b2c Mon Sep 17 00:00:00 2001
From: Marc Dionne <marc.dionne@your-file-system.com>
Date: Thu, 18 Dec 2014 07:13:46 -0500
Subject: [PATCH 2/2] Linux: d_alias becomes d_u.d_alias

The fields in struct dentry are re-arranged so that d_alias
shares space wth d_rcu inside the d_u union.  Some references
need to change from d_alias to d_u.d_alias.

The kernel change was introduced for 3.19 but was also backported
to the 3.18 stable series in 3.18.1, so this commit is required
for 3.19 and current 3.18 kernels.

Change-Id: I711a5a3a89af6e0055381dfd4474ddca2868bb9c
---
 acinclude.m4               | 1 +
 src/afs/LINUX/osi_compat.h | 4 ++++
 src/cf/linux-test4.m4      | 9 ++++++++-
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/acinclude.m4 b/acinclude.m4
index 96adde0..e8e238b 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -899,6 +899,7 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*)
 				       [backing-dev.h])
 		 AC_CHECK_LINUX_STRUCT([cred], [session_keyring], [cred.h])
 		 AC_CHECK_LINUX_STRUCT([ctl_table], [ctl_name], [sysctl.h])
+		 AC_CHECK_LINUX_STRUCT([dentry], [d_u.d_alias], [dcache.h])
 		 AC_CHECK_LINUX_STRUCT([dentry_operations], [d_automount], [dcache.h])
 		 AC_CHECK_LINUX_STRUCT([inode], [i_alloc_sem], [fs.h])
 		 AC_CHECK_LINUX_STRUCT([inode], [i_blkbits], [fs.h])
diff --git a/src/afs/LINUX/osi_compat.h b/src/afs/LINUX/osi_compat.h
index 57f6ea7..497b1ef 100644
--- a/src/afs/LINUX/osi_compat.h
+++ b/src/afs/LINUX/osi_compat.h
@@ -37,6 +37,10 @@ typedef struct vfs_path afs_linux_path_t;
 typedef struct path afs_linux_path_t;
 #endif
 
+#if defined(STRUCT_DENTRY_HAS_D_U_D_ALIAS)
+# define d_alias d_u.d_alias
+#endif
+
 #ifndef HAVE_LINUX_DO_SYNC_READ
 static inline int
 do_sync_read(struct file *fp, char *buf, size_t count, loff_t *offp) {
diff --git a/src/cf/linux-test4.m4 b/src/cf/linux-test4.m4
index f0269b3..9dd55b3 100644
--- a/src/cf/linux-test4.m4
+++ b/src/cf/linux-test4.m4
@@ -713,7 +713,11 @@ AC_DEFUN([LINUX_D_ALIAS_IS_HLIST], [
 			[#include <linux/fs.h>],
 			[struct dentry *d = NULL;
 			struct hlist_node *hn = NULL;
-			d->d_alias = *hn;],
+			#if defined(STRUCT_DENTRY_HAS_D_U_D_ALIAS)
+			d->d_u.d_alias = *hn;
+			#else
+			d->d_alias = *hn;
+			#endif],
 			[D_ALIAS_IS_HLIST],
 			[define if dentry->d_alias is an hlist],
 			[])
@@ -727,6 +731,9 @@ AC_DEFUN([LINUX_HLIST_ITERATOR_NO_NODE], [
 			#include <linux/fs.h>],
 			[struct dentry *d = NULL, *cur;
 			struct inode *ip;
+			#if defined(STRUCT_DENTRY_HAS_D_U_D_ALIAS)
+			# define d_alias d_u.d_alias
+			#endif
 			hlist_for_each_entry(cur, &ip->i_dentry, d_alias) { }
 			],
 			[HLIST_ITERATOR_NO_NODE],
-- 
2.2.1

