linux-dentry-deletion-for-unlinked-files-22-version-20020721
[openafs.git] / src / afs / LINUX / osi_vnodeops.c
index f9f5b0b..e18d6b3 100644 (file)
@@ -42,6 +42,7 @@ RCSID("$Header$");
 #endif
 
 extern struct vcache *afs_globalVp;
+extern afs_rwlock_t afs_xvcache;
 
 extern struct dentry_operations *afs_dops;
 #if defined(AFS_LINUX24_ENV)
@@ -261,6 +262,7 @@ static int afs_linux_readdir(struct file *fp,
     int len;
     afs_size_t origOffset, tlen;
     cred_t *credp = crref();
+    struct afs_fakestat_state fakestat;
 
     AFS_GLOCK();
     AFS_STATCNT(afs_readdir);
@@ -272,10 +274,19 @@ static int afs_linux_readdir(struct file *fp,
        return -code;
     }
 
+    afs_InitFakeStat(&fakestat);
+    code = afs_EvalFakeStat(&avc, &fakestat, &treq);
+    if (code) {
+       afs_PutFakeStat(&fakestat);
+       AFS_GUNLOCK();
+       return -code;
+    }
+
     /* update the cache entry */
 tagain:
     code = afs_VerifyVCache(avc, &treq);
     if (code) {
+       afs_PutFakeStat(&fakestat);
        AFS_GUNLOCK();
        return -code;
     }
@@ -284,6 +295,7 @@ tagain:
     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
     len = tlen;
     if (!tdc) {
+       afs_PutFakeStat(&fakestat);
        AFS_GUNLOCK();
        return -ENOENT;
     }
@@ -343,6 +355,7 @@ tagain:
              afid.Fid.Unique=ntohl(de->fid.vunique);
              if ((avc->states & CForeign) == 0 &&
                  (ntohl(de->fid.vnode) & 1)) {
+                type=DT_DIR;
              } else if ((tvc=afs_FindVCache(&afid,0,0,0,0))) {
                   if (tvc->mvstat) {
                        type=DT_DIR;
@@ -380,6 +393,7 @@ tagain:
     ReleaseReadLock(&tdc->lock);
     afs_PutDCache(tdc);
     ReleaseReadLock(&avc->lock);
+    afs_PutFakeStat(&fakestat);
     AFS_GUNLOCK();
     return 0;
 }
@@ -750,20 +764,33 @@ static int afs_linux_revalidate(struct dentry *dp)
     cred_t *credp;
     struct vrequest treq;
     struct vcache *vcp = ITOAFS(dp->d_inode);
+    struct vcache *rootvp = NULL;
 
     AFS_GLOCK();
+
+    if (afs_fakestat_enable && vcp->mvstat == 1 && vcp->mvid &&
+       (vcp->states & CMValid) && (vcp->states & CStatd)) {
+       ObtainSharedLock(&afs_xvcache, 680);
+       rootvp = afs_FindVCache(vcp->mvid, 0, 0, 0, 0);
+       ReleaseSharedLock(&afs_xvcache);
+    }
+
 #ifdef AFS_LINUX24_ENV
     lock_kernel();
 #endif
 
     /* Make this a fast path (no crref), since it's called so often. */
     if (vcp->states & CStatd) {
-        if (*dp->d_name.name != '/' && vcp->mvstat == 2) /* root vnode */
+       if (*dp->d_name.name != '/' && vcp->mvstat == 2) /* root vnode */
            check_bad_parent(dp); /* check and correct mvid */
-       vcache2inode(vcp);
+       if (rootvp)
+           vcache2fakeinode(rootvp, vcp);
+       else
+           vcache2inode(vcp);
 #ifdef AFS_LINUX24_ENV
        unlock_kernel();
 #endif
+       if (rootvp) afs_PutVCache(rootvp);
        AFS_GUNLOCK();
        return 0;
     }
@@ -813,6 +840,13 @@ static int afs_linux_dentry_revalidate(struct dentry *dp)
     if (!vcp || !parentvcp)
         goto done;
 
+    /* If it is the AFS root, then there's no chance it needs 
+       revalidating */
+    if (vcp == afs_globalVp) {
+       bad_dentry = 0;
+       goto done;
+    }
+
     if (code = afs_InitReq(&treq, credp))
         goto done;
 
@@ -873,7 +907,7 @@ static int afs_linux_dentry_revalidate(struct dentry *dp)
 
     unsigned long timeout = 3*HZ; /* 3 seconds */
 
-if (!ip)
+    if (!ip)
        printk("negative dentry: %s\n", dp->d_name.name);
 
     if (!(flags & LOOKUP_CONTINUE)) {
@@ -897,13 +931,31 @@ if (!ip)
 /* afs_dentry_iput */
 static void afs_dentry_iput(struct dentry *dp, struct inode *ip)
 {
+    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);
+
     osi_iput(ip);
 }
 
+static int afs_dentry_delete(struct dentry *dp)
+{
+    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 (dp->d_inode && (ITOAFS(dp->d_inode)->states & CUnlinked))
+       return 1;               /* bad inode? */
+
+    return 0;
+}
+
 #if defined(AFS_LINUX24_ENV)
 struct dentry_operations afs_dentry_operations = {
        d_revalidate:   afs_linux_dentry_revalidate,
        d_iput:         afs_dentry_iput,
+       d_delete:       afs_dentry_delete,
 };
 struct dentry_operations *afs_dops = &afs_dentry_operations;
 #else
@@ -911,7 +963,7 @@ struct dentry_operations afs_dentry_operations = {
        afs_linux_dentry_revalidate,    /* d_validate(struct dentry *) */
        NULL,                   /* d_hash */
        NULL,                   /* d_compare */
-       NULL,                   /* d_delete(struct dentry *) */
+       afs_dentry_delete,      /* d_delete(struct dentry *) */
        NULL,                   /* d_release(struct dentry *) */
        afs_dentry_iput         /* d_iput(struct dentry *, struct inode *) */
 };
@@ -1066,7 +1118,6 @@ int afs_linux_unlink(struct inode *dip, struct dentry *dp)
     int code;
     cred_t *credp = crref();
     const char *name = dp->d_name.name;
-    int putback = 0;
 
     AFS_GLOCK();
     code = afs_remove(ITOAFS(dip), name, credp);