Initial fakestat support (fake mountpoint directory attributes).
authorNickolai Zeldovich <kolya@mit.edu>
Tue, 2 Apr 2002 06:09:48 +0000 (06:09 +0000)
committerNickolai Zeldovich <kolya@mit.edu>
Tue, 2 Apr 2002 06:09:48 +0000 (06:09 +0000)
Useful for quickly stat'ing everything under /afs, for instance.
Reasonably tested on Solaris, and appears to work on Linux too.
Enable with 'afsd -fakestat'.

20 files changed:
NEWS
src/afs/LINUX/osi_vnodeops.c
src/afs/VNOPS/afs_vnop_access.c
src/afs/VNOPS/afs_vnop_attrs.c
src/afs/VNOPS/afs_vnop_create.c
src/afs/VNOPS/afs_vnop_dirops.c
src/afs/VNOPS/afs_vnop_flock.c
src/afs/VNOPS/afs_vnop_lookup.c
src/afs/VNOPS/afs_vnop_open.c
src/afs/VNOPS/afs_vnop_readdir.c
src/afs/VNOPS/afs_vnop_remove.c
src/afs/VNOPS/afs_vnop_rename.c
src/afs/VNOPS/afs_vnop_symlink.c
src/afs/VNOPS/afs_vnop_write.c
src/afs/afs.h
src/afs/afs_call.c
src/afs/afs_pioctl.c
src/afs/afs_vcache.c
src/afsd/afsd.c
src/config/afs_args.h

diff --git a/NEWS b/NEWS
index 535c528..53889d4 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,12 @@
 OpenAFS News -- history of user-visible changes. October 19, 2001
 
+* Changes incorporated in OpenAFS 1.3
+
+** Mountpoint directory information can be faked by the cache manager,
+   making operations such as stat'ing all cells under /afs much faster.
+   This is enabled by passing -fakestat to afsd, but might not be stable
+   on all platforms.
+
 * Changes incorporated in OpenAFS 1.2.3
 
 ** Cell aliases for dynroot can be specified in the CellAlias file in
index f9f5b0b..4c2fd2e 100644 (file)
@@ -261,6 +261,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 +273,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 +294,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;
     }
@@ -380,6 +391,7 @@ tagain:
     ReleaseReadLock(&tdc->lock);
     afs_PutDCache(tdc);
     ReleaseReadLock(&avc->lock);
+    afs_PutFakeStat(&fakestat);
     AFS_GUNLOCK();
     return 0;
 }
index e3c00a6..24912cb 100644 (file)
@@ -188,22 +188,32 @@ afs_access(OSI_VC_ARG(avc), amode, acred)
     struct AFS_UCRED *acred; {
     register afs_int32 code;
     struct vrequest treq;
+    struct afs_fakestat_state fakestate;
     OSI_VC_CONVERT(avc)
 
     AFS_STATCNT(afs_access);
     afs_Trace3(afs_iclSetp, CM_TRACE_ACCESS, ICL_TYPE_POINTER, avc, 
                ICL_TYPE_INT32, amode,
                ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
+    afs_InitFakeStat(&fakestate);
     if (code = afs_InitReq(&treq, acred)) return code;
 
+    code = afs_EvalFakeStat(&avc, &fakestate, &treq);
+    if (code) {
+       afs_PutFakeStat(&fakestate);
+       return code;
+    }
+
     code = afs_VerifyVCache(avc, &treq);
     if (code) {
+      afs_PutFakeStat(&fakestate);
       code = afs_CheckCode(code, &treq, 16);
       return code; 
     }
 
     /* if we're looking for write access and we have a read-only file system, report it */
     if ((amode & VWRITE) && (avc->states & CRO)) {
+       afs_PutFakeStat(&fakestate);
        return EROFS;
     }
     code = 1;          /* Default from here on in is access ok. */
@@ -270,11 +280,12 @@ afs_access(OSI_VC_ARG(avc), amode, acred)
               code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
        }
     }
-    if (code)
+    afs_PutFakeStat(&fakestate);
+    if (code) {
        return 0;               /* if access is ok */
-    else {
-      code = afs_CheckCode(EACCES, &treq, 17);      /* failure code */
-      return code;
+    } else {
+       code = afs_CheckCode(EACCES, &treq, 17);             /* failure code */
+       return code;
     }
 }
 
index f7de5fe..2d14805 100644 (file)
@@ -37,20 +37,24 @@ extern struct vcache *afs_globalVp;
 /* copy out attributes from cache entry */
 afs_CopyOutAttrs(avc, attrs)
     register struct vattr *attrs;
-    register struct vcache *avc; {
+    register struct vcache *avc;
+{
     register struct volume *tvp;
     register struct cell *tcell;
     register afs_int32 i;
+    int fakedir = 0;
 
     AFS_STATCNT(afs_CopyOutAttrs);
+    if (afs_fakestat_enable && avc->mvstat == 1)
+       fakedir = 1;
 #if    defined(AFS_MACH_ENV )
-    attrs->va_mode = vType(avc) | (avc->m.Mode&~VFMT);
+    attrs->va_mode = fakedir ? VDIR | 0755 : vType(avc) | (avc->m.Mode&~VFMT);
 #else /* AFS_MACH_ENV */
-    attrs->va_type = vType(avc);
+    attrs->va_type = fakedir ? VDIR : vType(avc);
 #if defined(AFS_SGI_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
-    attrs->va_mode = (mode_t)(avc->m.Mode & 0xffff);
+    attrs->va_mode = fakedir ? 0755 : (mode_t)(avc->m.Mode & 0xffff);
 #else
-    attrs->va_mode = avc->m.Mode;
+    attrs->va_mode = fakedir ? VDIR | 0755 : avc->m.Mode;
 #endif
 #endif /* AFS_MACH_ENV */
 
@@ -60,8 +64,8 @@ afs_CopyOutAttrs(avc, attrs)
        if (tcell && (tcell->states & CNoSUID))
            attrs->va_mode &= ~(VSUID|VSGID);
     }
-    attrs->va_uid = avc->m.Owner;
-    attrs->va_gid = avc->m.Group;   /* yeah! */
+    attrs->va_uid = fakedir ? 0 : avc->m.Owner;
+    attrs->va_gid = fakedir ? 0 : avc->m.Group;   /* yeah! */
 #if    defined(AFS_SUN56_ENV)
     attrs->va_fsid = avc->v.v_vfsp->vfs_fsid.val[0];
 #else
@@ -90,10 +94,10 @@ afs_CopyOutAttrs(avc, attrs)
     }
     else attrs->va_nodeid = avc->fid.Fid.Vnode + (avc->fid.Fid.Volume << 16);
     attrs->va_nodeid &= 0x7fffffff;    /* Saber C hates negative inode #s! */
-    attrs->va_nlink = avc->m.LinkCount;
-    attrs->va_size = avc->m.Length;
+    attrs->va_nlink = fakedir ? 100 : avc->m.LinkCount;
+    attrs->va_size = fakedir ? 4096 : avc->m.Length;
     attrs->va_atime.tv_sec = attrs->va_mtime.tv_sec = attrs->va_ctime.tv_sec =
