From: Nickolai Zeldovich Date: Tue, 2 Apr 2002 06:09:48 +0000 (+0000) Subject: Initial fakestat support (fake mountpoint directory attributes). X-Git-Tag: openafs-devel_1_3_3~163 X-Git-Url: http://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=6b33ed2b0544ca8b80a098af8db98e9714f41415 Initial fakestat support (fake mountpoint directory attributes). 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'. --- diff --git a/NEWS b/NEWS index 535c528..53889d4 100644 --- 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 diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index f9f5b0b..4c2fd2e 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_access.c b/src/afs/VNOPS/afs_vnop_access.c index e3c00a6..24912cb 100644 --- a/src/afs/VNOPS/afs_vnop_access.c +++ b/src/afs/VNOPS/afs_vnop_access.c @@ -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; } } diff --git a/src/afs/VNOPS/afs_vnop_attrs.c b/src/afs/VNOPS/afs_vnop_attrs.c index f7de5fe..2d14805 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 = - 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; } diff --git a/src/afs/VNOPS/afs_vnop_create.c b/src/afs/VNOPS/afs_vnop_create.c index a385ab8..8a78d63 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; @@ -469,6 +474,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 deac964..791e37f 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; @@ -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 diff --git a/src/afs/VNOPS/afs_vnop_flock.c b/src/afs/VNOPS/afs_vnop_flock.c index 7042b49..0782b3b 100644 --- a/src/afs/VNOPS/afs_vnop_flock.c +++ b/src/afs/VNOPS/afs_vnop_flock.c @@ -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 } diff --git a/src/afs/VNOPS/afs_vnop_lookup.c b/src/afs/VNOPS/afs_vnop_lookup.c index 726a95d..e68974c 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,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; } diff --git a/src/afs/VNOPS/afs_vnop_open.c b/src/afs/VNOPS/afs_vnop_open.c index d883e46..2ab022f 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 71b86fe..1b70fd7 100644 --- a/src/afs/VNOPS/afs_vnop_readdir.c +++ b/src/afs/VNOPS/afs_vnop_readdir.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_remove.c b/src/afs/VNOPS/afs_vnop_remove.c index 1ad449c..0fac0e4 100644 --- a/src/afs/VNOPS/afs_vnop_remove.c +++ b/src/afs/VNOPS/afs_vnop_remove.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_rename.c b/src/afs/VNOPS/afs_vnop_rename.c index c8e81e0..ad62563 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 */ @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_symlink.c b/src/afs/VNOPS/afs_vnop_symlink.c index fe6a32b..d626f30 100644 --- a/src/afs/VNOPS/afs_vnop_symlink.c +++ b/src/afs/VNOPS/afs_vnop_symlink.c @@ -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; } diff --git a/src/afs/VNOPS/afs_vnop_write.c b/src/afs/VNOPS/afs_vnop_write.c index 2a97d4a..f5b208e 100644 --- a/src/afs/VNOPS/afs_vnop_write.c +++ b/src/afs/VNOPS/afs_vnop_write.c @@ -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; } diff --git a/src/afs/afs.h b/src/afs/afs.h index 33e861b..3deb835 100644 --- a/src/afs/afs.h +++ b/src/afs/afs.h @@ -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_ */ diff --git a/src/afs/afs_call.c b/src/afs/afs_call.c index 4f59f94..06db6f3 100644 --- a/src/afs/afs_call.c +++ b/src/afs/afs_call.c @@ -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; diff --git a/src/afs/afs_pioctl.c b/src/afs/afs_pioctl.c index ee43ba6..4266d75 100644 --- a/src/afs/afs_pioctl.c +++ b/src/afs/afs_pioctl.c @@ -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; diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index 13e91ab..c3189e0 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -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 diff --git a/src/afsd/afsd.c b/src/afsd/afsd.c index e63a20e..7e95b73 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 @@ -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)); } diff --git a/src/config/afs_args.h b/src/config/afs_args.h index 14644a2..ab8d095 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