From 8e19de870a2d32ee918575030222b4e1dd1ca70b Mon Sep 17 00:00:00 2001 From: Nickolai Zeldovich Date: Tue, 23 Jul 2002 00:14:45 +0000 Subject: [PATCH] Pullup all fakestat support to 1.2 branch. This includes all of the 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 --- src/afs/LINUX/osi_vfsops.c | 10 ++ src/afs/LINUX/osi_vnodeops.c | 30 ++++- src/afs/VNOPS/afs_vnop_access.c | 19 ++- src/afs/VNOPS/afs_vnop_attrs.c | 49 ++++++-- src/afs/VNOPS/afs_vnop_create.c | 6 + src/afs/VNOPS/afs_vnop_dirops.c | 11 ++ src/afs/VNOPS/afs_vnop_flock.c | 45 ++++++- src/afs/VNOPS/afs_vnop_lookup.c | 194 +++++++++++++++++++++++++++++-- src/afs/VNOPS/afs_vnop_open.c | 7 +- src/afs/VNOPS/afs_vnop_readdir.c | 16 +++ src/afs/VNOPS/afs_vnop_remove.c | 37 ++++-- src/afs/VNOPS/afs_vnop_rename.c | 53 +++++---- src/afs/VNOPS/afs_vnop_symlink.c | 18 ++- src/afs/VNOPS/afs_vnop_write.c | 34 ++++-- src/afs/afs.h | 14 ++- src/afs/afs_call.c | 4 + src/afs/afs_pioctl.c | 27 +++-- src/afs/afs_vcache.c | 13 ++- src/afsd/afsd.c | 1 + src/config/afs_args.h | 1 + 20 files changed, 503 insertions(+), 86 deletions(-) diff --git a/src/afs/LINUX/osi_vfsops.c b/src/afs/LINUX/osi_vfsops.c index e9d68992c..fd200623e 100644 --- a/src/afs/LINUX/osi_vfsops.c +++ b/src/afs/LINUX/osi_vfsops.c @@ -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); +} diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index 9bc7d95d5..4efabf08a 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_access.c b/src/afs/VNOPS/afs_vnop_access.c index a1bf30229..22c80391f 100644 --- a/src/afs/VNOPS/afs_vnop_access.c +++ b/src/afs/VNOPS/afs_vnop_access.c @@ -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; } } diff --git a/src/afs/VNOPS/afs_vnop_attrs.c b/src/afs/VNOPS/afs_vnop_attrs.c index 64db3958b..32157ff3e 100644 --- a/src/afs/VNOPS/afs_vnop_attrs.c +++ b/src/afs/VNOPS/afs_vnop_attrs.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_create.c b/src/afs/VNOPS/afs_vnop_create.c index 8ed72c240..3a61d8ea8 100644 --- a/src/afs/VNOPS/afs_vnop_create.c +++ b/src/afs/VNOPS/afs_vnop_create.c @@ -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: diff --git a/src/afs/VNOPS/afs_vnop_dirops.c b/src/afs/VNOPS/afs_vnop_dirops.c index 0ff2fa0f2..274c9b503 100644 --- a/src/afs/VNOPS/afs_vnop_dirops.c +++ b/src/afs/VNOPS/afs_vnop_dirops.c @@ -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 diff --git a/src/afs/VNOPS/afs_vnop_flock.c b/src/afs/VNOPS/afs_vnop_flock.c index c25d775f1..73c0ceaeb 100644 --- a/src/afs/VNOPS/afs_vnop_flock.c +++ b/src/afs/VNOPS/afs_vnop_flock.c @@ -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 } diff --git a/src/afs/VNOPS/afs_vnop_lookup.c b/src/afs/VNOPS/afs_vnop_lookup.c index 7352d5ba2..01c0ab6af 100644 --- a/src/afs/VNOPS/afs_vnop_lookup.c +++ b/src/afs/VNOPS/afs_vnop_lookup.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_open.c b/src/afs/VNOPS/afs_vnop_open.c index d883e46a2..2ab022fc3 100644 --- a/src/afs/VNOPS/afs_vnop_open.c +++ b/src/afs/VNOPS/afs_vnop_open.c @@ -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, diff --git a/src/afs/VNOPS/afs_vnop_readdir.c b/src/afs/VNOPS/afs_vnop_readdir.c index 58bb488a6..fe1f86080 100644 --- a/src/afs/VNOPS/afs_vnop_readdir.c +++ b/src/afs/VNOPS/afs_vnop_readdir.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_remove.c b/src/afs/VNOPS/afs_vnop_remove.c index 650baf05a..c5fe7cc2f 100644 --- a/src/afs/VNOPS/afs_vnop_remove.c +++ b/src/afs/VNOPS/afs_vnop_remove.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_rename.c b/src/afs/VNOPS/afs_vnop_rename.c index 05a5a708a..1fb0a1157 100644 --- a/src/afs/VNOPS/afs_vnop_rename.c +++ b/src/afs/VNOPS/afs_vnop_rename.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_symlink.c b/src/afs/VNOPS/afs_vnop_symlink.c index e7bd5d4bb..7158074de 100644 --- a/src/afs/VNOPS/afs_vnop_symlink.c +++ b/src/afs/VNOPS/afs_vnop_symlink.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_write.c b/src/afs/VNOPS/afs_vnop_write.c index 268e12d75..0d0b13159 100644 --- a/src/afs/VNOPS/afs_vnop_write.c +++ b/src/afs/VNOPS/afs_vnop_write.c @@ -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; } diff --git a/src/afs/afs.h b/src/afs/afs.h index 0f03fcda6..58836e698 100644 --- a/src/afs/afs.h +++ b/src/afs/afs.h @@ -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_ */ diff --git a/src/afs/afs_call.c b/src/afs/afs_call.c index 0770043c7..ba600f4d5 100644 --- a/src/afs/afs_call.c +++ b/src/afs/afs_call.c @@ -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; diff --git a/src/afs/afs_pioctl.c b/src/afs/afs_pioctl.c index 5422b8ce1..c2ebb6a60 100644 --- a/src/afs/afs_pioctl.c +++ b/src/afs/afs_pioctl.c @@ -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; diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index 4f51f26c3..42da4f9fb 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -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 diff --git a/src/afsd/afsd.c b/src/afsd/afsd.c index 92612fbaf..1cb3488d2 100644 --- a/src/afsd/afsd.c +++ b/src/afsd/afsd.c @@ -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 diff --git a/src/config/afs_args.h b/src/config/afs_args.h index 14644a269..ab8d095ee 100644 --- a/src/config/afs_args.h +++ b/src/config/afs_args.h @@ -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 -- 2.39.5