linux-change-dentry-cleanup-20050619
[openafs.git] / src / afs / LINUX / osi_vnodeops.c
index 2da933c..33eeefa 100644 (file)
@@ -27,7 +27,6 @@ RCSID
 #include "afs/sysincludes.h"
 #include "afsincludes.h"
 #include "afs/afs_stats.h"
-#include "afs/afs_osidnlc.h"
 #include "h/mm.h"
 #ifdef HAVE_MM_INLINE_H
 #include "h/mm_inline.h"
@@ -865,15 +864,10 @@ static int
 afs_linux_dentry_revalidate(struct dentry *dp)
 #endif
 {
-    char *name = NULL;
-    cred_t *credp = crref();
     struct vrequest treq;
-    struct vcache *lookupvcp = NULL;
-    int code, bad_dentry = 1;
-    struct sysname_info sysState;
-    struct vcache *vcp, *parentvcp;
-
-    sysState.allocked = 0;
+    cred_t *credp = NULL;
+    struct vcache *vcp, *pvcp, *tvc = NULL;
+    int valid;
 
 #ifdef AFS_LINUX24_ENV
     lock_kernel();
@@ -881,88 +875,86 @@ afs_linux_dentry_revalidate(struct dentry *dp)
     AFS_GLOCK();
 
     vcp = ITOAFS(dp->d_inode);
-    parentvcp = ITOAFS(dp->d_parent->d_inode);
+    pvcp = ITOAFS(dp->d_parent->d_inode);              /* dget_parent()? */
 
-    /* If it's a negative dentry, then there's nothing to do. */
-    if (!vcp || !parentvcp)
-       goto done;
+    if (vcp) {
 
-    /* If it is the AFS root, then there's no chance it needs 
-     * revalidating */
-    if (vcp == afs_globalVp) {
-       bad_dentry = 0;
-       goto done;
-    }
+       /* If it's the AFS root no chance it needs revalidating */
+       if (vcp == afs_globalVp)
+           goto good_dentry;
 
-    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;
-    }
+       /* check_bad_parent()? */
+
+#ifdef notdef
+       /* If the last looker changes, we should make sure the current
+        * looker still has permission to examine this file.  This would
+        * always require a crref() which would be "slow".
+        */
+       if (vcp->last_looker != treq.uid) {
+           if (!afs_AccessOK(vcp, (vType(vcp) == VREG) ? PRSFS_READ : PRSFS_LOOKUP, &treq, CHECK_MODE_BITS))
+               goto bad_dentry;
+
+           vcp->last_looker = treq.uid;
+       }
+#endif
 
-    /* A DNLC lookup failure cannot be trusted. Try a real lookup. 
-       Make sure to try the real name and not the @sys expansion; 
-       afs_lookup will expand @sys itself. */
-  
-    code = afs_lookup(parentvcp, dp->d_name.name, &lookupvcp, credp);
+       /* If the parent's DataVersion has changed or the vnode
+        * is longer valid, we need to do a full lookup.  VerifyVCache
+        * isn't enough since the vnode may have been renamed.
+        */
+       if (hgetlo(pvcp->m.DataVersion) > dp->d_time || !(vcp->states & CStatd)) {
+
+           credp = crref();
+           if (afs_InitReq(&treq, credp))
+               goto bad_dentry;
+           afs_lookup(pvcp, dp->d_name.name, &tvc, credp);
+           if (!tvc || tvc != vcp)
+               goto bad_dentry;
+           if (afs_VerifyVCache(vcp, &treq))   /* update inode attributes */
+               goto bad_dentry;
+
+           dp->d_time = hgetlo(pvcp->m.DataVersion);
+       }
 
-    /* Verify that the dentry does not point to an old inode */
-    if (vcp != lookupvcp)
-       goto done;
+    } else {
+       if (hgetlo(pvcp->m.DataVersion) > dp->d_time)
+           goto bad_dentry;
 
-    bad_dentry = 0;
+       /* No change in parent's DataVersion so this negative
+        * lookup is still valid.
+        */
+    }
+
+  good_dentry:
+    valid = 1;
 
   done:
     /* Clean up */
-    if (lookupvcp)
-       afs_PutVCache(lookupvcp);
-    if (sysState.allocked)
-       osi_FreeLargeSpace(name);
-
+    if (tvc)
+       afs_PutVCache(tvc);
     AFS_GUNLOCK();
+    if (credp)
+       crfree(credp);
 
-    if (bad_dentry) {
+    if (!valid) {
        shrink_dcache_parent(dp);
        d_drop(dp);
     }
-
 #ifdef AFS_LINUX24_ENV
     unlock_kernel();
 #endif
-    crfree(credp);
+    return valid;
 
-    return !bad_dentry;
+  bad_dentry:
+    valid = 0;
+    goto done;
 }
 
