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'.
This commit is contained in:
Nickolai Zeldovich 2002-04-02 06:09:48 +00:00
parent fd318a1fc9
commit 6b33ed2b05
20 changed files with 496 additions and 97 deletions

7
NEWS
View File

@ -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

View File

@ -261,6 +261,7 @@ static int afs_linux_readdir(struct file *fp,
int len;
afs_size_t origOffset, tlen;
cred_t *credp = crref();
struct afs_fakestat_state fakestat;
AFS_GLOCK();
AFS_STATCNT(afs_readdir);
@ -272,10 +273,19 @@ static int afs_linux_readdir(struct file *fp,
return -code;
}
afs_InitFakeStat(&fakestat);
code = afs_EvalFakeStat(&avc, &fakestat, &treq);
if (code) {
afs_PutFakeStat(&fakestat);
AFS_GUNLOCK();
return -code;
}
/* update the cache entry */
tagain:
code = afs_VerifyVCache(avc, &treq);
if (code) {
afs_PutFakeStat(&fakestat);
AFS_GUNLOCK();
return -code;
}
@ -284,6 +294,7 @@ tagain:
tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
len = tlen;
if (!tdc) {
afs_PutFakeStat(&fakestat);
AFS_GUNLOCK();
return -ENOENT;
}
@ -380,6 +391,7 @@ tagain:
ReleaseReadLock(&tdc->lock);
afs_PutDCache(tdc);
ReleaseReadLock(&avc->lock);
afs_PutFakeStat(&fakestat);
AFS_GUNLOCK();
return 0;
}

View File

@ -188,22 +188,32 @@ afs_access(OSI_VC_ARG(avc), amode, acred)
struct AFS_UCRED *acred; {
register afs_int32 code;
struct vrequest treq;
struct afs_fakestat_state fakestate;
OSI_VC_CONVERT(avc)
AFS_STATCNT(afs_access);
afs_Trace3(afs_iclSetp, CM_TRACE_ACCESS, ICL_TYPE_POINTER, avc,
ICL_TYPE_INT32, amode,
ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
afs_InitFakeStat(&fakestate);
if (code = afs_InitReq(&treq, acred)) return code;
code = afs_EvalFakeStat(&avc, &fakestate, &treq);
if (code) {
afs_PutFakeStat(&fakestate);
return code;
}
code = afs_VerifyVCache(avc, &treq);
if (code) {
afs_PutFakeStat(&fakestate);
code = afs_CheckCode(code, &treq, 16);
return code;
}
/* if we're looking for write access and we have a read-only file system, report it */
if ((amode & VWRITE) && (avc->states & CRO)) {
afs_PutFakeStat(&fakestate);
return EROFS;
}
code = 1; /* Default from here on in is access ok. */
@ -270,11 +280,12 @@ afs_access(OSI_VC_ARG(avc), amode, acred)
code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
}
}
if (code)
afs_PutFakeStat(&fakestate);
if (code) {
return 0; /* if access is ok */
else {
code = afs_CheckCode(EACCES, &treq, 17); /* failure code */
return code;
} else {
code = afs_CheckCode(EACCES, &treq, 17); /* failure code */
return code;
}
}

View File