-       avc->m.Date;
+       fakedir ? 0 : avc->m.Date;
     /* set microseconds to be dataversion # so that we approximate NFS-style
      * use of mtime as a dataversion #.  We take it mod 512K because
      * microseconds *must* be less than a million, and 512K is the biggest
@@ -203,6 +207,23 @@ afs_getattr(OSI_VC_ARG(avc), attrs, acred)
     afs_Trace2(afs_iclSetp, CM_TRACE_GETATTR, ICL_TYPE_POINTER, avc, 
               ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
 
+    if (afs_fakestat_enable && avc->mvstat == 1) {
+       struct afs_fakestat_state fakestat;
+
+       code = afs_InitReq(&treq, acred);
+       if (code) return code;
+       afs_InitFakeStat(&fakestat);
+       code = afs_TryEvalFakeStat(&avc, &fakestat, &treq);
+       if (code) {
+           afs_PutFakeStat(&fakestat);
+           return code;
+       }
+
+       code = afs_CopyOutAttrs(avc, attrs);
+       afs_PutFakeStat(&fakestat);
+       return code;
+    }
+
 #if defined(AFS_SUN5_ENV)
     if (flags & ATTR_HINT) {
        code = afs_CopyOutAttrs(avc, attrs);
@@ -403,12 +424,19 @@ afs_setattr(avc, attrs, acred)
     struct vrequest treq;
     struct AFSStoreStatus astat;
     register afs_int32 code;
+    struct afs_fakestat_state fakestate;
     OSI_VC_CONVERT(avc)
 
     AFS_STATCNT(afs_setattr);
     afs_Trace2(afs_iclSetp, CM_TRACE_SETATTR, ICL_TYPE_POINTER, avc, 
               ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
     if (code = afs_InitReq(&treq, acred)) return code;
+    afs_InitFakeStat(&fakestate);
+    code = afs_EvalFakeStat(&avc, &fakestate, &treq);
+    if (code)
+       goto done;
+
     if (avc->states & CRO) {
        code=EROFS;
        goto done;
@@ -528,6 +556,7 @@ afs_setattr(avc, attrs, acred)
     AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
 #endif
 done:
+    afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 15);
     return code;
 }
index a385ab8..8a78d63 100644 (file)
@@ -72,6 +72,7 @@ afs_create(OSI_VC_ARG(adp), aname, attrs, aexcl, amode, avcp, acred)
     struct server *hostp=0;
     struct vcache *tvc;
     struct volume*     volp = 0;
+    struct afs_fakestat_state fakestate;
     XSTATS_DECLS
     OSI_VC_CONVERT(adp)
 
@@ -83,6 +84,8 @@ afs_create(OSI_VC_ARG(adp), aname, attrs, aexcl, amode, avcp, acred)
     afs_Trace3(afs_iclSetp, CM_TRACE_CREATE, ICL_TYPE_POINTER, adp,
               ICL_TYPE_STRING, aname, ICL_TYPE_INT32, amode);
 
+    afs_InitFakeStat(&fakestate);
+
 #ifdef AFS_SGI65_ENV
     /* If avcp is passed not null, it's the old reference to this file.
      * We can use this to avoid create races. For now, just decrement
@@ -112,6 +115,8 @@ afs_create(OSI_VC_ARG(adp), aname, attrs, aexcl, amode, avcp, acred)
        code = EINVAL;          
        goto done;
     }
+    code = afs_EvalFakeStat(&adp, &fakestate, &treq);
+    if (code) goto done;
 tagain:
     code = afs_VerifyVCache(adp, &treq);
     if (code) goto done;
@@ -469,6 +474,7 @@ done:
        tvc->states |= CCore1;
 #endif
 
+    afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 20);
 
 done2:
index deac964..791e37f 100644 (file)
@@ -62,6 +62,7 @@ afs_mkdir(OSI_VC_ARG(adp), aname, attrs, avcp, acred)
     struct AFSCallBack CallBack;
     struct AFSVolSync tsync;
     afs_int32 now;
+    struct afs_fakestat_state fakestate;
     XSTATS_DECLS
     OSI_VC_CONVERT(adp)
 
@@ -71,6 +72,7 @@ afs_mkdir(OSI_VC_ARG(adp), aname, attrs, avcp, acred)
 
     if (code = afs_InitReq(&treq, acred)) 
        goto done2;
+    afs_InitFakeStat(&fakestate);
 
     if (strlen(aname) > AFSNAMEMAX) {
        code = ENAMETOOLONG;
@@ -81,6 +83,8 @@ afs_mkdir(OSI_VC_ARG(adp), aname, attrs, avcp, acred)
        code = EINVAL;
        goto done;
     }
+    code = afs_EvalFakeStat(&adp, &fakestate, &treq);
+    if (code) goto done;
     code = afs_VerifyVCache(adp, &treq);
     if (code) goto done;
 
@@ -159,6 +163,7 @@ afs_mkdir(OSI_VC_ARG(adp), aname, attrs, avcp, acred)
     }
     else code = ENOENT;
 done:
+    afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 26);
 done2:
 #ifdef AFS_OSF_ENV
@@ -194,6 +199,7 @@ afs_rmdir(adp, aname, acred)
     afs_size_t offset, len;
     struct AFSFetchStatus OutDirStatus;
     struct AFSVolSync tsync;
+    struct afs_fakestat_state fakestate;
     XSTATS_DECLS
     OSI_VC_CONVERT(adp)
 
@@ -202,14 +208,19 @@ afs_rmdir(adp, aname, acred)
     afs_Trace2(afs_iclSetp, CM_TRACE_RMDIR, ICL_TYPE_POINTER, adp, 
               ICL_TYPE_STRING, aname);
 
-    if (code = afs_InitReq(&treq, acred)) 
+    if (code = afs_InitReq(&treq, acred))
        goto done2;
+    afs_InitFakeStat(&fakestate);
 
     if (strlen(aname) > AFSNAMEMAX) {
        code = ENAMETOOLONG;
        goto done;
     }
 
+    code = afs_EvalFakeStat(&adp, &fakestate, &treq);
+    if (code)
+       goto done;
+
     code = afs_VerifyVCache(adp, &treq);
     if (code) goto done;
 
@@ -314,6 +325,7 @@ afs_rmdir(adp, aname, acred)
     code = 0;
 
 done:
+    afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 27); 
 done2:
 #ifdef AFS_OSF_ENV
index 7042b49..0782b3b 100644 (file)
@@ -503,11 +503,21 @@ struct AFS_UCRED *acred; {
 #ifdef AFS_OSF_ENV
     int acmd = 0;
 #endif
+    struct afs_fakestat_state fakestate;
 
     AFS_STATCNT(afs_lockctl);
     if (code = afs_InitReq(&treq, acred)) return code;
+    afs_InitFakeStat(&fakestate);
+    code = afs_EvalFakeStat(&fakestate, &avc, &treq);
+    if (code) {
+       afs_PutFakeStat(&fakestate);
+       return code;
+    }
 #ifdef AFS_OSF_ENV
-    if (flag & VNOFLCK)        return 0;
+    if (flag & VNOFLCK)        {
+       afs_PutFakeStat(&fakestate);
+       return 0;
+    }
     if (flag & CLNFLCK) {
        acmd = LOCK_UN;
     } else if ((flag & GETFLCK) || (flag & RGETFLCK)) {
@@ -521,12 +531,15 @@ struct AFS_UCRED *acred; {
 #else
     if (acmd == F_GETLK) {
 #endif
-       if (af->l_type == F_UNLCK)
+       if (af->l_type == F_UNLCK) {
+           afs_PutFakeStat(&fakestate);
            return 0;
+       }
 #ifndef        AFS_OSF_ENV     /* getlock is a no-op for osf (for now) */
        code = HandleGetLock(avc, af, &treq, clid);
 #endif
        code = afs_CheckCode(code, &treq, 2); /* defeat buggy AIX optimz */
