From eafc370c0eba7949d85547ebc27574aa106d3355 Mon Sep 17 00:00:00 2001
From: Anders Kaseorg <andersk@mit.edu>
Date: Tue, 7 May 2013 00:27:33 -0400
Subject: [PATCH] =?UTF-8?q?Linux:=20osi=5FTryEvictVCache:=20Don=E2=80=99t?=
 =?UTF-8?q?=20skip=20the=20first=20dentry=20if=20D=5FALIAS=5FIS=5FHLIST?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

An hlist doesn’t begin with a sentinel like a list does, so the old
code would skip the first dentry or crash with a NULL dereference if
there wasn’t one.  Use the kernel’s list_for_each_entry or
hlist_for_each_entry macros instead of trying to do it manually.

Should fix a crash observed by Alex Chernyakhovsky on kernel 3.6 and
newer.

Change-Id: I6d7bd190013a0250ca896af8d5182df55a3376b0
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
---
 src/afs/LINUX/osi_vcache.c | 30 +++++++++---------------------
 1 file changed, 9 insertions(+), 21 deletions(-)

diff --git a/src/afs/LINUX/osi_vcache.c b/src/afs/LINUX/osi_vcache.c
index dc3685b..99aab91 100644
--- a/src/afs/LINUX/osi_vcache.c
+++ b/src/afs/LINUX/osi_vcache.c
@@ -19,10 +19,8 @@ osi_TryEvictVCache(struct vcache *avc, int *slept, int defersleep) {
 
     struct dentry *dentry;
     struct inode *inode = AFSTOV(avc);
-#if defined(D_ALIAS_IS_HLIST)
-    struct hlist_node *cur, *head, *list_end;
-#else
-    struct list_head *cur, *head, *list_end;
+#if defined(D_ALIAS_IS_HLIST) && !defined(HLIST_ITERATOR_NO_NODE)
+    struct hlist_node *p;
 #endif
 
     /* First, see if we can evict the inode from the dcache */
@@ -33,13 +31,9 @@ osi_TryEvictVCache(struct vcache *avc, int *slept, int defersleep) {
 
 #if defined(HAVE_DCACHE_LOCK)
         spin_lock(&dcache_lock);
-	head = &inode->i_dentry;
 
 restart:
-        cur = head;
-	while ((cur = cur->next) != head) {
-	    dentry = list_entry(cur, struct dentry, d_alias);
-
+	list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
 	    if (d_unhashed(dentry))
 		continue;
 	    dget_locked(dentry);
@@ -57,23 +51,17 @@ restart:
 	spin_unlock(&dcache_lock);
 #else /* HAVE_DCACHE_LOCK */
 	spin_lock(&inode->i_lock);
-#if defined(D_ALIAS_IS_HLIST)
-	head = inode->i_dentry.first;
-	list_end = NULL;
-#else
-	head = &inode->i_dentry;
-	list_end = head;
-#endif
 
 restart:
-	cur = head;
-	while ((cur = cur->next) != list_end) {
 #if defined(D_ALIAS_IS_HLIST)
-	    dentry = hlist_entry(cur, struct dentry, d_alias);
+# if defined(HLIST_ITERATOR_NO_NODE)
+	hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+# else
+	hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
+# endif
 #else
-	    dentry = list_entry(cur, struct dentry, d_alias);
+	list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
 #endif
-
 	    spin_lock(&dentry->d_lock);
 	    if (d_unhashed(dentry)) {
 		spin_unlock(&dentry->d_lock);
-- 
1.8.3.rc1

