

Patch from Maneesh Soni <maneesh@in.ibm.com>

Turns out that sysfs is doing dget() on a zero-ref dentry.  That's a bug, but
dcache is no longer detecting it.

The check was removed because with lockless d_lookup, there can be cases when
d_lookup and dput are going on concurrently, If d_lookup happens earlier then
it may do dget() on a dentry for which dput() has decremented the ref count
to zero.  This race is handled by taking the per dentry lock and checking the
DCACHE_UNHASHED flag.  

The patch open-codes that part of d_lookup(), and restores the BUG check in
dget().


 dcache.c       |    7 +++++--
 linux/dcache.h |    2 ++
 2 files changed, 7 insertions(+), 2 deletions(-)

diff -puN fs/dcache.c~dget-BUG fs/dcache.c
--- 25/fs/dcache.c~dget-BUG	2003-02-20 02:09:12.000000000 -0800
+++ 25-akpm/fs/dcache.c	2003-02-20 02:09:12.000000000 -0800
@@ -1004,8 +1004,11 @@ struct dentry * d_lookup(struct dentry *
 		 */ 
 		if (unlikely(move_count != dentry->d_move_count)) 
 			break;
-		if (!d_unhashed(dentry))
-			found = dget(dentry);
+		if (!d_unhashed(dentry)) {
+			atomic_inc(&dentry->d_count);
+			dentry->d_vfs_flags |= DCACHE_REFERENCED;
+			found = dentry;
+		}
 		spin_unlock(&dentry->d_lock);
 		break;
  	}
diff -puN include/linux/dcache.h~dget-BUG include/linux/dcache.h
--- 25/include/linux/dcache.h~dget-BUG	2003-02-20 02:09:12.000000000 -0800
+++ 25-akpm/include/linux/dcache.h	2003-02-20 02:09:12.000000000 -0800
@@ -262,6 +262,8 @@ extern char * d_path(struct dentry *, st
 static __inline__ struct dentry * dget(struct dentry *dentry)
 {
 	if (dentry) {
+		if (!atomic_read(&dentry->d_count))
+			BUG();
 		atomic_inc(&dentry->d_count);
 		dentry->d_vfs_flags |= DCACHE_REFERENCED;
 	}

_