+       afs_PutFakeStat(&fakestate);
        return code;
     }
     else if ((acmd == F_SETLK) || (acmd == F_SETLKW) 
@@ -554,13 +567,17 @@ struct AFS_UCRED *acred; {
           even when they should block */
        if (af->l_whence != 0 || af->l_start != 0 || af->l_len != 0) {
            DoLockWarning();
+           afs_PutFakeStat(&fakestate);
            return 0;
        }
        /* otherwise we can turn this into a whole-file flock */
        if (af->l_type == F_RDLCK) code = LOCK_SH;
        else if (af->l_type == F_WRLCK) code = LOCK_EX;
        else if (af->l_type == F_UNLCK) code = LOCK_UN;
-       else return EINVAL; /* unknown lock type */
+       else {
+           afs_PutFakeStat(&fakestate);
+           return EINVAL; /* unknown lock type */
+       }
        if (((acmd == F_SETLK) 
 #if    (defined(AFS_SGI_ENV) || defined(AFS_SUN_ENV)) && !defined(AFS_SUN58_ENV)
        || (acmd == F_RSETLK) 
@@ -579,8 +596,10 @@ struct AFS_UCRED *acred; {
 #endif
 #endif
        code = afs_CheckCode(code, &treq, 3); /* defeat AIX -O bug */
+       afs_PutFakeStat(&fakestate);
        return code;
     }
+    afs_PutFakeStat(&fakestate);
     return EINVAL;
 }
 
@@ -859,7 +878,9 @@ afs_xflock () {
     struct vrequest treq;
     struct vcache *tvc;
     int flockDone;
+    struct afs_fakestat_state fakestate;
 
+    afs_InitFakeStat(&fakestate);
     AFS_STATCNT(afs_xflock);
     flockDone = 0;
 #ifdef AFS_OSF_ENV
@@ -869,9 +890,15 @@ afs_xflock () {
     uap = (struct a *)u.u_ap;
     fd = getf(uap->fd);
 #endif
-    if (!fd) return;
+    if (!fd) {
+       afs_PutFakeStat(&fakestate);
+       return;
+    }
 
-    if (flockDone = afs_InitReq(&treq, u.u_cred)) return flockDone;
+    if (flockDone = afs_InitReq(&treq, u.u_cred)) {
+       afs_PutFakeStat(&fakestate);
+       return flockDone;
+    }
     /* first determine whether this is any sort of vnode */
     if (fd->f_type == DTYPE_VNODE) {
        /* good, this is a vnode; next see if it is an AFS vnode */
@@ -885,9 +912,15 @@ afs_xflock () {
            tvc = VTOAFS(afs_gntovn)(tvc);
            if (!tvc) {
                u.u_error = ENOENT;
+               afs_PutFakeStat(&fakestate);
                return;
            }
 #endif
+           code = afs_EvalFakeStat(&fakestate, &tvc, &treq);
+           if (code) {
+               afs_PutFakeStat(&fakestate);
+               return code;
+           }
            if ((fd->f_flag & (FEXLOCK | FSHLOCK)) && !(uap->com & LOCK_UN)) {
                /* First, if fd already has lock, release it for relock path */
 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV))
@@ -935,6 +968,7 @@ afs_xflock () {
 #else
     FP_UNREF(fd);
 #endif
+    afs_PutFakeStat(&fakestate);
     return code;
 #else  /* AFS_OSF_ENV */
     if (!flockDone)
@@ -943,6 +977,7 @@ afs_xflock () {
 #else
        flock();
 #endif
+    afs_PutFakeStat(&fakestate);
     return;
 #endif
 }
index 726a95d..e68974c 100644 (file)
@@ -54,6 +54,7 @@ extern struct inode_operations afs_symlink_iops, afs_dir_iops;
 
 afs_int32 afs_bulkStatsDone;
 static int bulkStatCounter = 0;        /* counter for bulk stat seq. numbers */
+int afs_fakestat_enable = 0;
 
 
 /* this would be faster if it did comparison as int32word, but would be 
@@ -90,8 +91,9 @@ char *afs_index(a, c)
 }
 
 /* call under write lock, evaluate mvid field from a mt pt.
- * avc is the vnode of the mount point object.
- * advc is the vnode of the containing directory
+ * avc is the vnode of the mount point object; must be write-locked.
+ * advc is the vnode of the containing directory (optional; if NULL and
+ *   EvalMountPoint succeeds, caller must initialize *avolpp->dotdot)
  * avolpp is where we return a pointer to the volume named by the mount pt, if success
  * areq is the identity of the caller.
  *
@@ -231,11 +233,159 @@ EvalMountPoint(avc, advc, avolpp, areq)
      * to the new path.
      */
     tvp->mtpoint = avc->fid;   /* setup back pointer to mtpoint */
-    tvp->dotdot  = advc->fid;
+    if (advc) tvp->dotdot  = advc->fid;
 
     *avolpp = tvp;
     return 0;
 }
+
+/*
+ * afs_InitFakeStat
+ *
+ * Must be called on an afs_fakestat_state object before calling
+ * afs_EvalFakeStat or afs_PutFakeStat.  Calling afS_PutFakeStat
+ * without calling afs_EvalFakeStat is legal, as long as this
+ * function is called.
+ */
+
+void
+afs_InitFakeStat(state)
+    struct afs_fakestat_state *state;
+{
+    state->valid = 1;
+    state->did_eval = 0;
+    state->need_release = 0;
+    state->nonblock = 0;
+}
+
+/*
+ * afs_EvalFakeStat
+ *
+ * Automatically does the equivalent of EvalMountPoint for vcache entries
+ * which are mount points.  Remembers enough state to properly release
+ * the volume root vcache when afs_PutFakeStat() is called.
+ *
+ * State variable must be initialized by afs_InitFakeState() beforehand.
+ *
+ * Returns 0 when everything succeeds and *avcp points to the vcache entry
+ * that should be used for the real vnode operation.  Returns non-zero if
+ * something goes wrong and the error code should be returned to the user.
+ */
+int
+afs_EvalFakeStat(avcp, state, areq)
+    struct vcache **avcp;
+    struct afs_fakestat_state *state;
+    struct vrequest *areq;
+{
+    struct vcache *tvc, *root_vp;
+    struct volume *tvolp = NULL;
+    int code = 0;
+
+    osi_Assert(state->valid == 1);
+    osi_Assert(state->did_eval == 0);
+    state->did_eval = 1;
+    if (!afs_fakestat_enable)
+       return 0;
+    tvc = *avcp;
+    if (tvc->mvstat != 1)
+       return 0;
+
+    /* Is the call to VerifyVCache really necessary? */
+    code = afs_VerifyVCache(tvc, areq);
+    if (code)
+       goto done;
+    if (!state->nonblock) {
+       ObtainWriteLock(&tvc->lock, 599);
+       code = EvalMountPoint(tvc, NULL, &tvolp, areq);
+       ReleaseWriteLock(&tvc->lock);
+       if (code)
+           goto done;
+       if (tvolp) {
+           tvolp->dotdot = tvc->fid;
+           tvolp->dotdot.Fid.Vnode = tvc->parentVnode;
+           tvolp->dotdot.Fid.Unique = tvc->parentUnique;
+       }
+    }
+    if (tvc->mvid && (tvc->states & CMValid)) {
+       if (state->nonblock) {
+           afs_int32 retry;
+
+           do {
+               retry = 0;
+               ObtainWriteLock(&afs_xvcache, 597);
+               root_vp = afs_FindVCache(tvc->mvid, 0, 0, &retry, 0);
+               if (root_vp && retry) {
+                   ReleaseWriteLock(&afs_xvcache);
+                   afs_PutVCache(root_vp, 0);
+               }
+           } while (root_vp && retry);
+           ReleaseWriteLock(&afs_xvcache);
+       } else {
+           root_vp = afs_GetVCache(tvc->mvid, areq, NULL, NULL, WRITE_LOCK);
+       }
+       if (!root_vp) {
+           code = state->nonblock ? 0 : ENOENT;
+           goto done;
+       }
+       if (tvolp) {
+           /* Is this always kosher?  Perhaps we should instead use
+            * NBObtainWriteLock to avoid potential deadlock.
+            */
+           ObtainWriteLock(&root_vp->lock, 598);
+           if (!root_vp->mvid)
+               root_vp->mvid = osi_AllocSmallSpace(sizeof(struct VenusFid));
+           *root_vp->mvid = tvolp->dotdot;
+           ReleaseWriteLock(&root_vp->lock);
+       }
+       state->need_release = 1;
+       state->root_vp = root_vp;
+       *avcp = root_vp;
+       code = 0;
+    } else {
+       code = state->nonblock ? 0 : ENOENT;
+    }
+
+done:
+    if (tvolp)
+       afs_PutVolume(tvolp, WRITE_LOCK);
+    return code;
+}
+
+/*
+ * afs_TryEvalFakeStat
+ *
+ * Same as afs_EvalFakeStat, but tries not to talk to remote servers
+ * and only evaluate the mount point if all the data is already in
+ * local caches.
+ *
+ * Returns 0 if everything succeeds and *avcp points to a valid
+ * vcache entry (possibly evaluated).
+ */
+int
+afs_TryEvalFakeStat(avcp, state, areq)
+    struct vcache **avcp;
+    struct afs_fakestat_state *state;
+    struct vrequest *areq;
+{
+    state->nonblock = 1;
+    return afs_EvalFakeStat(avcp, state, areq);
+}
+
+/*
+ * afs_PutFakeStat
+ *
+ * Perform any necessary cleanup at the end of a vnode op, given that
+ * afs_InitFakeStat was previously called with this state.
+ */
+void
+afs_PutFakeStat(state)
+    struct afs_fakestat_state *state;
+{
+    osi_Assert(state->valid == 1);
+    if (state->need_release)
+       afs_PutVCache(state->root_vp, 0);
+    state->valid = 0;
+}
     
 afs_ENameOK(aname)
     register char *aname; {
@@ -932,8 +1082,17 @@ afs_lookup(adp, aname, avcp, acred)
     int no_read_access = 0;
     struct sysname_info sysState;   /* used only for @sys checking */
     int dynrootRetry = 1;
+    struct afs_fakestat_state fakestate;
 
     AFS_STATCNT(afs_lookup);
+    afs_InitFakeStat(&fakestate);
+
+    if (code = afs_InitReq(&treq, acred))
+       goto done;
+
+    code = afs_EvalFakeStat(&adp, &fakestate, &treq);
+    if (code)
+       goto done;
 #ifdef AFS_OSF_ENV
     ndp->ni_dvp = AFSTOV(adp);
     memcpy(aname, ndp->ni_ptr, ndp->ni_namelen);
@@ -942,10 +1101,6 @@ afs_lookup(adp, aname, avcp, acred)
 
     *avcp = (struct vcache *) 0;   /* Since some callers don't initialize it */
 
-    if (code = afs_InitReq(&treq, acred)) { 
-       goto done;
-    }
-
     /* come back to here if we encounter a non-existent object in a read-only
        volume's directory */
 
@@ -1232,9 +1387,9 @@ afs_lookup(adp, aname, avcp, acred)
         if (!(flags & AFS_LOOKUP_NOEVAL))
           /* don't eval mount points */
 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
-       if (tvc->mvstat == 1) {
-         /* a mt point, possibly unevaluated */
-         struct volume *tvolp;
+       if (!afs_fakestat_enable && tvc->mvstat == 1) {
+           /* a mt point, possibly unevaluated */
+           struct volume *tvolp;
 
            ObtainWriteLock(&tvc->lock,133);
            code = EvalMountPoint(tvc, adp, &tvolp, &treq);
@@ -1334,6 +1489,7 @@ done:
            if (!FidCmp(&(tvc->fid), &(adp->fid))) { 
                afs_PutVCache(*avcp, WRITE_LOCK);
                *avcp = NULL;
+               afs_PutFakeStat(&fakestate);
                return afs_CheckCode(EISDIR, &treq, 18);
            }
        }
@@ -1357,6 +1513,7 @@ done:
            /* So Linux inode cache is up to date. */
            code = afs_VerifyVCache(tvc, &treq);
 #else
+           afs_PutFakeStat(&fakestate);
            return 0;  /* can't have been any errors if hit and !code */
 #endif
        }
@@ -1370,5 +1527,6 @@ done:
        *avcp = (struct vcache *)0;
     }
 
+    afs_PutFakeStat(&fakestate);
     return code;
 }
index d883e46..2ab022f 100644 (file)
@@ -44,8 +44,9 @@ afs_open(avcp, aflags, acred)
 {
     register afs_int32 code;
     struct vrequest treq;
-    register struct vcache *tvc;
+    struct vcache *tvc;
     int writing;
+    struct afs_fakestat_state fakestate;
     
     AFS_STATCNT(afs_open);
     if (code = afs_InitReq(&treq, acred)) return code;
@@ -57,6 +58,9 @@ afs_open(avcp, aflags, acred)
 #endif
     afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc,
               ICL_TYPE_INT32, aflags);
+    afs_InitFakeStat(&fakestate);
+    code = afs_EvalFakeStat(&tvc, &fakestate, &treq);
+    if (code) goto done;
     code = afs_VerifyVCache(tvc, &treq);
     if (code) goto done;
     if (aflags & (FWRITE | FTRUNC)) writing = 1;
@@ -143,6 +147,7 @@ afs_open(avcp, aflags, acred)
 #endif
     ReleaseReadLock(&tvc->lock);
 done:
+    afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 4); /* avoid AIX -O bug */
 
     afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc,
index 71b86fe..1b70fd7 100644 (file)
@@ -483,6 +483,7 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
     struct DirEntry *ode = 0, *nde = 0;
     int o_slen = 0, n_slen = 0;
     afs_uint32 us;
+    struct afs_fakestat_state fakestate;
 #if defined(AFS_SGI53_ENV)
     afs_int32 use64BitDirent;
 #endif /* defined(AFS_SGI53_ENV) */
@@ -535,6 +536,9 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
        return code;
     }
     /* update the cache entry */
+    afs_InitFakeStat(&fakestate);
+    code = afs_EvalFakeStat(&avc, &fakestate, &treq);
+    if (code) goto done;
 tagain:
     code = afs_VerifyVCache(avc, &treq);
     if (code) goto done;
@@ -779,6 +783,7 @@ done:
 #ifdef AFS_HPUX_ENV
     osi_FreeSmallSpace((char *)sdirEntry);
 #endif
+    afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 28);
     return code;
 }
@@ -809,6 +814,7 @@ afs1_readdir(avc, auio, acred)
     struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
     afs_int32 rlen;
 #endif
+    struct afs_fakestat_state fakestate;
 
     AFS_STATCNT(afs_readdir);
 #if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
@@ -820,6 +826,15 @@ afs1_readdir(avc, auio, acred)
 #endif
        return code;
     }
