]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
Pullup all fakestat support to 1.2 branch. This includes all of the
authorNickolai Zeldovich <kolya@mit.edu>
Tue, 23 Jul 2002 00:14:45 +0000 (00:14 +0000)
committerGarry Zacheiss <zacheiss@mit.edu>
Tue, 23 Jul 2002 00:14:45 +0000 (00:14 +0000)
following deltas:

- initial-fakestat-support-20020402
- fakestat-fix-eval-args-ordering-20020409
- fix-evalfakestat-argument-ordering-20020409
- minor-fakestat-cleanup-20020720
- update-volume-root-attributes-on-linux-fakestat-20020720

20 files changed:
src/afs/LINUX/osi_vfsops.c
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

index e9d68992ce6d3d206ab7d00e5051ee9235fa172b..fd200623e16566463c384e42948e414efd11ce8f 100644 (file)
@@ -463,3 +463,13 @@ void vcache2inode(struct vcache *avc)
     VATTR_NULL(&vattr);
     afs_CopyOutAttrs(avc, &vattr); /* calls vattr2inode */
 }
+
+/* Yet another one for fakestat'ed mountpoints */
+void vcache2fakeinode(struct vcache *rootvp, struct vcache *mpvp)
+{
+    struct vattr vattr;
+
+    VATTR_NULL(&vattr);
+    afs_CopyOutAttrs(rootvp, &vattr);
+    vattr2inode(AFSTOV(mpvp), &vattr);
+}
index 9bc7d95d5d84e00883e8898dc547dce3822aaa75..4efabf08adb42b6d0dfdd74ae38aa8ea8e839e2e 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)
@@ -169,6 +170,7 @@ static int afs_linux_readdir(struct file *fp,
     int len;
     int origOffset;
     cred_t *credp = crref();
+    struct afs_fakestat_state fakestat;
 
     AFS_GLOCK();
     AFS_STATCNT(afs_readdir);
@@ -180,10 +182,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;
     }
@@ -191,6 +202,7 @@ tagain:
     /* get a reference to the entire directory */
     tdc = afs_GetDCache(avc, 0, &treq, &origOffset, &len, 1);
     if (!tdc) {
+       afs_PutFakeStat(&fakestat);
        AFS_GUNLOCK();
        return -ENOENT;
     }
@@ -284,6 +296,7 @@ tagain:
 
     afs_PutDCache(tdc);
     ReleaseReadLock(&avc->lock);
+    afs_PutFakeStat(&fakestat);
     AFS_GUNLOCK();
     return 0;
 }
@@ -654,20 +667,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;
     }
index a1bf3022975627ffc38c1d7451328db81d97469a..22c80391fb698f49a21d91e944b97462b6dc3c75 100644 (file)
@@ -188,21 +188,31 @@ 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_INT32, 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. */
@@ -269,11 +279,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 64db3958b13e7285f07985a316a08f6a2b30766d..32157ff3ebdd1c2e9d186ccc6f746825591a2645 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 =
-       (int)avc->m.Date;
+       fakedir ? 0 : (int)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
@@ -192,6 +196,23 @@ afs_getattr(OSI_VC_ARG(avc), attrs, acred)
     afs_Trace2(afs_iclSetp, CM_TRACE_GETATTR, ICL_TYPE_POINTER, avc, 
               ICL_TYPE_INT32, 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);
@@ -392,12 +413,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_INT32, 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;
@@ -516,6 +544,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 8ed72c240f47b7ce78bceb050af0052615baea52..3a61d8ea82da875a02d54e5d744342b2608b7c10 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;
@@ -454,6 +459,7 @@ done:
        tvc->states |= CCore1;
 #endif
 
+    afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 20);
 
 done2:
index 0ff2fa0f2658a7a505ae2dc0ade376acf44fbcae..274c9b5036299ae3bf94cdda4b4b2f57e909dac5 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;
 
@@ -157,6 +161,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
@@ -192,6 +197,7 @@ afs_rmdir(adp, aname, acred)
     afs_int32 offset, len;
     struct AFSFetchStatus OutDirStatus;
     struct AFSVolSync tsync;
+    struct afs_fakestat_state fakestate;
     XSTATS_DECLS
     OSI_VC_CONVERT(adp)
 
@@ -202,12 +208,16 @@ afs_rmdir(adp, aname, 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;
 
@@ -306,6 +316,7 @@ afs_rmdir(adp, aname, acred)
     code = 0;
 
 done:
+    afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 27); 
 done2:
 #ifdef AFS_OSF_ENV
