[OpenAFS-devel] Linux 2.6.12 kernel BUG at fs/namei.c:1189

chas williams - CONTRACTOR chas@cmf.nrl.navy.mil
Mon, 12 Dec 2005 20:14:45 -0500


In message <877jab34qc.fsf@windlord.stanford.edu>,Russ Allbery writes:
>This sounds fairly credible to me, although I don't really know how to fix
>it.  :)  I'm surprised that more people haven't run into this.  I mv mount
>points all the time; maybe I'm weird?

some earlier versions of afs didnt worry about how many dentries were
hanging off a directory inode.  anyway, try this.  do_rename() seems
to do a lookup/revalidation before it does the rename.  this patch just
drops the existing dentry in favor of a more "relative" dentry.

Index: src/afs/LINUX/osi_vnodeops.c
===================================================================
RCS file: /cvs/openafs/src/afs/LINUX/osi_vnodeops.c,v
retrieving revision 1.121
diff -u -u -r1.121 osi_vnodeops.c
--- src/afs/LINUX/osi_vnodeops.c	15 Oct 2005 15:51:09 -0000	1.121
+++ src/afs/LINUX/osi_vnodeops.c	13 Dec 2005 01:04:30 -0000
@@ -879,11 +882,9 @@
 afs_linux_lookup(struct inode *dip, struct dentry *dp)
 #endif
 {
-    struct vattr vattr;
     cred_t *credp = crref();
     struct vcache *vcp = NULL;
     const char *comp = dp->d_name.name;
-    struct dentry *res = NULL;
     struct inode *ip = NULL;
     int code;
 
@@ -894,24 +895,33 @@
     code = afs_lookup(VTOAFS(dip), comp, &vcp, credp);
     
     if (vcp) {
-	ip = AFSTOV(vcp);
+	struct vattr vattr;
 
+	ip = AFSTOV(vcp);
 	afs_getattr(vcp, &vattr, credp);
 	afs_fill_inode(ip, &vattr);
     }
     dp->d_op = &afs_dentry_operations;
     dp->d_time = hgetlo(VTOAFS(dip)->m.DataVersion);
     AFS_GUNLOCK();
+
 #if defined(AFS_LINUX24_ENV)
     if (ip && S_ISDIR(ip->i_mode)) {
-            d_prune_aliases(ip);
-            res = d_find_alias(ip);
+	struct dentry *alias;
+
+	alias = d_find_alias(ip);
+	if (alias) {
+	    if (d_invalidate(alias) == 0) {
+		dput(alias);
+	    } else {
+		iput(ip);
+#if defined(AFS_LINUX26_ENV)
+		unlock_kernel();
+#endif
+		return alias;
+	    }
+	}
     }
-    if (res) {
-	if (d_unhashed(res))
-	    d_rehash(res);
-	iput(ip);
-    } else
 #endif
     d_add(dp, ip);
 
@@ -923,10 +933,6 @@
     /* It's ok for the file to not be found. That's noted by the caller by
      * seeing that the dp->d_inode field is NULL.
      */
-#if defined(AFS_LINUX24_ENV)
-    if (code == 0)
-        return res;
-#endif
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
     if (code == ENOENT)
 	return ERR_PTR(0);