[OpenAFS-devel] funny lookup/dnlc/dcache/...

chas williams - CONTRACTOR chas@cmf.nrl.navy.mil
Sun, 24 Apr 2005 09:35:48 -0400


after a bit of discussion and testing i think the following might be a
satisfactory replacement.  the original rewrite was to handle leaking
stat information.  cached dentries would be available to other afs users
without regard to the access that afs user should have.

this is addressed by keeping track of the last_looker of a particular
vcache entry.  if the looker changes, then access is checked with
afs_AccessOK and the last_looker possibly updated.  if the looker doesnt
change their access didnt change.  this does leak stat information but
only to a user whose credentials expire.  however, it allow dentries that
might be common paths to be "shared" safely among several users.

@sys is never cached.  @sys can be changed out of band so it always needs
to be checked.  you could go through all the dentries and drop the @sys
entries if the sysname changes (negative dentries would still be missed).

comments?

Index: src/afs/LINUX/osi_vnodeops.c
===================================================================
RCS file: /cvs/openafs/src/afs/LINUX/osi_vnodeops.c,v
retrieving revision 1.100
diff -u -u -r1.100 osi_vnodeops.c
--- src/afs/LINUX/osi_vnodeops.c	18 Apr 2005 14:28:05 -0000	1.100
+++ src/afs/LINUX/osi_vnodeops.c	24 Apr 2005 13:18:42 -0000
@@ -27,7 +27,6 @@
 #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,84 +864,76 @@
 afs_linux_dentry_revalidate(struct dentry *dp)
 #endif
 {
-    char *name = NULL;
-    cred_t *credp = crref();
+    cred_t *credp = NULL;
     struct vrequest treq;
-    struct vcache *lookupvcp = NULL;
-    int code, bad_dentry = 1;
-    struct sysname_info sysState;
+    int code, bad_dentry;
     struct vcache *vcp, *parentvcp;
 
-    sysState.allocked = 0;
-
 #ifdef AFS_LINUX24_ENV
     lock_kernel();
 #endif
     AFS_GLOCK();
 
     vcp = ITOAFS(dp->d_inode);
-    parentvcp = ITOAFS(dp->d_parent->d_inode);
+    parentvcp = 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 it is the AFS root, then there's no chance it needs 
-     * revalidating */
-    if (vcp == afs_globalVp) {
-	bad_dentry = 0;
+    /* If it's a negative dentry, it's never valid */
+    if (!vcp || !parentvcp) {
+	bad_dentry = 1;
 	goto done;
     }
 
-    if ((code = afs_InitReq(&treq, credp)))
+    /* If it's @sys, perhaps it has been changed */
+    if (!afs_ENameOK(dp->d_name.name)) {
+	bad_dentry = 10;
 	goto done;
+    }
 
-    Check_AtSys(parentvcp, dp->d_name.name, &sysState, &treq);
-    name = sysState.name;
+    /* If it's the AFS root no chance it needs revalidating */
+    if (vcp == afs_globalVp)
+	goto good_dentry;
 
-    /* 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;
+    /* Get a validated vcache entry */
+    credp = crref();
+    code = afs_InitReq(&treq, credp);
+    if (code) {
+	bad_dentry = 2;
+	goto done;
+    }
+    code = afs_VerifyVCache(vcp, &treq);
+    if (code) {
+	bad_dentry = 3;
 	goto done;
     }
 
-    /* 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 we aren't the last looker, verify access */
+    if (vcp->last_looker != treq.uid) {
+	if (!afs_AccessOK(vcp, (vType(vcp) == VREG) ? PRSFS_READ : PRSFS_LOOKUP, &treq, CHECK_MODE_BITS)) {
+	    bad_dentry = 5;
+	    goto done;
+	}
 
-    /* Verify that the dentry does not point to an old inode */
-    if (vcp != lookupvcp)
-	goto done;
+	vcp->last_looker = treq.uid;
+    }
 
+  good_dentry:
     bad_dentry = 0;
 
   done:
-    /* Clean up */
-    if (lookupvcp)
-	afs_PutVCache(lookupvcp);
-    if (sysState.allocked)
-	osi_FreeLargeSpace(name);
+    if (bad_dentry)
+	afs_Trace2(afs_iclSetp, CM_TRACE_BAD_DENTRY, ICL_TYPE_POINTER, dp->d_name.name, ICL_TYPE_INT32, bad_dentry);
 
+    /* Clean up */
     AFS_GUNLOCK();
-
     if (bad_dentry) {
 	shrink_dcache_parent(dp);
 	d_drop(dp);
     }
-
 #ifdef AFS_LINUX24_ENV
     unlock_kernel();
 #endif
-    crfree(credp);
+    if (credp)
+	crfree(credp);
 
     return !bad_dentry;
 }