linux-dcache-inconsistency-fix-20020115
authorChas Williams <chas@cmf.nrl.navy.mil>
Wed, 16 Jan 2002 02:08:43 +0000 (02:08 +0000)
committerDerrick Brashear <shadow@dementia.org>
Wed, 16 Jan 2002 02:08:43 +0000 (02:08 +0000)
minor rework on a patch from Ted Anderson (ota@transarc.com) to
fit OpenAFS

src/afs/LINUX/osi_vnodeops.c

index 19a2d44..6be78d1 100644 (file)
@@ -28,6 +28,7 @@ RCSID("$Header$");
 #include "../afs/sysincludes.h"
 #include "../afs/afsincludes.h"
 #include "../afs/afs_stats.h"
+#include "../afs/afs_osidnlc.h"
 #include "../h/mm.h"
 #include "../h/pagemap.h"
 #if defined(AFS_LINUX24_ENV)
@@ -781,6 +782,82 @@ static int afs_linux_revalidate(struct dentry *dp)
     return -code ;
 }
 
+
+/* Validate a dentry. Return 1 if unchanged, 0 if VFS layer should re-evaluate.
+ * In kernels 2.2.10 and above, we are passed an additional flags var which
+ * may have either the LOOKUP_FOLLOW OR LOOKUP_DIRECTORY set in which case
+ * we are advised to follow the entry if it is a link or to make sure that 
+ * it is a directory. But since the kernel itself checks these possibilities
+ * later on, we shouldn't have to do it until later. Perhaps in the future..
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
+static int afs_linux_dentry_revalidate(struct dentry *dp, int flags)
+#else
+static int afs_linux_dentry_revalidate(struct dentry *dp)
+#endif
+{
+    char *name;
+    cred_t *credp = crref();
+    struct vrequest treq;
+    struct vcache *lookupvcp = NULL;
+    int code, bad_dentry = 1;
+    struct sysname_info sysState;
+    struct vcache *vcp = (struct vcache*) dp->d_inode;
+    struct vcache *parentvcp = (struct vcache*) dp->d_parent->d_inode;
+
+    AFS_GLOCK();
+
+    /* If it's a negative dentry, then there's nothing to do. */
+    if (!vcp || !parentvcp)
+        goto done;
+
+    if (code = afs_InitReq(&treq, credp))
+        goto done;
+
+    Check_AtSys(parentvcp, dp->d_name.name, &sysState, &treq);
+    name = sysState.name;
+
+    /* First try looking up the DNLC */
+    if (lookupvcp = osi_dnlc_lookup(parentvcp, name, WRITE_LOCK)) {
+        /* Verify that the dentry does not point to an old inode */
+        if (vcp != lookupvcp)
+            goto done;
+        /* Check and correct mvid */
+        if (*name != '/' && vcp->mvstat == 2) 
+            check_bad_parent(dp);
+       vcache2inode(vcp);
+        bad_dentry = 0;
+        goto done;
+    }
+
+    /* A DNLC lookup failure cannot be trusted. Try a real lookup */
+    code = afs_lookup(parentvcp, name, &lookupvcp, credp);
+
+    /* Verify that the dentry does not point to an old inode */
+    if (vcp != lookupvcp)
+        goto done;
+
+    bad_dentry = 0;
+
+done:
+    /* Clean up */
+    if (lookupvcp)
+        afs_PutVCache(lookupvcp, WRITE_LOCK);
+    if (sysState.allocked)
+        osi_FreeLargeSpace(name);
+
+    AFS_GUNLOCK();
+    crfree(credp);
+
+    if (bad_dentry) {
+        shrink_dcache_parent(dp);
+        d_drop(dp);
+    }
+
+    return !bad_dentry;
+}
+
+#ifdef notdef
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
 static int afs_linux_dentry_revalidate(struct dentry *dp, int flags)
 #else
@@ -794,6 +871,9 @@ static int afs_linux_dentry_revalidate(struct dentry *dp)
 
     unsigned long timeout = 3*HZ; /* 3 seconds */
 
+if (!ip)
+       printk("negative dentry: %s\n", dp->d_name.name);
+
     if (!(flags & LOOKUP_CONTINUE)) {
        long diff = CURRENT_TIME - dp->d_parent->d_inode->i_mtime;
 
@@ -810,6 +890,7 @@ static int afs_linux_dentry_revalidate(struct dentry *dp)
  out_bad:
     return 0;
 }
+#endif
 
 /* afs_dentry_iput */
 static void afs_dentry_iput(struct dentry *dp, struct inode *ip)
@@ -927,17 +1008,17 @@ int afs_linux_lookup(struct inode *dip, struct dentry *dp)
            ip->i_data.a_ops = &afs_symlink_aops;
            ip->i_mapping = &ip->i_data;
        } else
-           printk("afs_linux_lookup: FIXME\n");
+           printk("afs_linux_lookup: ip->i_mode 0x%x  dp->d_name.name %s  code %d\n", ip->i_mode, dp->d_name.name, code);
 #else
        if (S_ISDIR(ip->i_mode))
            ip->i_op = &afs_dir_iops;
        else if (S_ISLNK(ip->i_mode))
            ip->i_op = &afs_symlink_iops;
 #endif
-    }
     dp->d_time = jiffies;
     dp->d_op = afs_dops;
     d_add(dp, (struct inode*)vcp);
+    } 
 
     AFS_GUNLOCK();
     crfree(credp);
@@ -985,27 +1066,11 @@ int afs_linux_unlink(struct inode *dip, struct dentry *dp)
     const char *name = dp->d_name.name;
     int putback = 0;
 
-    if (!list_empty(&dp->d_hash)) {
-       d_drop(dp);
-       /* Install a definite non-existence if we're the only user. */
-#if defined(AFS_LINUX24_ENV)
-       if (atomic_read(&dp->d_count) == 1)
-#else
-       if (dp->d_count == 1)
-#endif
-           putback = 1;
-    }
-
     AFS_GLOCK();
     code = afs_remove((struct vcache*)dip, name, credp);
     AFS_GUNLOCK();
-    if (!code) {
-       d_delete(dp);
-       if (putback) {
-           dp->d_time = jiffies;
-           d_add(dp, NULL); /* means definitely does _not_ exist */
-       }
-    }
+    if (!code)
+       d_drop(dp);
     crfree(credp);
     return -code;
 }
@@ -1055,6 +1120,7 @@ int afs_linux_mkdir(struct inode *dip, struct dentry *dp, int mode)
        dp->d_time = jiffies;
        d_instantiate(dp, (struct inode*)tvcp);
     }
+
     AFS_GUNLOCK();
     crfree(credp);
     return -code;
@@ -1078,7 +1144,7 @@ int afs_linux_rmdir(struct inode *dip, struct dentry *dp)
     }
     
     if (!code) {
-       d_delete(dp);
+       d_drop(dp);
     }
 
     AFS_GUNLOCK();