-#if !defined(AFS_LINUX26_ENV)
+#if !defined(AFS_LINUX24_ENV)
 /* afs_dentry_iput */
 static void
 afs_dentry_iput(struct dentry *dp, struct inode *ip)
 {
-    int isglock;
-
-    if (ICL_SETACTIVE(afs_iclSetp)) {
-       isglock = ISAFS_GLOCK();
-       if (!isglock) AFS_GLOCK();
-       afs_Trace3(afs_iclSetp, CM_TRACE_DENTRYIPUT, ICL_TYPE_POINTER, ip,
-                  ICL_TYPE_STRING, dp->d_parent->d_name.name,
-                  ICL_TYPE_STRING, dp->d_name.name);
-       if (!isglock) AFS_GUNLOCK();
-    }
-
     osi_iput(ip);
 }
 #endif
@@ -970,16 +962,6 @@ afs_dentry_iput(struct dentry *dp, struct inode *ip)
 static int
 afs_dentry_delete(struct dentry *dp)
 {
-    int isglock;
-    if (ICL_SETACTIVE(afs_iclSetp)) {
-       isglock = ISAFS_GLOCK();
-       if (!isglock) AFS_GLOCK();
-       afs_Trace3(afs_iclSetp, CM_TRACE_DENTRYDELETE, ICL_TYPE_POINTER,
-                  dp->d_inode, ICL_TYPE_STRING, dp->d_parent->d_name.name,
-                  ICL_TYPE_STRING, dp->d_name.name);
-       if (!isglock) AFS_GUNLOCK();
-    }
-
     if (dp->d_inode && (ITOAFS(dp->d_inode)->states & CUnlinked))
        return 1;               /* bad inode? */
 
@@ -989,7 +971,7 @@ afs_dentry_delete(struct dentry *dp)
 struct dentry_operations afs_dentry_operations = {
   .d_revalidate =      afs_linux_dentry_revalidate,
   .d_delete =          afs_dentry_delete,
-#if !defined(AFS_LINUX26_ENV)
+#if !defined(AFS_LINUX24_ENV)
   .d_iput =            afs_dentry_iput,
 #endif
 };
@@ -1057,6 +1039,7 @@ afs_linux_create(struct inode *dip, struct dentry *dp, int mode)
 #endif
 
        dp->d_op = &afs_dentry_operations;
+       dp->d_time = hgetlo(ITOAFS(dip)->m.DataVersion);
        d_instantiate(dp, ip);
     }
 
@@ -1087,6 +1070,9 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
     cred_t *credp = crref();
     struct vcache *vcp = NULL;
     const char *comp = dp->d_name.name;
+#if 1
+    struct dentry *res = 0;
+#endif
 
 #if defined(AFS_LINUX26_ENV)
     lock_kernel();
@@ -1106,6 +1092,8 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
        } else if (S_ISDIR(ip->i_mode)) {
            ip->i_op = &afs_dir_iops;
            ip->i_fop = &afs_dir_fops;
+            d_prune_aliases(ip);
+            res = d_find_alias(ip);
        } else if (S_ISLNK(ip->i_mode)) {
            ip->i_op = &afs_symlink_iops;
            ip->i_data.a_ops = &afs_symlink_aops;
@@ -1128,6 +1116,13 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
 #endif
     }
     dp->d_op = &afs_dentry_operations;
+    dp->d_time = hgetlo(ITOAFS(dip)->m.DataVersion);
+#if defined(AFS_LINUX24_ENV)
+    if (res) {
+       if (d_unhashed(res))
+           d_rehash(res);
+    } else
+#endif
     d_add(dp, AFSTOI(vcp));
 
 #if defined(AFS_LINUX26_ENV)
@@ -1138,6 +1133,10 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
     /* 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);
@@ -1218,8 +1217,10 @@ afs_linux_unlink(struct inode *dip, struct dentry *dp)
        }
        AFS_GUNLOCK();
 
-       if (!code)
+       if (!code) {
+           __dp->d_time = hgetlo(ITOAFS(dip)->m.DataVersion);
            d_move(dp, __dp);
+       }
        dput(__dp);
 
        goto out;
@@ -1285,6 +1286,7 @@ afs_linux_mkdir(struct inode *dip, struct dentry *dp, int mode)
        tvcp->v.v_fop = &afs_dir_fops;
 #endif
        dp->d_op = &afs_dentry_operations;
+       dp->d_time = hgetlo(ITOAFS(dip)->m.DataVersion);
        d_instantiate(dp, AFSTOI(tvcp));
     }