+    afs_InitFakeStat(&fakestate);
+    code = afs_EvalFakeStat(&fakestate, &avc, &treq);
+    if (code) {
+#ifdef AFS_HPUX_ENV
+       osi_FreeSmallSpace((char *)sdirEntry);
+#endif
+       afs_PutFakeStat(&fakestate);
+       return code;
+    }
     /* update the cache entry */
 tagain:
     code = afs_VerifyVCache(avc, &treq);
@@ -1014,6 +1029,7 @@ done:
 #if    defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
     osi_FreeSmallSpace((char *)sdirEntry);
 #endif
+    afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 29);
     return code;
 }
index 1ad449c..0fac0e4 100644 (file)
@@ -230,6 +230,7 @@ afs_remove(OSI_VC_ARG(adp), aname, acred)
     afs_size_t offset, len;
     struct AFSFetchStatus OutDirStatus;
     struct AFSVolSync tsync;
+    struct afs_fakestat_state fakestate;
     XSTATS_DECLS
     OSI_VC_CONVERT(adp)
 
@@ -241,23 +242,37 @@ afs_remove(OSI_VC_ARG(adp), aname, acred)
     tvc = (struct vcache *)ndp->ni_vp;  /* should never be null */
 #endif
 
-    /* Check if this is dynroot */
-    if (afs_IsDynroot(adp)) {
+    if (code = afs_InitReq(&treq, acred)) {
 #ifdef  AFS_OSF_ENV
-        afs_PutVCache(adp, 0);
-        afs_PutVCache(tvc, 0);
+       afs_PutVCache(adp, 0);
+       afs_PutVCache(tvc, 0);
 #endif
-       return afs_DynrootVOPRemove(adp, acred, aname);
+       return code;
     }
 
-    if (code = afs_InitReq(&treq, acred)) {
+    afs_InitFakeStat(&fakestate);
+    code = afs_EvalFakeStat(&adp, &fakestate, &treq);
+    if (code) {
+       afs_PutFakeStat(&fakestate);
 #ifdef  AFS_OSF_ENV
-        afs_PutVCache(adp, 0);
-        afs_PutVCache(tvc, 0);
+       afs_PutVCache(adp, 0);
+       afs_PutVCache(tvc, 0);
+#endif
+       return code;
+    }
+
+    /* Check if this is dynroot */
+    if (afs_IsDynroot(adp)) {
+       code = afs_DynrootVOPRemove(adp, acred, aname);
+       afs_PutFakeStat(&fakestate);
+#ifdef  AFS_OSF_ENV
+       afs_PutVCache(adp, 0);
+       afs_PutVCache(tvc, 0);
 #endif
-      return code;
+       return code;
     }
     if (strlen(aname) > AFSNAMEMAX) {
+       afs_PutFakeStat(&fakestate);
 #ifdef  AFS_OSF_ENV
        afs_PutVCache(adp, 0);
        afs_PutVCache(tvc, 0);
@@ -271,13 +286,15 @@ tagain:
     if (code) {
        afs_PutVCache(adp, 0);
        afs_PutVCache(tvc, 0);
+       afs_PutFakeStat(&fakestate);
        return afs_CheckCode(code, &treq, 22);
     }
 #else  /* AFS_OSF_ENV */
     tvc = (struct vcache *) 0;
     if (code) {
-      code = afs_CheckCode(code, &treq, 23);
-      return code;
+       code = afs_CheckCode(code, &treq, 23);
+       afs_PutFakeStat(&fakestate);
+       return code;
     }
 #endif
 
@@ -290,6 +307,7 @@ tagain:
         afs_PutVCache(tvc, 0);
 #endif
         code = EROFS;
+       afs_PutFakeStat(&fakestate);
        return code;
     }
 
@@ -386,6 +404,7 @@ tagain:
 #ifdef AFS_OSF_ENV
     afs_PutVCache(adp, WRITE_LOCK);
 #endif /* AFS_OSF_ENV */
+    afs_PutFakeStat(&fakestate);
     return code;
 }
 
index c8e81e0..ad62563 100644 (file)
@@ -31,11 +31,12 @@ extern afs_rwlock_t afs_xcbhash;
 /* Note that we don't set CDirty here, this is OK because the rename
  * RPC is called synchronously. */
 
-afsrename(aodp, aname1, andp, aname2, acred)
-    register struct vcache *aodp, *andp;
+afsrename(aodp, aname1, andp, aname2, acred, areq)
+    struct vcache *aodp, *andp;
     char *aname1, *aname2;
-    struct AFS_UCRED *acred; {
-    struct vrequest treq;
+    struct AFS_UCRED *acred;
+    struct vrequest *areq;
+{
     register struct conn *tc;
     register afs_int32 code;
     afs_int32 returnCode;
@@ -53,8 +54,6 @@ afsrename(aodp, aname1, andp, aname2, acred)
               ICL_TYPE_STRING, aname1, ICL_TYPE_POINTER, andp,
               ICL_TYPE_STRING, aname2);
 
-    if (code = afs_InitReq(&treq, acred)) return code;
-
     if (strlen(aname1) > AFSNAMEMAX || strlen(aname2) > AFSNAMEMAX) {
        code = ENAMETOOLONG;
        goto done;
@@ -62,9 +61,9 @@ afsrename(aodp, aname1, andp, aname2, acred)
 
     /* verify the latest versions of the stat cache entries */
 tagain:
-    code = afs_VerifyVCache(aodp, &treq);
+    code = afs_VerifyVCache(aodp, areq);
     if (code) goto done;
-    code = afs_VerifyVCache(andp, &treq);
+    code = afs_VerifyVCache(andp, areq);
     if (code) goto done;
     
     /* lock in appropriate order, after some checks */
@@ -83,7 +82,7 @@ tagain:
            goto done;
        }
        ObtainWriteLock(&andp->lock,147);
-       tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, &treq, &offset, &len, 0);
+       tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
        if (!tdc1) {
            code = ENOENT;
        } else {
@@ -101,7 +100,7 @@ tagain:
        ObtainWriteLock(&aodp->lock,149);
        tdc2 = afs_FindDCache(andp, 0);
        if (tdc2) ObtainWriteLock(&tdc2->lock, 644);
-       tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, &treq, &offset, &len, 0);
+       tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
        if (tdc1)
            ObtainWriteLock(&tdc1->lock, 645);
        else
@@ -110,7 +109,7 @@ tagain:
     else {
        ObtainWriteLock(&aodp->lock,150);       /* lock smaller one first */
        ObtainWriteLock(&andp->lock,557);
-       tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, &treq, &offset, &len, 0);
+       tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
        if (tdc1)
            ObtainWriteLock(&tdc1->lock, 646);
        else
@@ -166,7 +165,7 @@ tagain:
 
     /* locks are now set, proceed to do the real work */
     do {
-       tc = afs_Conn(&aodp->fid, &treq, SHARED_LOCK);
+       tc = afs_Conn(&aodp->fid, areq, SHARED_LOCK);
        if (tc) {
           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RENAME);
 #ifdef RX_ENABLE_LOCKS
@@ -182,7 +181,7 @@ tagain:
        } else code = -1;
 
     } while