@ -37,20 +37,24 @@ extern struct vcache *afs_globalVp;
/* copy out attributes from cache entry */
afs_CopyOutAttrs(avc, attrs)
register struct vattr *attrs;
register struct vcache *avc; {
register struct vcache *avc;
{
register struct volume *tvp;
register struct cell *tcell;
register afs_int32 i;
int fakedir = 0;
AFS_STATCNT(afs_CopyOutAttrs);
if (afs_fakestat_enable && avc->mvstat == 1)
fakedir = 1;
#if defined(AFS_MACH_ENV )
attrs->va_mode = vType(avc) | (avc->m.Mode&~VFMT);
attrs->va_mode = fakedir ? VDIR | 0755 : vType(avc) | (avc->m.Mode&~VFMT);
#else /* AFS_MACH_ENV */
attrs->va_type = vType(avc);
attrs->va_type = fakedir ? VDIR : vType(avc);
#if defined(AFS_SGI_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
attrs->va_mode = (mode_t)(avc->m.Mode & 0xffff);
attrs->va_mode = fakedir ? 0755 : (mode_t)(avc->m.Mode & 0xffff);
#else
attrs->va_mode = avc->m.Mode;
attrs->va_mode = fakedir ? VDIR | 0755 : avc->m.Mode;
#endif
#endif /* AFS_MACH_ENV */
@ -60,8 +64,8 @@ afs_CopyOutAttrs(avc, attrs)
if (tcell && (tcell->states & CNoSUID))
attrs->va_mode &= ~(VSUID|VSGID);
}
attrs->va_uid = avc->m.Owner;
attrs->va_gid = avc->m.Group; /* yeah! */
attrs->va_uid = fakedir ? 0 : avc->m.Owner;
attrs->va_gid = fakedir ? 0 : avc->m.Group; /* yeah! */
#if defined(AFS_SUN56_ENV)
attrs->va_fsid = avc->v.v_vfsp->vfs_fsid.val[0];
#else
@ -90,10 +94,10 @@ afs_CopyOutAttrs(avc, attrs)
}
else attrs->va_nodeid = avc->fid.Fid.Vnode + (avc->fid.Fid.Volume << 16);
attrs->va_nodeid &= 0x7fffffff; /* Saber C hates negative inode #s! */
attrs->va_nlink = avc->m.LinkCount;
attrs->va_size = avc->m.Length;
attrs->va_nlink = fakedir ? 100 : avc->m.LinkCount;
attrs->va_size = fakedir ? 4096 : avc->m.Length;
attrs->va_atime.tv_sec = attrs->va_mtime.tv_sec = attrs->va_ctime.tv_sec =
avc->m.Date;
fakedir ? 0 : avc->m.Date;
/* set microseconds to be dataversion # so that we approximate NFS-style
* use of mtime as a dataversion #. We take it mod 512K because
* microseconds *must* be less than a million, and 512K is the biggest
@ -203,6 +207,23 @@ afs_getattr(OSI_VC_ARG(avc), attrs, acred)
afs_Trace2(afs_iclSetp, CM_TRACE_GETATTR, ICL_TYPE_POINTER, avc,
ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
if (afs_fakestat_enable && avc->mvstat == 1) {
struct afs_fakestat_state fakestat;
code = afs_InitReq(&treq, acred);
if (code) return code;
afs_InitFakeStat(&fakestat);
code = afs_TryEvalFakeStat(&avc, &fakestat, &treq);
if (code) {
afs_PutFakeStat(&fakestat);
return code;
}
code = afs_CopyOutAttrs(avc, attrs);
afs_PutFakeStat(&fakestat);
return code;
}
#if defined(AFS_SUN5_ENV)
if (flags & ATTR_HINT) {
code = afs_CopyOutAttrs(avc, attrs);
@ -403,12 +424,19 @@ afs_setattr(avc, attrs, acred)
struct vrequest treq;
struct AFSStoreStatus astat;
register afs_int32 code;
struct afs_fakestat_state fakestate;
OSI_VC_CONVERT(avc)
AFS_STATCNT(afs_setattr);
afs_Trace2(afs_iclSetp, CM_TRACE_SETATTR, ICL_TYPE_POINTER, avc,
ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
if (code = afs_InitReq(&treq, acred)) return code;
afs_InitFakeStat(&fakestate);
code = afs_EvalFakeStat(&avc, &fakestate, &treq);
if (code)
goto done;
if (avc->states & CRO) {
code=EROFS;
goto done;
@ -528,6 +556,7 @@ afs_setattr(avc, attrs, acred)
AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
#endif
done:
afs_PutFakeStat(&fakestate);
code = afs_CheckCode(code, &treq, 15);
return code;
}

View File

@ -72,6 +72,7 @@ afs_create(OSI_VC_ARG(adp), aname, attrs, aexcl, amode, avcp, acred)
struct server *hostp=0;
struct vcache *tvc;
struct volume* volp = 0;
struct afs_fakestat_state fakestate;
XSTATS_DECLS
OSI_VC_CONVERT(adp)
@ -83,6 +84,8 @@ afs_create(OSI_VC_ARG(adp), aname, attrs, aexcl, amode, avcp, acred)
afs_Trace3(afs_iclSetp, CM_TRACE_CREATE, ICL_TYPE_POINTER, adp,
ICL_TYPE_STRING, aname, ICL_TYPE_INT32, amode);
afs_InitFakeStat(&fakestate);
#ifdef AFS_SGI65_ENV
/* If avcp is passed not null, it's the old reference to this file.
* We can use this to avoid create races. For now, just decrement
@ -112,6 +115,8 @@ afs_create(OSI_VC_ARG(adp), aname, attrs, aexcl, amode, avcp, acred)
code = EINVAL;
goto done;
}
code = afs_EvalFakeStat(&adp, &fakestate, &treq);
if (code) goto done;
tagain:
code = afs_VerifyVCache(adp, &treq);
if (code) goto done;
@ -469,6 +474,7 @@ done:
tvc->states |= CCore1;
#endif
afs_PutFakeStat(&fakestate);
code = afs_CheckCode(code, &treq, 20);
done2:

View File

@ -62,6 +62,7 @@ afs_mkdir(OSI_VC_ARG(adp), aname, attrs, avcp, acred)
struct AFSCallBack CallBack;
struct AFSVolSync tsync;
afs_int32 now;
struct afs_fakestat_state fakestate;
XSTATS_DECLS
OSI_VC_CONVERT(adp)
@ -71,6 +72,7 @@ afs_mkdir(OSI_VC_ARG(adp), aname, attrs, avcp, acred)
if (code = afs_InitReq(&treq, acred))
goto done2;
afs_InitFakeStat(&fakestate);
if (strlen(aname) > AFSNAMEMAX) {
code = ENAMETOOLONG;
@ -81,6 +83,8 @@ afs_mkdir(OSI_VC_ARG(adp), aname, attrs, avcp, acred)
code = EINVAL;
goto done;
}
code = afs_EvalFakeStat(&adp, &fakestate, &treq);
if (code) goto done;
code = afs_VerifyVCache(adp, &treq);
if (code) goto done;
@ -159,6 +163,7 @@ afs_mkdir(OSI_VC_ARG(adp), aname, attrs, avcp, acred)
}
else code = ENOENT;
done:
afs_PutFakeStat(&fakestate);
code = afs_CheckCode(code, &treq, 26);
done2:
#ifdef AFS_OSF_ENV
@ -194,6 +199,7 @@ afs_rmdir(adp, aname, acred)
afs_size_t offset, len;
struct AFSFetchStatus OutDirStatus;
struct AFSVolSync tsync;
struct afs_fakestat_state fakestate;
XSTATS_DECLS
OSI_VC_CONVERT(adp)
@ -202,14 +208,19 @@ afs_rmdir(adp, aname, acred)
afs_Trace2(afs_iclSetp, CM_TRACE_RMDIR, ICL_TYPE_POINTER, adp,
ICL_TYPE_STRING, aname);
if (code = afs_InitReq(&treq, acred))
if (code = afs_InitReq(&treq, acred))
goto done2;
afs_InitFakeStat(&fakestate);
if (strlen(aname) > AFSNAMEMAX) {
code = ENAMETOOLONG;
goto done;
}
code = afs_EvalFakeStat(&adp, &fakestate, &treq);
if (code)
goto done;
code = afs_VerifyVCache(adp, &treq);
if (code) goto done;
@ -314,6 +325,7 @@ afs_rmdir(adp, aname, acred)
code = 0;
done:
afs_PutFakeStat(&fakestate);
code = afs_CheckCode(code, &treq, 27);
done2:
#ifdef AFS_OSF_ENV

View File

@ -503,11 +503,21 @@ struct AFS_UCRED *acred; {
#ifdef AFS_OSF_ENV
int acmd = 0;
#endif
struct afs_fakestat_state fakestate;
AFS_STATCNT(afs_lockctl);
if (code = afs_InitReq(&treq, acred)) return code;
afs_InitFakeStat(&fakestate);
code = afs_EvalFakeStat(&fakestate, &avc, &treq);
if (code) {
afs_PutFakeStat(&fakestate);
return code;
}
#ifdef AFS_OSF_ENV
if (flag & VNOFLCK) return 0;
if (flag & VNOFLCK) {
afs_PutFakeStat(&fakestate);
return 0;
}
if (flag & CLNFLCK) {
acmd = LOCK_UN;
} else if ((flag & GETFLCK) || (flag & RGETFLCK)) {
@ -521,12 +531,15 @@ struct AFS_UCRED *acred; {
#else
if (acmd == F_GETLK) {
#endif
if (af->l_type == F_UNLCK)
if (af->l_type == F_UNLCK) {
afs_PutFakeStat(&fakestate);
return 0;
}
#ifndef AFS_OSF_ENV /* getlock is a no-op for osf (for now) */
code = HandleGetLock(avc, af, &treq, clid);
#endif
code = afs_CheckCode(code, &treq, 2); /* defeat buggy AIX optimz */
afs_PutFakeStat(&fakestate);
return code;
}
else if ((acmd == F_SETLK) || (acmd == F_SETLKW)
@ -554,13 +567,17 @@ struct AFS_UCRED *acred; {
even when they should block */
if (af->l_whence != 0 || af->l_start != 0 || af->l_len != 0) {
DoLockWarning();
afs_PutFakeStat(&fakestate);
return 0;
}
/* otherwise we can turn this into a whole-file flock */
if (af->l_type == F_RDLCK) code = LOCK_SH;
else if (af->l_type == F_WRLCK) code = LOCK_EX;
else if (af->l_type == F_UNLCK) code = LOCK_UN;
else return EINVAL; /* unknown lock type */
else {
afs_PutFakeStat(&fakestate);
return EINVAL; /* unknown lock type */
}
if (((acmd == F_SETLK)
#if (defined(AFS_SGI_ENV) || defined(AFS_SUN_ENV)) && !defined(AFS_SUN58_ENV)
|| (acmd == F_RSETLK)
@ -579,8 +596,10 @@ struct AFS_UCRED *acred; {
#endif
#endif
code = afs_CheckCode(code, &treq, 3); /* defeat AIX -O bug */
afs_PutFakeStat(&fakestate);
return code;
}
afs_PutFakeStat(&fakestate);
return EINVAL;
}
@ -859,7 +878,9 @@ afs_xflock () {
struct vrequest treq;
struct vcache *tvc;
int flockDone;
struct afs_fakestat_state fakestate;
afs_InitFakeStat(&fakestate);
AFS_STATCNT(afs_xflock);
flockDone = 0;
#ifdef AFS_OSF_ENV
@ -869,9 +890,15 @@ afs_xflock () {
uap = (struct a *)u.u_ap;
fd = getf(uap->fd);
#endif
if (!fd) return;
if (!fd) {
afs_PutFakeStat(&fakestate);
return;
}
if (flockDone = afs_InitReq(&treq, u.u_cred)) return flockDone;
if (flockDone = afs_InitReq(&treq, u.u_cred)) {
afs_PutFakeStat(&fakestate);
return flockDone;
}
/* first determine whether this is any sort of vnode */
if (fd->f_type == DTYPE_VNODE) {
/* good, this is a vnode; next see if it is an AFS vnode */
@ -885,9 +912,15 @@ afs_xflock () {
tvc = VTOAFS(afs_gntovn)(tvc);
if (!tvc) {
u.u_error = ENOENT;
afs_PutFakeStat(&fakestate);
return;
}
#endif
code = afs_EvalFakeStat(&fakestate, &tvc, &treq);
if (code) {
afs_PutFakeStat(&fakestate);
return code;
}
if ((fd->f_flag & (FEXLOCK | FSHLOCK)) && !(uap->com & LOCK_UN)) {
/* First, if fd already has lock, release it for relock path */
#if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV))
@ -935,6 +968,7 @@ afs_xflock () {
#else
FP_UNREF(fd);
#endif
afs_PutFakeStat(&fakestate);
return code;
#else /* AFS_OSF_ENV */
if (!flockDone)
@ -943,6 +977,7 @@ afs_xflock () {
#else
flock();
#endif
afs_PutFakeStat(&fakestate);
return;
#endif
}

View File

@ -54,6 +54,7 @@ extern struct inode_operations afs_symlink_iops, afs_dir_iops;
afs_int32 afs_bulkStatsDone;
static int bulkStatCounter = 0; /* counter for bulk stat seq. numbers */
int afs_fakestat_enable = 0;
/* this would be faster if it did comparison as int32word, but would be
@ -90,8 +91,9 @@ char *afs_index(a, c)
}
/* call under write lock, evaluate mvid field from a mt pt.
* avc is the vnode of the mount point object.
* advc is the vnode of the containing directory
* avc is the vnode of the mount point object; must be write-locked.
* advc is the vnode of the containing directory (optional; if NULL and
* EvalMountPoint succeeds, caller must initialize *avolpp->dotdot)
* avolpp is where we return a pointer to the volume named by the mount pt, if success
* areq is the identity of the caller.
*
@ -231,11 +233,159 @@ EvalMountPoint(avc, advc, avolpp, areq)
* to the new path.
*/
tvp->mtpoint = avc->fid; /* setup back pointer to mtpoint */
tvp->dotdot = advc->fid;
if (advc) tvp->dotdot = advc->fid;
*avolpp = tvp;
return 0;
}
/*
* afs_InitFakeStat
*
* Must be called on an afs_fakestat_state object before calling
* afs_EvalFakeStat or afs_PutFakeStat. Calling afS_PutFakeStat
* without calling afs_EvalFakeStat is legal, as long as this
* function is called.
*/
void
afs_InitFakeStat(state)
struct afs_fakestat_state *state;
{
state->valid = 1;
state->did_eval = 0;
state->need_release = 0;
state->nonblock = 0;
}
/*
* afs_EvalFakeStat
*
* Automatically does the equivalent of EvalMountPoint for vcache entries
* which are mount points. Remembers enough state to properly release
* the volume root vcache when afs_PutFakeStat() is called.
*
* State variable must be initialized by afs_InitFakeState() beforehand.
*
* Returns 0 when everything succeeds and *avcp points to the vcache entry
* that should be used for the real vnode operation. Returns non-zero if
* something goes wrong and the error code should be returned to the user.
*/
int
afs_EvalFakeStat(avcp, state, areq)
struct vcache **avcp;
struct afs_fakestat_state *state;
struct vrequest *areq;
{
struct vcache *tvc, *root_vp;
struct volume *tvolp = NULL;
int code = 0;
osi_Assert(state->valid == 1);
osi_Assert(state->did_eval == 0);
state->did_eval = 1;
if (!afs_fakestat_enable)
return 0;
tvc = *avcp;
if (tvc->mvstat != 1)
return 0;
/* Is the call to VerifyVCache really necessary? */
code = afs_VerifyVCache(tvc, areq);
if (code)
goto done;
if (!state->nonblock) {
ObtainWriteLock(&tvc->lock, 599);
code = EvalMountPoint(tvc, NULL, &tvolp, areq);
ReleaseWriteLock(&tvc->lock);
if (code)
goto done;
if (tvolp) {
tvolp->dotdot = tvc->fid;
tvolp->dotdot.Fid.Vnode = tvc->parentVnode;
tvolp->dotdot.Fid.Unique = tvc->parentUnique;
}
}
if (tvc->mvid && (tvc->states & CMValid)) {
if (state->nonblock) {
afs_int32 retry;
do {
retry = 0;
ObtainWriteLock(&afs_xvcache, 597);
root_vp = afs_FindVCache(tvc->mvid, 0, 0, &retry, 0);
if (root_vp && retry) {
ReleaseWriteLock(&afs_xvcache);
afs_PutVCache(root_vp, 0);
}
} while (root_vp && retry);
ReleaseWriteLock(&afs_xvcache);
} else {
root_vp = afs_GetVCache(tvc->mvid, areq, NULL, NULL, WRITE_LOCK);
}
if (!root_vp) {
code = state->nonblock ? 0 : ENOENT;
goto done;
}
if (tvolp) {
/* Is this always kosher? Perhaps we should instead use
* NBObtainWriteLock to avoid potential deadlock.
*/
ObtainWriteLock(&root_vp->lock, 598);
if (!root_vp->mvid)
root_vp->mvid = osi_AllocSmallSpace(sizeof(struct VenusFid));
*root_vp->mvid = tvolp->dotdot;
ReleaseWriteLock(&root_vp->lock);
}
state->need_release = 1;
state->root_vp = root_vp;
*avcp = root_vp;
code = 0;
} else {
code = state->nonblock ? 0 : ENOENT;
}
done:
if (tvolp)
afs_PutVolume(tvolp, WRITE_LOCK);
return code;
}
/*
* afs_TryEvalFakeStat
*
* Same as afs_EvalFakeStat, but tries not to talk to remote servers
* and only evaluate the mount point if all the data is already in
* local caches.
*
* Returns 0 if everything succeeds and *avcp points to a valid
* vcache entry (possibly evaluated).
*/
int
afs_TryEvalFakeStat(avcp, state, areq)
struct vcache **avcp;
struct afs_fakestat_state *state;
struct vrequest *areq;
{
state->nonblock = 1;
return afs_EvalFakeStat(avcp, state, areq);
}
/*
* afs_PutFakeStat
*
* Perform any necessary cleanup at the end of a vnode op, given that
* afs_InitFakeStat was previously called with this state.
*/
void
afs_PutFakeStat(state)
struct afs_fakestat_state *state;
{
osi_Assert(state->valid == 1);
if (state->need_release)
afs_PutVCache(state->root_vp, 0);
state->valid = 0;
}
afs_ENameOK(aname)
register char *aname; {
@ -932,8 +1082,17 @@ afs_lookup(adp, aname, avcp, acred)
int no_read_access = 0;
struct sysname_info sysState; /* used only for @sys checking */
int dynrootRetry = 1;
struct afs_fakestat_state fakestate;
AFS_STATCNT(afs_lookup);
afs_InitFakeStat(&fakestate);
if (code = afs_InitReq(&treq, acred))
goto done;
code = afs_EvalFakeStat(&adp, &fakestate, &treq);
if (code)
goto done;
#ifdef AFS_OSF_ENV
ndp->ni_dvp = AFSTOV(adp);
memcpy(aname, ndp->ni_ptr, ndp->ni_namelen);
@ -942,10 +1101,6 @@ afs_lookup(adp, aname, avcp, acred)
*avcp = (struct vcache *) 0; /* Since some callers don't initialize it */
if (code = afs_InitReq(&treq, acred)) {
goto done;
}
/* come back to here if we encounter a non-existent object in a read-only
volume's directory */
@ -1232,9 +1387,9 @@ afs_lookup(adp, aname, avcp, acred)
if (!(flags & AFS_LOOKUP_NOEVAL))
/* don't eval mount points */
#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
if (tvc->mvstat == 1) {
/* a mt point, possibly unevaluated */
struct volume *tvolp;
if (!afs_fakestat_enable && tvc->mvstat == 1) {
/* a mt point, possibly unevaluated */
struct volume *tvolp;
ObtainWriteLock(&tvc->lock,133);
code = EvalMountPoint(tvc, adp, &tvolp, &treq);
@ -1334,6 +1489,7 @@ done:
if (!FidCmp(&(tvc->fid), &(adp->fid))) {
afs_PutVCache(*avcp, WRITE_LOCK);
*avcp = NULL;
afs_PutFakeStat(&fakestate);
return afs_CheckCode(EISDIR, &treq, 18);
}
}
@ -1357,6 +1513,7 @@ done:
/* So Linux inode cache is up to date. */
code = afs_VerifyVCache(tvc, &treq);
#else
afs_PutFakeStat(&fakestate);
return 0; /* can't have been any errors if hit and !code */
#endif
}
@ -1370,5 +1527,6 @@ done:
*avcp = (struct vcache *)0;
}
afs_PutFakeStat(&fakestate);
return code;
}

View 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,

View File

@ -483,6 +483,7 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
struct DirEntry *ode = 0, *nde = 0;
int o_slen = 0, n_slen = 0;
afs_uint32 us;
struct afs_fakestat_state fakestate;
#if defined(AFS_SGI53_ENV)
afs_int32 use64BitDirent;
#endif /* defined(AFS_SGI53_ENV) */
@ -535,6 +536,9 @@ afs_readdir(OSI_VC_ARG(avc), auio, acred)
return code;
}
/* update the cache entry */
afs_InitFakeStat(&fakestate);
code = afs_EvalFakeStat(&avc, &fakestate, &treq);
if (code) goto done;
tagain:
code = afs_VerifyVCache(avc, &treq);
if (code) goto done;
@ -779,6 +783,7 @@ done:
#ifdef AFS_HPUX_ENV
osi_FreeSmallSpace((char *)sdirEntry);
#endif
afs_PutFakeStat(&fakestate);
code = afs_CheckCode(code, &treq, 28);
return code;
}
@ -809,6 +814,7 @@ afs1_readdir(avc, auio, acred)
struct minnfs_direct *sdirEntry = (struct minnfs_direct *)osi_AllocSmallSpace(sizeof(struct min_direct));
afs_int32 rlen;
#endif
struct afs_fakestat_state fakestate;
AFS_STATCNT(afs_readdir);
#if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV)
@ -820,6 +826,15 @@ afs1_readdir(avc, auio, acred)
#endif
return code;
}
afs_InitFakeStat(&fakestate);
code = afs_EvalFakeStat(&fakestate, &avc, &treq);
if (code) {
#ifdef AFS_HPUX_ENV
osi_FreeSmallSpace((char *)sdirEntry);
#endif
afs_PutFakeStat(&fakestate);
return code;
}
/* update the cache entry */
tagain:
code = afs_VerifyVCache(avc, &treq);
@ -1014,6 +1029,7 @@ done:
#if defined(AFS_HPUX_ENV) || defined(AFS_OSF_ENV)
osi_FreeSmallSpace((char *)sdirEntry);
#endif
afs_PutFakeStat(&fakestate);
code = afs_CheckCode(code, &treq, 29);
return code;
}

View File

@ -230,6 +230,7 @@ afs_remove(OSI_VC_ARG(adp), aname, acred)
afs_size_t offset, len;
struct AFSFetchStatus OutDirStatus;
struct AFSVolSync tsync;
struct afs_fakestat_state fakestate;
XSTATS_DECLS
OSI_VC_CONVERT(adp)
@ -241,23 +242,37 @@ afs_remove(OSI_VC_ARG(adp), aname, acred)
tvc = (struct vcache *)ndp->ni_vp; /* should never be null */
#endif
/* Check if this is dynroot */
if (afs_IsDynroot(adp)) {
#ifdef AFS_OSF_ENV
afs_PutVCache(adp, 0);
afs_PutVCache(tvc, 0);
#endif
return afs_DynrootVOPRemove(adp, acred, aname);
}
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 code;
return code;
}
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);
#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;
}
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;
}