index c25d775f13683aa373688e602d7c160f368f55ac..73c0ceaebfb31295fbe5106da97391ba2d63c90d 100644 (file)
@@ -502,11 +502,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(&avc, &fakestate, &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)) {
@@ -520,12 +530,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) 
@@ -553,13 +566,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) 
@@ -578,8 +595,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;
 }
 
@@ -858,7 +877,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
@@ -872,9 +893,15 @@ afs_xflock () {
 #endif /* AFS_FBSD_ENV */
     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 */
@@ -888,9 +915,15 @@ afs_xflock () {
            tvc = VTOAFS(afs_gntovn)(tvc);
            if (!tvc) {
                u.u_error = ENOENT;
+               afs_PutFakeStat(&fakestate);
                return;
            }
 #endif
+           code = afs_EvalFakeStat(&tvc, &fakestate, &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))
@@ -938,6 +971,7 @@ afs_xflock () {
 #else
     FP_UNREF(fd);
 #endif
+    afs_PutFakeStat(&fakestate);
     return code;
 #else  /* AFS_OSF_ENV */
     if (!flockDone)
@@ -946,6 +980,7 @@ afs_xflock () {
 #else
        flock();
 #endif
+    afs_PutFakeStat(&fakestate);
     return;
 #endif
 }
index 7352d5ba23c37e9b0dc1837af5c9bf816e6cb471..01c0ab6aff5b79352a674e4f6fe6d8248b7327bb 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,175 @@ 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;
+}
+
+/*
+ * afs_EvalFakeStat_int
+ *
+ * The actual implementation of afs_EvalFakeStat and afs_TryEvalFakeStat,
+ * which is called by those wrapper functions.
+ *
+ * Only issues RPCs if canblock is non-zero.
+ */
+static int
+afs_EvalFakeStat_int(avcp, state, areq, canblock)
+    struct vcache **avcp;
+    struct afs_fakestat_state *state;
+    struct vrequest *areq;
+    int canblock;
+{
+    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 (canblock) {
+       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 (!canblock) {
+           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 = canblock ? ENOENT : 0;
+           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 = canblock ? ENOENT : 0;
+    }
+
+done:
+    if (tvolp)
+       afs_PutVolume(tvolp, WRITE_LOCK);
+    return code;
+}
+
+/*
+ * 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;
+{
+    return afs_EvalFakeStat_int(avcp, state, areq, 1);
+}
+
+/*
+ * 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;
+{
+    return afs_EvalFakeStat_int(avcp, state, areq, 0);
+}
+
+/*
+ * 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; {
@@ -921,8 +1087,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);
@@ -931,10 +1106,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 */
 
@@ -1217,9 +1388,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);
@@ -1319,6 +1490,7 @@ done:
            if (!FidCmp(&(tvc->fid), &(adp->fid))) { 
                afs_PutVCache(*avcp, WRITE_LOCK);
                *avcp = NULL;
+               afs_PutFakeStat(&fakestate);
                return afs_CheckCode(EISDIR, &treq, 18);
            }
        }
@@ -1342,6 +1514,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
        }
@@ -1355,5 +1528,6 @@ done:
        *avcp = (struct vcache *)0;
     }
 
+    afs_PutFakeStat(&fakestate);
     return code;
 }
index d883e46a254374c534f9ddb42012c27ba265e07d..2ab022fc3480016b74fb470af99bc59d3de6b580 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 58bb488a62d7fa01d31a102fbf098671967b901d..fe1f860806bc19a4e1ff3e9a14a5398a44d4bfd8 100644 (file)
@@ -443,6 +443,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) */
@@ -495,6 +496,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;
@@ -729,6 +733,7 @@ done:
 #ifdef AFS_HPUX_ENV
     osi_FreeSmallSpace((char *)sdirEntry);
 #endif
+    afs_PutFakeStat(&fakestate);
     code = afs_CheckCode(code, &treq, 28);
     return code;
 }
@@ -759,6 +764,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)
@@ -770,6 +776,15 @@ afs1_readdir(avc, auio, acred)
 #endif
        return code;
     }
+    afs_InitFakeStat(&fakestate);
+    code = afs_EvalFakeStat(&avc, &fakestate, &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);
@@ -955,6 +970,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 650baf05af7a487080f73d616149008b624bbdf0..c5fe7cc2f2d67eb18b39003231620bc3238811fa 100644 (file)
@@ -226,6 +226,7 @@ afs_remove(OSI_VC_ARG(adp), aname, acred)
     afs_int32 offset, len;
     struct AFSFetchStatus OutDirStatus;
     struct AFSVolSync tsync;
+    struct afs_fakestat_state fakestate;
     XSTATS_DECLS
     OSI_VC_CONVERT(adp)
 
@@ -237,23 +238,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);
 #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;