-       (afs_Analyze(tc, code, &andp->fid, &treq,
+       (afs_Analyze(tc, code, &andp->fid, areq,
                     AFS_STATS_FS_RPCIDX_RENAME, SHARED_LOCK, (struct cell *)0));
 
     returnCode = code;     /* remember for later */
@@ -296,11 +295,11 @@ tagain:
        unlinkFid.Cell = aodp->fid.Cell;
        tvc = (struct vcache *)0;
        if (!unlinkFid.Fid.Unique) {
-           tvc = afs_LookupVCache(&unlinkFid, &treq, (afs_int32 *)0, WRITE_LOCK,
+           tvc = afs_LookupVCache(&unlinkFid, areq, (afs_int32 *)0, WRITE_LOCK,
                                   aodp, aname1);
        }
        if (!tvc) /* lookup failed or wasn't called */
-          tvc = afs_GetVCache(&unlinkFid, &treq, (afs_int32 *)0,
+          tvc = afs_GetVCache(&unlinkFid, areq, (afs_int32 *)0,
                               (struct vcache*)0, WRITE_LOCK);
 
        if (tvc) {
@@ -334,9 +333,9 @@ tagain:
        fileFid.Fid.Volume = aodp->fid.Fid.Volume;
        fileFid.Cell = aodp->fid.Cell;
        if (!fileFid.Fid.Unique)
-           tvc = afs_LookupVCache(&fileFid, &treq, (afs_int32 *)0, WRITE_LOCK, andp, aname2);
+           tvc = afs_LookupVCache(&fileFid, areq, (afs_int32 *)0, WRITE_LOCK, andp, aname2);
        else
-           tvc = afs_GetVCache(&fileFid, &treq, (afs_int32 *)0,
+           tvc = afs_GetVCache(&fileFid, areq, (afs_int32 *)0,
                                (struct vcache*)0, WRITE_LOCK);
        if (tvc && (vType(tvc) == VDIR)) {
            ObtainWriteLock(&tvc->lock,152);
@@ -360,16 +359,15 @@ tagain:
     }
     code = returnCode;
 done:
-    code = afs_CheckCode(code, &treq, 25);
     return code;
 }
 
 #ifdef AFS_OSF_ENV
 afs_rename(fndp, tndp)
     struct nameidata *fndp, *tndp; {
-    register struct vcache *aodp = VTOAFS(fndp->ni_dvp);
+    struct vcache *aodp = VTOAFS(fndp->ni_dvp);
     char *aname1 = fndp->ni_dent.d_name;
-    register struct vcache *andp = VTOAFS(tndp->ni_dvp);
+    struct vcache *andp = VTOAFS(tndp->ni_dvp);
     char *aname2 = tndp->ni_dent.d_name;
     struct ucred *acred = tndp->ni_cred;
 #else  /* AFS_OSF_ENV */
@@ -380,14 +378,28 @@ afs_rename(OSI_VC_ARG(aodp), aname1, andp, aname2, npnp, acred)
 afs_rename(OSI_VC_ARG(aodp), aname1, andp, aname2, acred)
 #endif
     OSI_VC_DECL(aodp);
-    register struct vcache *andp;
+    struct vcache *andp;
     char *aname1, *aname2;
     struct AFS_UCRED *acred; {
 #endif
     register afs_int32 code;
+    struct afs_fakestat_state ofakestate;
+    struct afs_fakestat_state nfakestate;
+    struct vrequest treq;
     OSI_VC_CONVERT(aodp)
 
-    code = afsrename(aodp, aname1, andp, aname2, acred);
+    code = afs_InitReq(&treq, acred);
+    if (code) return code;
+    afs_InitFakeStat(&ofakestate);
+    afs_InitFakeStat(&nfakestate);
+    code = afs_EvalFakeStat(&aodp, &ofakestate, &treq);
+    if (code) goto done;
+    code = afs_EvalFakeStat(&andp, &nfakestate, &treq);
+    if (code) goto done;
+    code = afsrename(aodp, aname1, andp, aname2, acred, &treq);
+done:
+    afs_PutFakeStat(&ofakestate);
+    afs_PutFakeStat(&nfakestate);
 #ifdef AFS_OSF_ENV
     AFS_RELE(tndp->ni_dvp);
     if (tndp->ni_vp != NULL) {
@@ -396,5 +408,6 @@ afs_rename(OSI_VC_ARG(aodp), aname1, andp, aname2, acred)
     AFS_RELE(fndp->ni_dvp);
     AFS_RELE(fndp->ni_vp);
 #endif /* AFS_OSF_ENV */
+    code = afs_CheckCode(code, &treq, 25);
     return code;
 }
index fe6a32b..d626f30 100644 (file)
@@ -72,6 +72,7 @@ afs_symlink
     struct AFSCallBack CallBack;
     struct AFSVolSync tsync;
     struct volume*    volp=0;
+    struct afs_fakestat_state fakestate;
     XSTATS_DECLS
     OSI_VC_CONVERT(adp)
     
@@ -79,23 +80,28 @@ afs_symlink
     afs_Trace2(afs_iclSetp, CM_TRACE_SYMLINK, ICL_TYPE_POINTER, adp,
                 ICL_TYPE_STRING, aname);
 
+    if (code = afs_InitReq(&treq, acred))
+       goto done2;
+
+    afs_InitFakeStat(&fakestate);
+    code = afs_EvalFakeStat(&adp, &fakestate, &treq);
+    if (code)
+       goto done;
+
     if (strlen(aname) > AFSNAMEMAX || strlen(atargetName) > AFSPATHMAX) {
        code = ENAMETOOLONG;
-       goto done2;
+       goto done;
     }
 
     if (afs_IsDynroot(adp)) {
        code = afs_DynrootVOPSymlink(adp, acred, aname, atargetName);
-       goto done2;
+       goto done;
     }
 
-    if (code = afs_InitReq(&treq, acred))
-       goto done2;
-
     code = afs_VerifyVCache(adp, &treq);
     if (code) { 
-      code = afs_CheckCode(code, &treq, 30);
-      goto done2;
+       code = afs_CheckCode(code, &treq, 30);
+       goto done;
     }
 
     /** If the volume is read-only, return error without making an RPC to the
@@ -103,7 +109,7 @@ afs_symlink
       */
     if ( adp->states & CRO ) {
         code = EROFS;
-       goto done2;
+       goto done;
     }
 
     InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE;
@@ -223,6 +229,7 @@ afs_symlink
     afs_PutVCache(tvc, WRITE_LOCK);
     code = 0;
 done:
+    afs_PutFakeStat(&fakestate);
     if ( volp ) 
        afs_PutVolume(volp, READ_LOCK);
     code = afs_CheckCode(code, &treq, 31);
@@ -342,11 +349,15 @@ afs_readlink(OSI_VC_ARG(avc), auio, acred)
     register afs_int32 code;
     struct vrequest treq;
     register char *tp;
+    struct afs_fakestat_state fakestat;
     OSI_VC_CONVERT(avc)
 
     AFS_STATCNT(afs_readlink);
     afs_Trace1(afs_iclSetp, CM_TRACE_READLINK, ICL_TYPE_POINTER, avc);
     if (code = afs_InitReq(&treq, acred)) return code;
+    afs_InitFakeStat(&fakestat);
+    code = afs_EvalFakeStat(&avc, &fakestat, &treq);
+    if (code) goto done;
     code = afs_VerifyVCache(avc, &treq);
     if (code) goto done;
     if (vType(avc) != VLNK) {
@@ -365,6 +376,7 @@ afs_readlink(OSI_VC_ARG(avc), auio, acred)
     }
     ReleaseWriteLock(&avc->lock);
 done:
+    afs_PutFakeStat(&fakestat);
     code = afs_CheckCode(code, &treq, 32);
     return code;
 }
index 2a97d4a..f5b208e 100644 (file)
@@ -725,10 +725,12 @@ afs_closex(afd)
     afs_int32 flags;
     int closeDone;
     afs_int32 code = 0;
+    struct afs_fakestat_state fakestat;
 
     AFS_STATCNT(afs_closex);
     /* setup the credentials */
     if (code = afs_InitReq(&treq, u.u_cred)) return code;
+    afs_InitFakeStat(&fakestat);
 
     closeDone = 0;
     /* we're the last one.  If we're an AFS vnode, clear the flags,
@@ -737,6 +739,11 @@ afs_closex(afd)
     if (afd->f_type == DTYPE_VNODE) {
        tvc = VTOAFS(afd->f_data);
        if (IsAfsVnode(AFSTOV(tvc))) {
+           code = afs_EvalFakeStat(&tvc, &fakestat, &treq);
+           if (code) {
+               afs_PutFakeStat(&fakestat);
+               return code;
+           }
            VN_HOLD(AFSTOV(tvc));
            flags = afd->f_flag & (FSHLOCK | FEXLOCK);
            afd->f_flag &= ~(FSHLOCK | FEXLOCK);
@@ -760,6 +767,7 @@ afs_closex(afd)
     if (!closeDone) {
        code = vno_close(afd);
     }
+    afs_PutFakeStat(&fakestat);
     return code;       /* return code from vnode layer */
 }
 #endif
@@ -800,41 +808,44 @@ afs_close(OSI_VC_ARG(avc), aflags, acred)
     afs_int32 aflags;
     struct AFS_UCRED *acred; 
 {
-    register afs_int32 code, initreq=0;
+    register afs_int32 code;
     register struct brequest *tb;
     struct vrequest treq;
 #ifdef AFS_SGI65_ENV
     struct flid flid;
 #endif
+    struct afs_fakestat_state fakestat;
     OSI_VC_CONVERT(avc)
 
     AFS_STATCNT(afs_close);
     afs_Trace2(afs_iclSetp, CM_TRACE_CLOSE, ICL_TYPE_POINTER, avc,
               ICL_TYPE_INT32, aflags);
+    code = afs_InitReq(&treq, acred);
+    if (code) return code;
+    afs_InitFakeStat(&fakestat);
+    code = afs_EvalFakeStat(&avc, &fakestat, &treq);
+    if (code) {
+       afs_PutFakeStat(&fakestat);
+       return code;
+    }
 #ifdef AFS_SUN5_ENV
     if (avc->flockCount) {
-       if (code = afs_InitReq(&treq, acred)) return code;
-       initreq = 1;
        HandleFlock(avc, LOCK_UN, &treq, 0, 1/*onlymine*/);
     }
 #endif
 #if defined(AFS_SGI_ENV)
-    if (!lastclose)
+    if (!lastclose) {
+       afs_PutFakeStat(&fakestat);
        return 0;
+    }
 #else
 #if    defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV)
     if (count > 1) {
        /* The vfs layer may call this repeatedly with higher "count"; only on the last close (i.e. count = 1) we should actually proceed with the close. */
+       afs_PutFakeStat(&fakestat);
        return 0;
     }
 #endif
-#ifdef AFS_SUN5_ENV
-    if (!initreq) {
-#endif
-#endif
-       if (code = afs_InitReq(&treq, acred)) return code;
-#ifdef AFS_SUN5_ENV
-    }
 #endif
 #ifndef        AFS_SUN5_ENV
 #if defined(AFS_SGI_ENV)
@@ -957,6 +968,7 @@ afs_close(OSI_VC_ARG(avc), aflags, acred)
        afs_remunlink(avc, 1);  /* ignore any return code */
     }
 #endif
+    afs_PutFakeStat(&fakestat);
     code = afs_CheckCode(code, &treq, 5);
     return code;
 }
index 33e861b..3deb835 100644 (file)
@@ -627,7 +627,7 @@ struct vcache {
 #ifdef AFS_FBSD_ENV
     struct lock      rwlock;
 #endif
-    afs_int32 parentVnode;                     /* Parent dir, if a file. */
+    afs_int32 parentVnode;             /* Parent dir, if a file. */
     afs_int32 parentUnique;
     struct VenusFid *mvid;             /* Either parent dir (if root) or root (if mt pt) */
     char *linkData;                    /* Link data if a symlink. */
@@ -1181,5 +1181,18 @@ extern int afs_norefpanic;
 #endif /* AFS_SGI62_ENV */
 #endif
 
+/* fakestat support: opaque storage for afs_EvalFakeStat to remember
+ * what vcache should be released.
+ */
+struct afs_fakestat_state {
+    char valid;
+    char did_eval;
+    char need_release;
+    char nonblock;
+    struct vcache *root_vp;
+};
+
+extern int afs_fakestat_enable;
+
 #endif /* _AFS_H_ */
 
index 4f59f94..06db6f3 100644 (file)
@@ -662,6 +662,10 @@ long parm, parm2, parm3, parm4, parm5, parm6;
     else if (parm == AFSOP_SET_DYNROOT) {
        code = afs_SetDynrootEnable(parm2);
     }
+    else if (parm == AFSOP_SET_FAKESTAT) {
+       afs_fakestat_enable = parm2;
+       code = 0;
+    }
     else
       code = EINVAL;
 
index ee43ba6..4266d75 100644 (file)
@@ -1036,7 +1036,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
   
   
 afs_HandlePioctl(avc, acom, ablob, afollow, acred)
-     register struct vcache *avc;
+     struct vcache *avc;
      afs_int32 acom;
      struct AFS_UCRED **acred;
      register struct afs_ioctl *ablob;
@@ -1049,11 +1049,20 @@ afs_HandlePioctl(avc, acom, ablob, afollow, acred)
     char *inData, *outData;
     int (*(*pioctlSw))();
     int pioctlSwSize;
+    struct afs_fakestat_state fakestate;
 
     afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
               ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
     AFS_STATCNT(HandlePioctl);
     if (code = afs_InitReq(&treq, *acred)) return code;
+    afs_InitFakeStat(&fakestate);
+    if (avc) {
+       code = afs_EvalFakeStat(&avc, &fakestate, &treq);
+       if (code) {
+           afs_PutFakeStat(&fakestate);
+           return code;
+       }
+    }
     device = (acom & 0xff00) >> 8;
     switch (device) {
        case 'V':       /* Original pioctl's */
@@ -1065,11 +1074,13 @@ afs_HandlePioctl(avc, acom, ablob, afollow, acred)
                pioctlSwSize = sizeof(CpioctlSw);
                break;
        default:
+               afs_PutFakeStat(&fakestate);
                return EINVAL;
     }
     function = acom & 0xff;
     if (function >= (pioctlSwSize / sizeof(char *))) {
-      return EINVAL;   /* out of range */
+       afs_PutFakeStat(&fakestate);
+       return EINVAL;  /* out of range */
     }
     inSize = ablob->in_size;
     if (inSize >= PIGGYSIZE) return E2BIG;
@@ -1079,8 +1090,9 @@ afs_HandlePioctl(avc, acom, ablob, afollow, acred)
     }
     else code = 0;
     if (code) {
-      osi_FreeLargeSpace(inData);
-      return code;
+       osi_FreeLargeSpace(inData);
+       afs_PutFakeStat(&fakestate);
+       return code;
     }
     outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
     outSize = 0;
@@ -1096,6 +1108,7 @@ afs_HandlePioctl(avc, acom, ablob, afollow, acred)
        AFS_COPYOUT(outData, ablob->out, outSize, code);
     }
     osi_FreeLargeSpace(outData);
+    afs_PutFakeStat(&fakestate);
     return afs_CheckCode(code, &treq, 41);
   }
   
@@ -1719,7 +1732,7 @@ static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
        code = ENOENT;
        goto out;
     }
-    if (vType(tvc) != VLNK) {
+    if (tvc->mvstat != 1) {
        afs_PutVCache(tvc, WRITE_LOCK);
        code = EINVAL;
        goto out;
@@ -2504,7 +2517,7 @@ static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
        afs_PutDCache(tdc);
        goto out;
     }
-    if (vType(tvc) != VLNK) {
+    if (tvc->mvstat != 1) {
        afs_PutDCache(tdc);
        afs_PutVCache(tvc, WRITE_LOCK);
        code = EINVAL;
@@ -3703,7 +3716,7 @@ static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
        code = ENOENT;
        goto out;
     }
-    if (vType(tvc) != VLNK) {
+    if (tvc->mvstat != 1) {
        afs_PutVCache(tvc, WRITE_LOCK);
        code = EINVAL;
        goto out;
index 13e91ab..c3189e0 100644 (file)
@@ -1542,9 +1542,16 @@ afs_ProcessFS(avc, astat, areq)
        avc->m.Mode |= S_IFDIR;
     }
     else if (astat->FileType == SymbolicLink) {
-       vSetType(avc, VLNK);
-       avc->m.Mode |= S_IFLNK;
-       if ((avc->m.Mode & 0111) == 0) avc->mvstat = 1;
+       if (afs_fakestat_enable && (avc->m.Mode & 0111) == 0) {
+           vSetType(avc, VDIR);
+           avc->m.Mode |= S_IFDIR;
+       } else {
+           vSetType(avc, VLNK);
+           avc->m.Mode |= S_IFLNK;
+       }
+       if ((avc->m.Mode & 0111) == 0) {
+           avc->mvstat = 1;
+       }
     }
     avc->anyAccess = astat->AnonymousAccess;
 #ifdef badidea
index e63a20e..7e95b73 100644 (file)
@@ -240,6 +240,7 @@ static int enable_process_stats = 0;        /* enable rx stats */
 static int enable_afsdb = 0;           /* enable AFSDB support */
 #endif
 static int enable_dynroot = 0;         /* enable dynroot support */
+static int enable_fakestat = 0;                /* enable fakestat support */
 #ifdef notdef
 static int inodes = 60;                        /* VERY conservative, but has to be */
 #endif
@@ -1326,6 +1327,10 @@ mainproc(as, arock)
        /* -dynroot */
        enable_dynroot = 1;
     }
+    if (as->parms[27].items) {
+       /* -fakestat */
+       enable_fakestat = 1;
+    }
 
     /*
      * Pull out all the configuration info for the workstation's AFS cache and
@@ -1565,6 +1570,14 @@ mainproc(as, arock)
            printf("%s: Error enabling dynroot support.\n", rn);
     }
 
+    if (enable_fakestat) {
+       if (afsd_verbose)
+           printf("%s: Enabling fakestat support in kernel.\n", rn);
+       code = call_syscall(AFSOP_SET_FAKESTAT, 1);
+       if (code)
+           printf("%s: Error enabling fakestat support.\n", rn);
+    }
+
     /* Initialize AFS daemon threads. */
     if (afsd_verbose)
        printf("%s: Forking AFS daemon.\n", rn);
@@ -1918,6 +1931,7 @@ char **argv; {
                ), "Enable AFSDB support");
     cmd_AddParm(ts, "-files_per_subdir", CMD_SINGLE, CMD_OPTIONAL, "log(2) of the number of cache files per cache subdirectory");
     cmd_AddParm(ts, "-dynroot", CMD_FLAG, CMD_OPTIONAL, "Enable dynroot support");
+    cmd_AddParm(ts, "-fakestat", CMD_FLAG, CMD_OPTIONAL, "Enable fakestat support");
     return (cmd_Dispatch(argc, argv));
 }
 
index 14644a2..ab8d095 100644 (file)
@@ -41,6 +41,7 @@
 #define        AFSOP_AFSDB_HANDLER      30     /* userspace AFSDB lookup handler */
 #define        AFSOP_SET_DYNROOT        31     /* enable/disable dynroot support */
 #define        AFSOP_ADDCELLALIAS       32     /* create alias for existing cell */
+#define        AFSOP_SET_FAKESTAT       33     /* enable/disable fakestat support */
 
 /* The range 20-30 is reserved for AFS system offsets in the afs_syscall */
 #define        AFSCALL_PIOCTL          20