View File

@ -31,11 +31,12 @@ extern afs_rwlock_t afs_xcbhash;
/* Note that we don't set CDirty here, this is OK because the rename
* RPC is called synchronously. */
afsrename(aodp, aname1, andp, aname2, acred)
register struct vcache *aodp, *andp;
afsrename(aodp, aname1, andp, aname2, acred, areq)
struct vcache *aodp, *andp;
char *aname1, *aname2;
struct AFS_UCRED *acred; {
struct vrequest treq;
struct AFS_UCRED *acred;
struct vrequest *areq;
{
register struct conn *tc;
register afs_int32 code;
afs_int32 returnCode;
@ -53,8 +54,6 @@ afsrename(aodp, aname1, andp, aname2, acred)
ICL_TYPE_STRING, aname1, ICL_TYPE_POINTER, andp,
ICL_TYPE_STRING, aname2);
if (code = afs_InitReq(&treq, acred)) return code;
if (strlen(aname1) > AFSNAMEMAX || strlen(aname2) > AFSNAMEMAX) {
code = ENAMETOOLONG;
goto done;
@ -62,9 +61,9 @@ afsrename(aodp, aname1, andp, aname2, acred)
/* verify the latest versions of the stat cache entries */
tagain:
code = afs_VerifyVCache(aodp, &treq);
code = afs_VerifyVCache(aodp, areq);
if (code) goto done;
code = afs_VerifyVCache(andp, &treq);
code = afs_VerifyVCache(andp, areq);
if (code) goto done;
/* lock in appropriate order, after some checks */
@ -83,7 +82,7 @@ tagain:
goto done;
}
ObtainWriteLock(&andp->lock,147);
tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, &treq, &offset, &len, 0);
tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
if (!tdc1) {
code = ENOENT;
} else {
@ -101,7 +100,7 @@ tagain:
ObtainWriteLock(&aodp->lock,149);
tdc2 = afs_FindDCache(andp, 0);
if (tdc2) ObtainWriteLock(&tdc2->lock, 644);
tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, &treq, &offset, &len, 0);
tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
if (tdc1)
ObtainWriteLock(&tdc1->lock, 645);
else
@ -110,7 +109,7 @@ tagain:
else {
ObtainWriteLock(&aodp->lock,150); /* lock smaller one first */
ObtainWriteLock(&andp->lock,557);
tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, &treq, &offset, &len, 0);
tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
if (tdc1)
ObtainWriteLock(&tdc1->lock, 646);
else
@ -166,7 +165,7 @@ tagain:
/* locks are now set, proceed to do the real work */
do {
tc = afs_Conn(&aodp->fid, &treq, SHARED_LOCK);
tc = afs_Conn(&aodp->fid, areq, SHARED_LOCK);
if (tc) {
XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RENAME);
#ifdef RX_ENABLE_LOCKS
@ -182,7 +181,7 @@ tagain:
} else code = -1;
} while
(afs_Analyze(tc, code, &andp->fid, &treq,
(afs_Analyze(tc, code, &andp->fid, areq,
AFS_STATS_FS_RPCIDX_RENAME, SHARED_LOCK, (struct cell *)0));
returnCode = code; /* remember for later */
@ -296,11 +295,11 @@ tagain:
unlinkFid.Cell = aodp->fid.Cell;
tvc = (struct vcache *)0;
if (!unlinkFid.Fid.Unique) {
tvc = afs_LookupVCache(&unlinkFid, &treq, (afs_int32 *)0, WRITE_LOCK,
tvc = afs_LookupVCache(&unlinkFid, areq, (afs_int32 *)0, WRITE_LOCK,
aodp, aname1);
}
if (!tvc) /* lookup failed or wasn't called */
tvc = afs_GetVCache(&unlinkFid, &treq, (afs_int32 *)0,
tvc = afs_GetVCache(&unlinkFid, areq, (afs_int32 *)0,
(struct vcache*)0, WRITE_LOCK);
if (tvc) {
@ -334,9 +333,9 @@ tagain:
fileFid.Fid.Volume = aodp->fid.Fid.Volume;
fileFid.Cell = aodp->fid.Cell;
if (!fileFid.Fid.Unique)
tvc = afs_LookupVCache(&fileFid, &treq, (afs_int32 *)0, WRITE_LOCK, andp, aname2);
tvc = afs_LookupVCache(&fileFid, areq, (afs_int32 *)0, WRITE_LOCK, andp, aname2);
else
tvc = afs_GetVCache(&fileFid, &treq, (afs_int32 *)0,
tvc = afs_GetVCache(&fileFid, areq, (afs_int32 *)0,
(struct vcache*)0, WRITE_LOCK);
if (tvc && (vType(tvc) == VDIR)) {
ObtainWriteLock(&tvc->lock,152);
@ -360,16 +359,15 @@ tagain:
}
code = returnCode;
done:
code = afs_CheckCode(code, &treq, 25);
return code;
}
#ifdef AFS_OSF_ENV
afs_rename(fndp, tndp)
struct nameidata *fndp, *tndp; {
register struct vcache *aodp = VTOAFS(fndp->ni_dvp);
struct vcache *aodp = VTOAFS(fndp->ni_dvp);
char *aname1 = fndp->ni_dent.d_name;
register struct vcache *andp = VTOAFS(tndp->ni_dvp);
struct vcache *andp = VTOAFS(tndp->ni_dvp);
char *aname2 = tndp->ni_dent.d_name;
struct ucred *acred = tndp->ni_cred;
#else /* AFS_OSF_ENV */
@ -380,14 +378,28 @@ afs_rename(OSI_VC_ARG(aodp), aname1, andp, aname2, npnp, acred)
afs_rename(OSI_VC_ARG(aodp), aname1, andp, aname2, acred)
#endif
OSI_VC_DECL(aodp);
register struct vcache *andp;
struct vcache *andp;
char *aname1, *aname2;
struct AFS_UCRED *acred; {
#endif
register afs_int32 code;
struct afs_fakestat_state ofakestate;
struct afs_fakestat_state nfakestate;
struct vrequest treq;
OSI_VC_CONVERT(aodp)
code = afsrename(aodp, aname1, andp, aname2, acred);
code = afs_InitReq(&treq, acred);
if (code) return code;
afs_InitFakeStat(&ofakestate);
afs_InitFakeStat(&nfakestate);
code = afs_EvalFakeStat(&aodp, &ofakestate, &treq);
if (code) goto done;
code = afs_EvalFakeStat(&andp, &nfakestate, &treq);
if (code) goto done;
code = afsrename(aodp, aname1, andp, aname2, acred, &treq);
done:
afs_PutFakeStat(&ofakestate);
afs_PutFakeStat(&nfakestate);
#ifdef AFS_OSF_ENV
AFS_RELE(tndp->ni_dvp);
if (tndp->ni_vp != NULL) {
@ -396,5 +408,6 @@ afs_rename(OSI_VC_ARG(aodp), aname1, andp, aname2, acred)
AFS_RELE(fndp->ni_dvp);
AFS_RELE(fndp->ni_vp);
#endif /* AFS_OSF_ENV */
code = afs_CheckCode(code, &treq, 25);
return code;
}

View File

@ -72,6 +72,7 @@ afs_symlink
struct AFSCallBack CallBack;
struct AFSVolSync tsync;
struct volume* volp=0;
struct afs_fakestat_state fakestate;
XSTATS_DECLS
OSI_VC_CONVERT(adp)
@ -79,23 +80,28 @@ afs_symlink
afs_Trace2(afs_iclSetp, CM_TRACE_SYMLINK, ICL_TYPE_POINTER, adp,
ICL_TYPE_STRING, aname);
if (code = afs_InitReq(&treq, acred))
goto done2;
afs_InitFakeStat(&fakestate);
code = afs_EvalFakeStat(&adp, &fakestate, &treq);
if (code)
goto done;
if (strlen(aname) > AFSNAMEMAX || strlen(atargetName) > AFSPATHMAX) {
code = ENAMETOOLONG;
goto done2;
goto done;
}
if (afs_IsDynroot(adp)) {
code = afs_DynrootVOPSymlink(adp, acred, aname, atargetName);
goto done2;
goto done;
}
if (code = afs_InitReq(&treq, acred))
goto done2;
code = afs_VerifyVCache(adp, &treq);
if (code) {
code = afs_CheckCode(code, &treq, 30);
goto done2;
code = afs_CheckCode(code, &treq, 30);
goto done;
}
/** If the volume is read-only, return error without making an RPC to the
@ -103,7 +109,7 @@ afs_symlink
*/
if ( adp->states & CRO ) {
code = EROFS;
goto done2;
goto done;
}
InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE;
@ -223,6 +229,7 @@ afs_symlink
afs_PutVCache(tvc, WRITE_LOCK);
code = 0;
done:
afs_PutFakeStat(&fakestate);
if ( volp )
afs_PutVolume(volp, READ_LOCK);
code = afs_CheckCode(code, &treq, 31);
@ -342,11 +349,15 @@ afs_readlink(OSI_VC_ARG(avc), auio, acred)
register afs_int32 code;
struct vrequest treq;
register char *tp;
struct afs_fakestat_state fakestat;
OSI_VC_CONVERT(avc)
AFS_STATCNT(afs_readlink);
afs_Trace1(afs_iclSetp, CM_TRACE_READLINK, ICL_TYPE_POINTER, avc);
if (code = afs_InitReq(&treq, acred)) return code;
afs_InitFakeStat(&fakestat);
code = afs_EvalFakeStat(&avc, &fakestat, &treq);
if (code) goto done;
code = afs_VerifyVCache(avc, &treq);
if (code) goto done;
if (vType(avc) != VLNK) {
@ -365,6 +376,7 @@ afs_readlink(OSI_VC_ARG(avc), auio, acred)
}
ReleaseWriteLock(&avc->lock);
done:
afs_PutFakeStat(&fakestat);
code = afs_CheckCode(code, &treq, 32);
return code;
}

View File

@ -725,10 +725,12 @@ afs_closex(afd)
afs_int32 flags;
int closeDone;
afs_int32 code = 0;
struct afs_fakestat_state fakestat;
AFS_STATCNT(afs_closex);
/* setup the credentials */
if (code = afs_InitReq(&treq, u.u_cred)) return code;
afs_InitFakeStat(&fakestat);
closeDone = 0;
/* we're the last one. If we're an AFS vnode, clear the flags,
@ -737,6 +739,11 @@ afs_closex(afd)
if (afd->f_type == DTYPE_VNODE) {
tvc = VTOAFS(afd->f_data);
if (IsAfsVnode(AFSTOV(tvc))) {
code = afs_EvalFakeStat(&tvc, &fakestat, &treq);
if (code) {
afs_PutFakeStat(&fakestat);
return code;
}
VN_HOLD(AFSTOV(tvc));
flags = afd->f_flag & (FSHLOCK | FEXLOCK);
afd->f_flag &= ~(FSHLOCK | FEXLOCK);
@ -760,6 +767,7 @@ afs_closex(afd)
if (!closeDone) {
code = vno_close(afd);
}
afs_PutFakeStat(&fakestat);
return code; /* return code from vnode layer */
}
#endif
@ -800,41 +808,44 @@ afs_close(OSI_VC_ARG(avc), aflags, acred)
afs_int32 aflags;
struct AFS_UCRED *acred;
{
register afs_int32 code, initreq=0;
register afs_int32 code;
register struct brequest *tb;
struct vrequest treq;
#ifdef AFS_SGI65_ENV
struct flid flid;
#endif
struct afs_fakestat_state fakestat;
OSI_VC_CONVERT(avc)
AFS_STATCNT(afs_close);
afs_Trace2(afs_iclSetp, CM_TRACE_CLOSE, ICL_TYPE_POINTER, avc,
ICL_TYPE_INT32, aflags);
code = afs_InitReq(&treq, acred);
if (code) return code;
afs_InitFakeStat(&fakestat);
code = afs_EvalFakeStat(&avc, &fakestat, &treq);
if (code) {
afs_PutFakeStat(&fakestat);
return code;
}
#ifdef AFS_SUN5_ENV
if (avc->flockCount) {
if (code = afs_InitReq(&treq, acred)) return code;
initreq = 1;
HandleFlock(avc, LOCK_UN, &treq, 0, 1/*onlymine*/);
}
#endif
#if defined(AFS_SGI_ENV)
if (!lastclose)
if (!lastclose) {
afs_PutFakeStat(&fakestat);
return 0;
}
#else
#if defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV)
if (count > 1) {
/* The vfs layer may call this repeatedly with higher "count"; only on the last close (i.e. count = 1) we should actually proceed with the close. */
afs_PutFakeStat(&fakestat);
return 0;
}
#endif
#ifdef AFS_SUN5_ENV
if (!initreq) {
#endif
#endif
if (code = afs_InitReq(&treq, acred)) return code;
#ifdef AFS_SUN5_ENV
}
#endif
#ifndef AFS_SUN5_ENV
#if defined(AFS_SGI_ENV)
@ -957,6 +968,7 @@ afs_close(OSI_VC_ARG(avc), aflags, acred)
afs_remunlink(avc, 1); /* ignore any return code */
}
#endif
afs_PutFakeStat(&fakestat);
code = afs_CheckCode(code, &treq, 5);
return code;
}

View File

@ -627,7 +627,7 @@ struct vcache {
#ifdef AFS_FBSD_ENV
struct lock rwlock;
#endif
afs_int32 parentVnode; /* Parent dir, if a file. */
afs_int32 parentVnode; /* Parent dir, if a file. */
afs_int32 parentUnique;
struct VenusFid *mvid; /* Either parent dir (if root) or root (if mt pt) */
char *linkData; /* Link data if a symlink. */
@ -1181,5 +1181,18 @@ extern int afs_norefpanic;
#endif /* AFS_SGI62_ENV */
#endif
/* fakestat support: opaque storage for afs_EvalFakeStat to remember
* what vcache should be released.
*/
struct afs_fakestat_state {
char valid;
char did_eval;
char need_release;
char nonblock;
struct vcache *root_vp;
};
extern int afs_fakestat_enable;
#endif /* _AFS_H_ */

View File

@ -662,6 +662,10 @@ long parm, parm2, parm3, parm4, parm5, parm6;
else if (parm == AFSOP_SET_DYNROOT) {
code = afs_SetDynrootEnable(parm2);
}
else if (parm == AFSOP_SET_FAKESTAT) {
afs_fakestat_enable = parm2;
code = 0;
}
else
code = EINVAL;

View File

@ -1036,7 +1036,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
afs_HandlePioctl(avc, acom, ablob, afollow, acred)
register struct vcache *avc;
struct vcache *avc;
afs_int32 acom;
struct AFS_UCRED **acred;
register struct afs_ioctl *ablob;
@ -1049,11 +1049,20 @@ afs_HandlePioctl(avc, acom, ablob, afollow, acred)
char *inData, *outData;
int (*(*pioctlSw))();
int pioctlSwSize;
struct afs_fakestat_state fakestate;
afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
AFS_STATCNT(HandlePioctl);
if (code = afs_InitReq(&treq, *acred)) return code;
afs_InitFakeStat(&fakestate);
if (avc) {
code = afs_EvalFakeStat(&avc, &fakestate, &treq);
if (code) {
afs_PutFakeStat(&fakestate);
return code;
}
}
device = (acom & 0xff00) >> 8;
switch (device) {
case 'V': /* Original pioctl's */
@ -1065,11 +1074,13 @@ afs_HandlePioctl(avc, acom, ablob, afollow, acred)
pioctlSwSize = sizeof(CpioctlSw);
break;
default:
afs_PutFakeStat(&fakestate);
return EINVAL;
}
function = acom & 0xff;
if (function >= (pioctlSwSize / sizeof(char *))) {
return EINVAL; /* out of range */
afs_PutFakeStat(&fakestate);
return EINVAL; /* out of range */
}
inSize = ablob->in_size;
if (inSize >= PIGGYSIZE) return E2BIG;
@ -1079,8 +1090,9 @@ afs_HandlePioctl(avc, acom, ablob, afollow, acred)
}
else code = 0;
if (code) {
osi_FreeLargeSpace(inData);
return code;
osi_FreeLargeSpace(inData);
afs_PutFakeStat(&fakestate);
return code;
}
outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
outSize = 0;
@ -1096,6 +1108,7 @@ afs_HandlePioctl(avc, acom, ablob, afollow, acred)
AFS_COPYOUT(outData, ablob->out, outSize, code);
}
osi_FreeLargeSpace(outData);
afs_PutFakeStat(&fakestate);
return afs_CheckCode(code, &treq, 41);
}
@ -1719,7 +1732,7 @@ static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
code = ENOENT;
goto out;
}
if (vType(tvc) != VLNK) {
if (tvc->mvstat != 1) {
afs_PutVCache(tvc, WRITE_LOCK);
code = EINVAL;
goto out;
@ -2504,7 +2517,7 @@ static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
afs_PutDCache(tdc);
goto out;
}
if (vType(tvc) != VLNK) {
if (tvc->mvstat != 1) {
afs_PutDCache(tdc);
afs_PutVCache(tvc, WRITE_LOCK);
code = EINVAL;
@ -3703,7 +3716,7 @@ static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
code = ENOENT;
goto out;
}
if (vType(tvc) != VLNK) {
if (tvc->mvstat != 1) {
afs_PutVCache(tvc, WRITE_LOCK);
code = EINVAL;
goto out;

View File

@ -1542,9 +1542,16 @@ afs_ProcessFS(avc, astat, areq)
avc->m.Mode |= S_IFDIR;
}
else if (astat->FileType == SymbolicLink) {
vSetType(avc, VLNK);
avc->m.Mode |= S_IFLNK;
if ((avc->m.Mode & 0111) == 0) avc->mvstat = 1;
if (afs_fakestat_enable && (avc->m.Mode & 0111) == 0) {
vSetType(avc, VDIR);
avc->m.Mode |= S_IFDIR;
} else {
vSetType(avc, VLNK);
avc->m.Mode |= S_IFLNK;
}
if ((avc->m.Mode & 0111) == 0) {
avc->mvstat = 1;
}
}
avc->anyAccess = astat->AnonymousAccess;
#ifdef badidea

View File

@ -240,6 +240,7 @@ static int enable_process_stats = 0; /* enable rx stats */
static int enable_afsdb = 0; /* enable AFSDB support */
#endif
static int enable_dynroot = 0; /* enable dynroot support */
static int enable_fakestat = 0; /* enable fakestat support */
#ifdef notdef
static int inodes = 60; /* VERY conservative, but has to be */
#endif
@ -1326,6 +1327,10 @@ mainproc(as, arock)
/* -dynroot */
enable_dynroot = 1;
}
if (as->parms[27].items) {
/* -fakestat */
enable_fakestat = 1;
}
/*
* Pull out all the configuration info for the workstation's AFS cache and
@ -1565,6 +1570,14 @@ mainproc(as, arock)
printf("%s: Error enabling dynroot support.\n", rn);
}
if (enable_fakestat) {
if (afsd_verbose)
printf("%s: Enabling fakestat support in kernel.\n", rn);
code = call_syscall(AFSOP_SET_FAKESTAT, 1);
if (code)
printf("%s: Error enabling fakestat support.\n", rn);
}
/* Initialize AFS daemon threads. */
if (afsd_verbose)
printf("%s: Forking AFS daemon.\n", rn);
@ -1918,6 +1931,7 @@ char **argv; {
), "Enable AFSDB support");
cmd_AddParm(ts, "-files_per_subdir", CMD_SINGLE, CMD_OPTIONAL, "log(2) of the number of cache files per cache subdirectory");
cmd_AddParm(ts, "-dynroot", CMD_FLAG, CMD_OPTIONAL, "Enable dynroot support");
cmd_AddParm(ts, "-fakestat", CMD_FLAG, CMD_OPTIONAL, "Enable fakestat support");
return (cmd_Dispatch(argc, argv));
}

View 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