+       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;
     }
     if (strlen(aname) > AFSNAMEMAX) {
+       afs_PutFakeStat(&fakestate);
 #ifdef  AFS_OSF_ENV
        afs_PutVCache(adp, 0);
        afs_PutVCache(tvc, 0);
@@ -267,13 +282,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
 
@@ -286,6 +303,7 @@ tagain:
         afs_PutVCache(tvc, 0);
 #endif
         code = EROFS;
+       afs_PutFakeStat(&fakestate);
        return code;
     }
 
@@ -378,6 +396,7 @@ tagain:
 #ifdef AFS_OSF_ENV
     afs_PutVCache(adp, WRITE_LOCK);
 #endif /* AFS_OSF_ENV */
+    afs_PutFakeStat(&fakestate);
     return code;
 }
 
index 05a5a708a888da58f1985f40cbe248b744571671..1fb0a1157b1a237b72f4a22856f6e6c285100ade 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 */
@@ -107,7 +106,7 @@ tagain:
      * fileFid in order to handle ".." invalidation at the very end.
      */
     code = 0;
-    tdc1 = afs_GetDCache(aodp, 0, &treq, &offset, &len, 0);
+    tdc1 = afs_GetDCache(aodp, 0, areq, &offset, &len, 0);
     if (!tdc1) {
        code = ENOENT;
     }
@@ -135,7 +134,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
@@ -151,7 +150,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 */
@@ -265,11 +264,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) {
@@ -303,9 +302,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);
@@ -327,16 +326,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 */
@@ -347,14 +345,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) {
@@ -363,5 +375,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 e7bd5d4bb90a85d1167279cb30520acc3c3c90c8..7158074de833ad63be5526b8a15a09a178f45c9b 100644 (file)
@@ -71,6 +71,7 @@ afs_symlink
     struct AFSCallBack CallBack;
     struct AFSVolSync tsync;
     struct volume*    volp=0;
+    struct afs_fakestat_state fakestate;
     XSTATS_DECLS
     OSI_VC_CONVERT(adp)
     
@@ -78,6 +79,14 @@ 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;
@@ -88,9 +97,6 @@ afs_symlink
        goto done2;
     }
 
-    if (code = afs_InitReq(&treq, acred))
-       goto done2;
-
     code = afs_VerifyVCache(adp, &treq);
     if (code) { 
       code = afs_CheckCode(code, &treq, 30);
@@ -217,6 +223,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);
@@ -322,11 +329,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) {
@@ -345,6 +356,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 268e12d757b41d02f5ed47dd71088269832b6da3..0d0b131594aad4367c9f390a8cd7feb7287b508f 100644 (file)
@@ -685,10 +685,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,
@@ -697,6 +699,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);
@@ -720,6 +727,7 @@ afs_closex(afd)
     if (!closeDone) {
        code = vno_close(afd);
     }
+    afs_PutFakeStat(&fakestat);
     return code;       /* return code from vnode layer */
 }
 #endif
@@ -760,41 +768,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)
@@ -916,6 +927,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 0f03fcda6cd221a30f04ba6da3673f2e105ea89c..58836e698b2d6a9a6e55471ec3e4318667cea094 100644 (file)
@@ -616,7 +616,7 @@ struct vcache {
 #ifdef AFS_DARWIN_ENV
     struct lock__bsd__      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. */
@@ -1141,5 +1141,17 @@ 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;
+    struct vcache *root_vp;
+};
+
+extern int afs_fakestat_enable;
+
 #endif /* _AFS_H_ */
 
index 0770043c7e0170b385e3ebf77a59871c500be21f..ba600f4d53cdd7590d5c6226613c24cab32b7a27 100644 (file)
@@ -660,6 +660,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 5422b8ce1281025126867fdb0cf1ef01a0c20451..c2ebb6a600e195c55a531866865b9a4574466883 100644 (file)
@@ -1021,7 +1021,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;
@@ -1034,11 +1034,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 */
@@ -1050,11 +1059,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;
@@ -1064,8 +1075,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;
@@ -1081,6 +1093,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);
   }
   
@@ -1715,7 +1728,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;
@@ -2501,7 +2514,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;
@@ -3698,7 +3711,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 4f51f26c3272c996b98f98311dbc5272f2c93205..42da4f9fb193cafdce9e96d9bae092b5df86b896 100644 (file)
@@ -1489,9 +1489,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 92612fbaf2e7b06e8721852200c50cf12084d48a..1cb3488d20c694f661b8c456286a718ef28bbced 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
index 14644a269f6c4514a7d2af3dd81e9da212515dfd..ab8d095eed5b1c6d977a3744531774d8ab9ac6c9 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