From 64cc7f0ca7a44bb214396c829268a541ab286c69 Mon Sep 17 00:00:00 2001 From: Andrew Deason Date: Wed, 14 May 2014 19:56:58 -0500 Subject: [PATCH] afs: Create afs_StaleVCache In numerous different places in the code, we do something like this to mark a vcache as stale: ObtainWriteLock(&afs_xcbhash, somenumber); avc->f.states &= ~CStatd; afs_DequeueCallback(avc); ReleaseWriteLock(&afs_xcbhash); if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR)) osi_dnlc_purgedp(avc); There are some variations here and there, but all locations usually involve at least some code like that. But they all do the same general thing: invalidate a vcache so we hit the net the next time we need that vcache. In order to make it easier to modify what happens when we invalidate a vcache, and just to improve the code, take all of these instances and put the functionality in a single function, called afs_StaleVCache, which marks the vcache as 'stale'. To handle a few different situations that must be handled, we have some flags that can also be passed to the new function. These are primarily necessary to handle variations in the circumstances under which we hit this code path; for instance, we may already have afs_xcbhash locked, or we may be invalidating the entire osidnlc (if we're invalidating vcaches in bulk, for example). This should result in the same general behavior in all cases. The only slight differences in a few cases is that we hold locks for a few more operations than we used to; for example, we may clear an osidnlc entry while holding the vcache lock. But these are minor and shouldn't result in any actual differences in behavior. So, this commit should just be code reorganization and should incur no behavior change. However, this reorganization is complex, and should not be considered a simple risk-free refactoring. [kaduk@mit.edu: implement Tom Keiser's suggestion of a third argument to afs_StaleVCacheFlags, add AFS_STALEVC_CLEARCB and AFS_STALEVC_SKIP_DNLC_FOR_INIT_FLUSHED] Change-Id: I2b2f606c56d5b22826eeb98471187165260c7b91 Reviewed-on: https://gerrit.openafs.org/11790 Reviewed-by: Mark Vitale Tested-by: BuildBot Reviewed-by: Benjamin Kaduk --- src/afs/VNOPS/afs_vnop_attrs.c | 7 +- src/afs/VNOPS/afs_vnop_create.c | 14 +-- src/afs/VNOPS/afs_vnop_dirops.c | 12 +-- src/afs/VNOPS/afs_vnop_link.c | 13 +-- src/afs/VNOPS/afs_vnop_lookup.c | 24 ++--- src/afs/VNOPS/afs_vnop_remove.c | 6 +- src/afs/VNOPS/afs_vnop_rename.c | 8 +- src/afs/VNOPS/afs_vnop_symlink.c | 6 +- src/afs/afs_analyze.c | 3 +- src/afs/afs_bypasscache.c | 17 ++-- src/afs/afs_callback.c | 22 ++--- src/afs/afs_cbqueue.c | 37 +++----- src/afs/afs_dcache.c | 15 +--- src/afs/afs_dynroot.c | 3 +- src/afs/afs_pioctl.c | 24 ++--- src/afs/afs_prototypes.h | 32 +++++++ src/afs/afs_segments.c | 7 +- src/afs/afs_vcache.c | 185 ++++++++++++++++++++------------------- src/afs/afs_volume.c | 7 +- 19 files changed, 184 insertions(+), 258 deletions(-) diff --git a/src/afs/VNOPS/afs_vnop_attrs.c b/src/afs/VNOPS/afs_vnop_attrs.c index 3b065fd..26062d1 100644 --- a/src/afs/VNOPS/afs_vnop_attrs.c +++ b/src/afs/VNOPS/afs_vnop_attrs.c @@ -611,13 +611,8 @@ afs_setattr(OSI_VC_DECL(avc), struct vattr *attrs, ReleaseSharedLock(&avc->lock); /* release lock */ } if (code) { - ObtainWriteLock(&afs_xcbhash, 487); - afs_DequeueCallback(avc); - avc->f.states &= ~CStatd; - ReleaseWriteLock(&afs_xcbhash); - if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR)) - osi_dnlc_purgedp(avc); /* error? erase any changes we made to vcache entry */ + afs_StaleVCache(avc); } } else { ObtainSharedLock(&avc->lock, 712); diff --git a/src/afs/VNOPS/afs_vnop_create.c b/src/afs/VNOPS/afs_vnop_create.c index a2d600d..2fb580c 100644 --- a/src/afs/VNOPS/afs_vnop_create.c +++ b/src/afs/VNOPS/afs_vnop_create.c @@ -356,11 +356,7 @@ afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, if (code) { if (code < 0) { - ObtainWriteLock(&afs_xcbhash, 488); - afs_DequeueCallback(adp); - adp->f.states &= ~CStatd; - ReleaseWriteLock(&afs_xcbhash); - osi_dnlc_purgedp(adp); + afs_StaleVCache(adp); } ReleaseWriteLock(&adp->lock); if (tdc) { @@ -451,11 +447,9 @@ afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), volp); } } else { - afs_DequeueCallback(tvc); - tvc->f.states &= ~(CStatd | CUnique); - tvc->callback = 0; - if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR)) - osi_dnlc_purgedp(tvc); + afs_StaleVCacheFlags(tvc, + AFS_STALEVC_CBLOCKED | AFS_STALEVC_CLEARCB, + CUnique); } ReleaseWriteLock(&afs_xcbhash); if (AFS_IS_DISCON_RW) { diff --git a/src/afs/VNOPS/afs_vnop_dirops.c b/src/afs/VNOPS/afs_vnop_dirops.c index d1d2ab2..5966513 100644 --- a/src/afs/VNOPS/afs_vnop_dirops.c +++ b/src/afs/VNOPS/afs_vnop_dirops.c @@ -135,11 +135,7 @@ afs_mkdir(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, if (code) { if (code < 0) { - ObtainWriteLock(&afs_xcbhash, 490); - afs_DequeueCallback(adp); - adp->f.states &= ~CStatd; - ReleaseWriteLock(&afs_xcbhash); - osi_dnlc_purgedp(adp); + afs_StaleVCache(adp); } ReleaseWriteLock(&adp->lock); if (tdc) @@ -370,11 +366,7 @@ afs_rmdir(OSI_VC_DECL(adp), char *aname, afs_ucred_t *acred) } if (code < 0) { - ObtainWriteLock(&afs_xcbhash, 491); - afs_DequeueCallback(adp); - adp->f.states &= ~CStatd; - ReleaseWriteLock(&afs_xcbhash); - osi_dnlc_purgedp(adp); + afs_StaleVCache(adp); } ReleaseWriteLock(&adp->lock); goto done; diff --git a/src/afs/VNOPS/afs_vnop_link.c b/src/afs/VNOPS/afs_vnop_link.c index 2a88443..f57b7ad 100644 --- a/src/afs/VNOPS/afs_vnop_link.c +++ b/src/afs/VNOPS/afs_vnop_link.c @@ -123,11 +123,7 @@ afs_link(struct vcache *avc, OSI_VC_DECL(adp), char *aname, if (tdc) afs_PutDCache(tdc); if (code < 0) { - ObtainWriteLock(&afs_xcbhash, 492); - afs_DequeueCallback(adp); - adp->f.states &= ~CStatd; - ReleaseWriteLock(&afs_xcbhash); - osi_dnlc_purgedp(adp); + afs_StaleVCache(adp); } ReleaseWriteLock(&adp->lock); goto done; @@ -158,12 +154,7 @@ afs_link(struct vcache *avc, OSI_VC_DECL(adp), char *aname, * returned in ustat is the most recent to store in the file's * cache entry */ - ObtainWriteLock(&afs_xcbhash, 493); - afs_DequeueCallback(avc); - avc->f.states &= ~CStatd; /* don't really know new link count */ - ReleaseWriteLock(&afs_xcbhash); - if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR)) - osi_dnlc_purgedp(avc); + afs_StaleVCache(avc); /* don't really know new link count */ ReleaseWriteLock(&avc->lock); code = 0; done: diff --git a/src/afs/VNOPS/afs_vnop_lookup.c b/src/afs/VNOPS/afs_vnop_lookup.c index ff641e0..c3c3963 100644 --- a/src/afs/VNOPS/afs_vnop_lookup.c +++ b/src/afs/VNOPS/afs_vnop_lookup.c @@ -1266,11 +1266,9 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp) tvcp->f.states |= CStatd; afs_QueueCallback(tvcp, CBHash(3600), volp); } else { - tvcp->callback = 0; - tvcp->f.states &= ~(CStatd | CUnique); - afs_DequeueCallback(tvcp); - if ((tvcp->f.states & CForeign) || (vType(tvcp) == VDIR)) - osi_dnlc_purgedp(tvcp); /* if it (could be) a directory */ + afs_StaleVCacheFlags(tvcp, + AFS_STALEVC_CBLOCKED | AFS_STALEVC_CLEARCB, + CUnique); } #ifdef AFS_DARWIN80_ENV /* reclaim->FlushVCache will need xcbhash */ @@ -1280,11 +1278,9 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp) code = afs_darwin_finalizevnode(tvcp, NULL, NULL, 0, 1); if (code) { /* It's gonna get recycled - shouldn't happen */ - tvcp->callback = 0; - tvcp->f.states &= ~(CStatd | CUnique); - afs_DequeueCallback(tvcp); - if ((tvcp->f.states & CForeign) || (vType(tvcp) == VDIR)) - osi_dnlc_purgedp(tvcp); /* if it (could be) a directory */ + afs_StaleVCacheFlags(tvcp, + AFS_STALEVC_CBLOCKED | AFS_STALEVC_CLEARCB, + CUnique); } else /* re-acquire the usecount that finalizevnode disposed of */ vnode_ref(AFSTOV(tvcp)); @@ -1890,12 +1886,8 @@ afs_lookup(OSI_VC_DECL(adp), char *aname, struct vcache **avcp, afs_ucred_t *acr if (tv) { if (tv->states & VRO) { pass = 1; /* try this *once* */ - ObtainWriteLock(&afs_xcbhash, 495); - afs_DequeueCallback(adp); - /* re-stat to get later version */ - adp->f.states &= ~CStatd; - ReleaseWriteLock(&afs_xcbhash); - osi_dnlc_purgedp(adp); + /* re-stat to get later version */ + afs_StaleVCache(adp); afs_PutVolume(tv, READ_LOCK); goto redo; } diff --git a/src/afs/VNOPS/afs_vnop_remove.c b/src/afs/VNOPS/afs_vnop_remove.c index c19c2a5..f1e1faf 100644 --- a/src/afs/VNOPS/afs_vnop_remove.c +++ b/src/afs/VNOPS/afs_vnop_remove.c @@ -93,11 +93,7 @@ afsremove(struct vcache *adp, struct dcache *tdc, afs_PutVCache(tvc); if (code < 0) { - ObtainWriteLock(&afs_xcbhash, 497); - afs_DequeueCallback(adp); - adp->f.states &= ~CStatd; - ReleaseWriteLock(&afs_xcbhash); - osi_dnlc_purgedp(adp); + afs_StaleVCache(adp); } ReleaseWriteLock(&adp->lock); code = afs_CheckCode(code, treqp, 21); diff --git a/src/afs/VNOPS/afs_vnop_rename.c b/src/afs/VNOPS/afs_vnop_rename.c index 7791784..2d4b9c1 100644 --- a/src/afs/VNOPS/afs_vnop_rename.c +++ b/src/afs/VNOPS/afs_vnop_rename.c @@ -320,13 +320,9 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp, /* if failed, server might have done something anyway, and * assume that we know about it */ ObtainWriteLock(&afs_xcbhash, 498); - afs_DequeueCallback(aodp); - afs_DequeueCallback(andp); - andp->f.states &= ~CStatd; - aodp->f.states &= ~CStatd; + afs_StaleVCacheFlags(aodp, AFS_STALEVC_CBLOCKED, 0); + afs_StaleVCacheFlags(andp, AFS_STALEVC_CBLOCKED, 0); ReleaseWriteLock(&afs_xcbhash); - osi_dnlc_purgedp(andp); - osi_dnlc_purgedp(aodp); } } diff --git a/src/afs/VNOPS/afs_vnop_symlink.c b/src/afs/VNOPS/afs_vnop_symlink.c index f608b2b..1dd4611 100644 --- a/src/afs/VNOPS/afs_vnop_symlink.c +++ b/src/afs/VNOPS/afs_vnop_symlink.c @@ -200,11 +200,7 @@ afs_symlink(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, ObtainWriteLock(&afs_xvcache, 40); if (code) { if (code < 0) { - ObtainWriteLock(&afs_xcbhash, 499); - afs_DequeueCallback(adp); - adp->f.states &= ~CStatd; - ReleaseWriteLock(&afs_xcbhash); - osi_dnlc_purgedp(adp); + afs_StaleVCache(adp); } ReleaseWriteLock(&adp->lock); ReleaseWriteLock(&afs_xvcache); diff --git a/src/afs/afs_analyze.c b/src/afs/afs_analyze.c index c0233ef..4bb212b 100644 --- a/src/afs/afs_analyze.c +++ b/src/afs/afs_analyze.c @@ -317,7 +317,8 @@ afs_ClearStatus(struct VenusFid *afid, int op, struct volume *avp) ObtainReadLock(&afs_xvcache); if ((tvc = afs_FindVCache(afid, 0, 0))) { ReleaseReadLock(&afs_xvcache); - tvc->f.states &= ~(CStatd | CUnique); + afs_StaleVCacheFlags(tvc, AFS_STALEVC_NOCB | AFS_STALEVC_NODNLC, + CUnique); afs_PutVCache(tvc); } else { ReleaseReadLock(&afs_xvcache); diff --git a/src/afs/afs_bypasscache.c b/src/afs/afs_bypasscache.c index 4c6fb9a..76973d9 100644 --- a/src/afs/afs_bypasscache.c +++ b/src/afs/afs_bypasscache.c @@ -166,16 +166,11 @@ afs_TransitionToBypass(struct vcache *avc, } } -#if 0 /* also cg2v, don't dequeue the callback */ - ObtainWriteLock(&afs_xcbhash, 956); - afs_DequeueCallback(avc); - ReleaseWriteLock(&afs_xcbhash); -#endif - avc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat */ + /* next reference will re-stat */ + afs_StaleVCacheFlags(avc, AFS_STALEVC_NOCB, CDirty); /* now find the disk cache entries */ afs_TryToSmush(avc, acred, 1); - osi_dnlc_purgedp(avc); if (avc->linkData && !(avc->f.states & CCore)) { afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1); avc->linkData = NULL; @@ -226,13 +221,11 @@ afs_TransitionToCaching(struct vcache *avc, goto done; /* Ok, we actually do need to flush */ - ObtainWriteLock(&afs_xcbhash, 957); - afs_DequeueCallback(avc); - avc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */ - ReleaseWriteLock(&afs_xcbhash); + /* next reference will re-stat cache entry */ + afs_StaleVCacheFlags(avc, 0, CDirty); + /* now find the disk cache entries */ afs_TryToSmush(avc, acred, 1); - osi_dnlc_purgedp(avc); if (avc->linkData && !(avc->f.states & CCore)) { afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1); avc->linkData = NULL; diff --git a/src/afs/afs_callback.c b/src/afs/afs_callback.c index c90f82f..61b2a75 100644 --- a/src/afs/afs_callback.c +++ b/src/afs/afs_callback.c @@ -473,17 +473,12 @@ loop1: #endif #endif ReleaseReadLock(&afs_xvcache); - ObtainWriteLock(&afs_xcbhash, 449); - afs_DequeueCallback(tvc); - tvc->f.states &= ~(CStatd | CUnique | CBulkFetching); + afs_StaleVCacheFlags(tvc, 0, CUnique | CBulkFetching); afs_allCBs++; if (tvc->f.fid.Fid.Vnode & 1) afs_oddCBs++; else afs_evenCBs++; - ReleaseWriteLock(&afs_xcbhash); - if ((tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))) - osi_dnlc_purgedp(tvc); afs_Trace3(afs_iclSetp, CM_TRACE_CALLBACK, ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, tvc->f.states, ICL_TYPE_INT32, @@ -561,12 +556,7 @@ loop2: #endif #endif ReleaseReadLock(&afs_xvcache); - ObtainWriteLock(&afs_xcbhash, 450); - afs_DequeueCallback(tvc); - tvc->f.states &= ~(CStatd | CUnique | CBulkFetching); - ReleaseWriteLock(&afs_xcbhash); - if ((tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))) - osi_dnlc_purgedp(tvc); + afs_StaleVCacheFlags(tvc, 0, CUnique | CBulkFetching); afs_Trace3(afs_iclSetp, CM_TRACE_CALLBACK, ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, tvc->f.states, ICL_TYPE_LONG, 0); @@ -745,11 +735,9 @@ SRXAFSCB_InitCallBackState(struct rx_call *a_call) for (i = 0; i < VCSIZE; i++) for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) { if (tvc->callback == ts) { - ObtainWriteLock(&afs_xcbhash, 451); - afs_DequeueCallback(tvc); - tvc->callback = NULL; - tvc->f.states &= ~(CStatd | CUnique | CBulkFetching); - ReleaseWriteLock(&afs_xcbhash); + afs_StaleVCacheFlags(tvc, AFS_STALEVC_NODNLC | + AFS_STALEVC_CLEARCB, + CUnique | CBulkFetching); } } diff --git a/src/afs/afs_cbqueue.c b/src/afs/afs_cbqueue.c index 2f52250..85b3247 100644 --- a/src/afs/afs_cbqueue.c +++ b/src/afs/afs_cbqueue.c @@ -216,12 +216,9 @@ afs_CheckCallbacks(unsigned int secs) if (!(tvp->serverHost[i]->flags & SRVR_ISDOWN)) { /* What about locking xvcache or vrefcount++ or * write locking tvc? */ - QRemove(tq); - tvc->f.states &= ~(CStatd | CMValid | CUnique); - if (!(tvc->f.states & (CVInit|CVFlushed)) && - (tvc->f.fid.Fid.Vnode & 1 || - (vType(tvc) == VDIR))) - osi_dnlc_purgedp(tvc); + afs_StaleVCacheFlags(tvc, AFS_STALEVC_CBLOCKED | + AFS_STALEVC_SKIP_DNLC_FOR_INIT_FLUSHED, + CMValid | CUnique); tvc->dchint = NULL; /*invalidate em */ afs_ResetVolumeInfo(tvp); break; @@ -233,11 +230,9 @@ afs_CheckCallbacks(unsigned int secs) /* Do I need to worry about things like execsorwriters? * What about locking xvcache or vrefcount++ or write locking tvc? */ - QRemove(tq); - tvc->f.states &= ~(CStatd | CMValid | CUnique); - if (!(tvc->f.states & (CVInit|CVFlushed)) && - (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))) - osi_dnlc_purgedp(tvc); + afs_StaleVCacheFlags(tvc, AFS_STALEVC_CBLOCKED | + AFS_STALEVC_SKIP_DNLC_FOR_INIT_FLUSHED, + CMValid | CUnique); } } @@ -303,14 +298,10 @@ afs_FlushCBs(void) for (i = 0; i < VCSIZE; i++) /* reset all the vnodes */ for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) { - tvc->callback = 0; + afs_StaleVCacheFlags(tvc, AFS_STALEVC_CBLOCKED | + AFS_STALEVC_CLEARCB | + AFS_STALEVC_SKIP_DNLC_FOR_INIT_FLUSHED, 0); tvc->dchint = NULL; /* invalidate hints */ - tvc->f.states &= ~(CStatd); - if (QPrev(&(tvc->callsort))) - QRemove(&(tvc->callsort)); - if (!(tvc->f.states & (CVInit|CVFlushed)) && - ((tvc->f.fid.Fid.Vnode & 1) || (vType(tvc) == VDIR))) - osi_dnlc_purgedp(tvc); } afs_InitCBQueue(0); @@ -334,14 +325,10 @@ afs_FlushServerCBs(struct server *srvp) for (i = 0; i < VCSIZE; i++) { /* reset all the vnodes */ for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) { if (tvc->callback == srvp) { - tvc->callback = 0; + afs_StaleVCacheFlags(tvc, AFS_STALEVC_CBLOCKED | + AFS_STALEVC_CLEARCB | + AFS_STALEVC_SKIP_DNLC_FOR_INIT_FLUSHED, 0); tvc->dchint = NULL; /* invalidate hints */ - tvc->f.states &= ~(CStatd); - if (!(tvc->f.states & (CVInit|CVFlushed)) && - ((tvc->f.fid.Fid.Vnode & 1) || (vType(tvc) == VDIR))) { - osi_dnlc_purgedp(tvc); - } - afs_DequeueCallback(tvc); } } } diff --git a/src/afs/afs_dcache.c b/src/afs/afs_dcache.c index dc14762..60d2a31 100644 --- a/src/afs/afs_dcache.c +++ b/src/afs/afs_dcache.c @@ -2423,13 +2423,7 @@ afs_GetDCache(struct vcache *avc, afs_size_t abyte, afs_CFileTruncate(file, size); /* prune it */ } else { if (!setLocks || slowPass) { - ObtainWriteLock(&afs_xcbhash, 453); - afs_DequeueCallback(avc); - avc->f.states &= ~(CStatd | CUnique); - avc->callback = NULL; - ReleaseWriteLock(&afs_xcbhash); - if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR)) - osi_dnlc_purgedp(avc); + afs_StaleVCacheFlags(avc, AFS_STALEVC_CLEARCB, CUnique); } else { /* Something lost. Forget about performance, and go * back with a vcache write lock. @@ -2504,12 +2498,7 @@ afs_GetDCache(struct vcache *avc, afs_size_t abyte, ReleaseWriteLock(&tdc->lock); afs_PutDCache(tdc); if (!afs_IsDynroot(avc)) { - ObtainWriteLock(&afs_xcbhash, 454); - afs_DequeueCallback(avc); - avc->f.states &= ~(CStatd | CUnique); - ReleaseWriteLock(&afs_xcbhash); - if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR)) - osi_dnlc_purgedp(avc); + afs_StaleVCacheFlags(avc, 0, CUnique); /* * Locks held: * avc->lock(W); assert(!setLocks || slowPass) diff --git a/src/afs/afs_dynroot.c b/src/afs/afs_dynroot.c index 83dc1aa..a18602f 100644 --- a/src/afs/afs_dynroot.c +++ b/src/afs/afs_dynroot.c @@ -306,8 +306,7 @@ afs_DynrootInvalidate(void) ReleaseReadLock(&afs_xvcache); } while (retry); if (tvc) { - tvc->f.states &= ~(CStatd | CUnique); - osi_dnlc_purgedp(tvc); + afs_StaleVCacheFlags(tvc, AFS_STALEVC_NOCB, CUnique); afs_PutVCache(tvc); } } diff --git a/src/afs/afs_pioctl.c b/src/afs/afs_pioctl.c index bc6b3e6..6d5b7cc 100644 --- a/src/afs/afs_pioctl.c +++ b/src/afs/afs_pioctl.c @@ -1478,15 +1478,10 @@ DECL_PIOCTL(PSetAcl) SHARED_LOCK, NULL)); /* now we've forgotten all of the access info */ - ObtainWriteLock(&afs_xcbhash, 455); - avc->callback = 0; - afs_DequeueCallback(avc); - avc->f.states &= ~(CStatd | CUnique); - ReleaseWriteLock(&afs_xcbhash); - if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR)) - osi_dnlc_purgedp(avc); + afs_StaleVCacheFlags(avc, AFS_STALEVC_CLEARCB, CUnique); /* SXW - Should we flush metadata here? */ + return code; } @@ -3022,13 +3017,7 @@ DECL_PIOCTL(PRemoveCallBack) (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL)); - ObtainWriteLock(&afs_xcbhash, 457); - afs_DequeueCallback(avc); - avc->callback = 0; - avc->f.states &= ~(CStatd | CUnique); - ReleaseWriteLock(&afs_xcbhash); - if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR)) - osi_dnlc_purgedp(avc); + afs_StaleVCacheFlags(avc, AFS_STALEVC_CLEARCB, CUnique); } ReleaseWriteLock(&avc->lock); return 0; @@ -4859,13 +4848,10 @@ DECL_PIOCTL(PFlushMount) goto out; } ObtainWriteLock(&tvc->lock, 649); - ObtainWriteLock(&afs_xcbhash, 650); - afs_DequeueCallback(tvc); - tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */ - ReleaseWriteLock(&afs_xcbhash); + /* next reference will re-stat cache entry */ + afs_StaleVCacheFlags(tvc, 0, CDirty); /* now find the disk cache entries */ afs_TryToSmush(tvc, *acred, 1); - osi_dnlc_purgedp(tvc); if (tvc->linkData && !(tvc->f.states & CCore)) { afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1); tvc->linkData = NULL; diff --git a/src/afs/afs_prototypes.h b/src/afs/afs_prototypes.h index 945954e..d6b7cf6 100644 --- a/src/afs/afs_prototypes.h +++ b/src/afs/afs_prototypes.h @@ -1109,6 +1109,38 @@ extern struct vcache *afs_GetVCache(struct VenusFid *afid, struct vcache *avc); extern void afs_PutVCache(struct vcache *avc); extern int afs_RefVCache(struct vcache *avc); + +/* Flags for afs_StaleVCacheFlags */ + +/* afs_xcbhash is already locked by the caller */ +#define AFS_STALEVC_CBLOCKED (0x01) + +/* Normally we assume we only need to invalidate cached + * name -> vcache mappings for entries where the given + * vcache is the parent dir. This flag says to also clear + * entries for the vcache itself. */ +#define AFS_STALEVC_FILENAME (0x02) + +/* Do not touch the DNLC; the caller will deal with it. */ +#define AFS_STALEVC_NODNLC (0x04) + +/* Do not run afs_DequeueCallback; the caller will take + * care of callback management. */ +#define AFS_STALEVC_NOCB (0x08) + +/* NULL-out the callback field of the vcache, to save code at the callsite. */ +#define AFS_STALEVC_CLEARCB (0x10) + +/* Skip the DNLC purge if CVInit or CVFlushed is set, for efficiency. + * A transitional flag used to reduce the logic change during refactoring + * that is expected to be removed and the purge behavior standardized. */ +#define AFS_STALEVC_SKIP_DNLC_FOR_INIT_FLUSHED (0x20) +typedef unsigned int afs_stalevc_flags_t; + +#define afs_StaleVCache(avc) afs_StaleVCacheFlags(avc, 0, 0) +extern void afs_StaleVCacheFlags(struct vcache *avc, afs_stalevc_flags_t flags, + afs_uint32 cflags); + extern void afs_ProcessFS(struct vcache *avc, struct AFSFetchStatus *astat, struct vrequest *areq); diff --git a/src/afs/afs_segments.c b/src/afs/afs_segments.c index 69f7445..9992a84 100644 --- a/src/afs/afs_segments.c +++ b/src/afs/afs_segments.c @@ -526,12 +526,7 @@ afs_InvalidateAllSegments(struct vcache *avc) hash = DVHash(&avc->f.fid); avc->f.truncPos = AFS_NOTRUNC; /* don't truncate later */ avc->f.states &= ~CExtendedFile; /* not any more */ - ObtainWriteLock(&afs_xcbhash, 459); - afs_DequeueCallback(avc); - avc->f.states &= ~(CStatd | CDirty); /* mark status information as bad, too */ - ReleaseWriteLock(&afs_xcbhash); - if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR)) - osi_dnlc_purgedp(avc); + afs_StaleVCacheFlags(avc, 0, CDirty); /* Blow away pages; for now, only for Solaris */ #if (defined(AFS_SUN5_ENV)) if (WriteLocked(&avc->lock)) diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index 1403254..18fb79a 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -248,14 +248,7 @@ afs_FlushVCache(struct vcache *avc, int *slept) vn_reinit(AFSTOV(avc)); #endif afs_FreeAllAxs(&(avc->Access)); - ObtainWriteLock(&afs_xcbhash, 460); - afs_DequeueCallback(avc); /* remove it from queued callbacks list */ - avc->f.states &= ~(CStatd | CUnique); - ReleaseWriteLock(&afs_xcbhash); - if ((avc->f.states & CForeign) || (avc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(avc); /* if it (could be) a directory */ - else - osi_dnlc_purgevp(avc); + afs_StaleVCacheFlags(avc, AFS_STALEVC_FILENAME, CUnique); /* By this point, the vcache has been removed from all global structures * via which someone could try to use the vcache. It is okay to drop @@ -1240,22 +1233,10 @@ afs_VerifyVCache2(struct vcache *avc, struct vrequest *areq) ReleaseWriteLock(&avc->lock); return 0; } - ObtainWriteLock(&afs_xcbhash, 461); - avc->f.states &= ~(CStatd | CUnique); - avc->callback = NULL; - afs_DequeueCallback(avc); - ReleaseWriteLock(&afs_xcbhash); + afs_StaleVCacheFlags(avc, AFS_STALEVC_FILENAME | AFS_STALEVC_CLEARCB, + CUnique); ReleaseWriteLock(&avc->lock); - /* since we've been called back, or the callback has expired, - * it's possible that the contents of this directory, or this - * file's name have changed, thus invalidating the dnlc contents. - */ - if ((avc->f.states & CForeign) || (avc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(avc); - else - osi_dnlc_purgevp(avc); - /* fetch the status info */ tvc = afs_GetVCache(&avc->f.fid, areq, NULL, avc); if (!tvc) @@ -1411,12 +1392,7 @@ afs_WriteVCache(struct vcache *avc, avc->f.m.Date = OutStatus.ClientModTime; } else { /* failure, set up to check with server next time */ - ObtainWriteLock(&afs_xcbhash, 462); - afs_DequeueCallback(avc); - avc->f.states &= ~(CStatd | CUnique); /* turn off stat valid flag */ - ReleaseWriteLock(&afs_xcbhash); - if ((avc->f.states & CForeign) || (avc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(avc); /* if it (could be) a directory */ + afs_StaleVCacheFlags(avc, 0, CUnique); } ConvertWToSLock(&avc->lock); return code; @@ -1829,11 +1805,8 @@ afs_GetVCache(struct VenusFid *afid, struct vrequest *areq, #endif #endif - ObtainWriteLock(&afs_xcbhash, 464); - tvc->f.states &= ~CUnique; - tvc->callback = 0; - afs_DequeueCallback(tvc); - ReleaseWriteLock(&afs_xcbhash); + afs_StaleVCacheFlags(tvc, AFS_STALEVC_NODNLC | AFS_STALEVC_CLEARCB, + CUnique); /* It is always appropriate to throw away all the access rights? */ afs_FreeAllAxs(&(tvc->Access)); @@ -2048,12 +2021,7 @@ afs_LookupVCache(struct VenusFid *afid, struct vrequest *areq, } if (code) { - ObtainWriteLock(&afs_xcbhash, 465); - afs_DequeueCallback(tvc); - tvc->f.states &= ~(CStatd | CUnique); - ReleaseWriteLock(&afs_xcbhash); - if ((tvc->f.states & CForeign) || (tvc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(tvc); /* if it (could be) a directory */ + afs_StaleVCacheFlags(tvc, 0, CUnique); if (tvp) afs_PutVolume(tvp, READ_LOCK); ReleaseWriteLock(&tvc->lock); @@ -2076,19 +2044,14 @@ afs_LookupVCache(struct VenusFid *afid, struct vrequest *areq, tvc->f.states &= ~CBulkFetching; afs_QueueCallback(tvc, CBHash(3600), tvp); } else { - tvc->callback = NULL; - afs_DequeueCallback(tvc); - tvc->f.states &= ~(CStatd | CUnique); - if ((tvc->f.states & CForeign) || (tvc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(tvc); /* if it (could be) a directory */ + afs_StaleVCacheFlags(tvc, + AFS_STALEVC_CBLOCKED | AFS_STALEVC_CLEARCB, + CUnique); } } else { - afs_DequeueCallback(tvc); - tvc->f.states &= ~CStatd; - tvc->f.states &= ~CUnique; - tvc->callback = NULL; - if ((tvc->f.states & CForeign) || (tvc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(tvc); /* if it (could be) a directory */ + afs_StaleVCacheFlags(tvc, + AFS_STALEVC_CBLOCKED | AFS_STALEVC_CLEARCB, + CUnique); } ReleaseWriteLock(&afs_xcbhash); if (tvp) @@ -2286,13 +2249,7 @@ afs_GetRootVCache(struct VenusFid *afid, struct vrequest *areq, } if (code) { - ObtainWriteLock(&afs_xcbhash, 467); - afs_DequeueCallback(tvc); - tvc->callback = NULL; - tvc->f.states &= ~(CStatd | CUnique); - ReleaseWriteLock(&afs_xcbhash); - if ((tvc->f.states & CForeign) || (tvc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(tvc); /* if it (could be) a directory */ + afs_StaleVCacheFlags(tvc, AFS_STALEVC_CLEARCB, CUnique); ReleaseWriteLock(&tvc->lock); afs_PutVCache(tvc); return NULL; @@ -2315,11 +2272,8 @@ afs_GetRootVCache(struct VenusFid *afid, struct vrequest *areq, afs_QueueCallback(tvc, CBHash(3600), tvolp); } } else { - afs_DequeueCallback(tvc); - tvc->callback = NULL; - tvc->f.states &= ~(CStatd | CUnique); - if ((tvc->f.states & CForeign) || (tvc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(tvc); /* if it (could be) a directory */ + afs_StaleVCacheFlags(tvc, AFS_STALEVC_CBLOCKED | AFS_STALEVC_CLEARCB, + CUnique); } ReleaseWriteLock(&afs_xcbhash); afs_ProcessFS(tvc, &OutStatus, areq); @@ -2369,18 +2323,13 @@ afs_UpdateStatus(struct vcache *avc, struct VenusFid *afid, avc->f.states &= ~CBulkFetching; afs_QueueCallback(avc, CBHash(3600), volp); } else { - afs_DequeueCallback(avc); - avc->callback = NULL; - avc->f.states &= ~(CStatd | CUnique); - if ((avc->f.states & CForeign) || (avc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(avc); /* if it (could be) a directory */ + afs_StaleVCacheFlags(avc, + AFS_STALEVC_CBLOCKED | AFS_STALEVC_CLEARCB, + CUnique); } } else { - afs_DequeueCallback(avc); - avc->callback = NULL; - avc->f.states &= ~(CStatd | CUnique); - if ((avc->f.states & CForeign) || (avc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(avc); /* if it (could be) a directory */ + afs_StaleVCacheFlags(avc, AFS_STALEVC_CBLOCKED | AFS_STALEVC_CLEARCB, + CUnique); } ReleaseWriteLock(&afs_xcbhash); if (volp) @@ -2554,9 +2503,7 @@ afs_StuffVcache(struct VenusFid *afid, ReleaseSharedLock(&afs_xvcache); ObtainWriteLock(&tvc->lock, 58); - tvc->f.states &= ~CStatd; - if ((tvc->f.states & CForeign) || (tvc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(tvc); /* if it (could be) a directory */ + afs_StaleVCacheFlags(tvc, AFS_STALEVC_NOCB, 0); /* Is it always appropriate to throw away all the access rights? */ afs_FreeAllAxs(&(tvc->Access)); @@ -2608,11 +2555,8 @@ afs_StuffVcache(struct VenusFid *afid, tvc->f.states &= ~CBulkFetching; afs_QueueCallback(tvc, CBHash(3600), tvp); } else { - afs_DequeueCallback(tvc); - tvc->callback = NULL; - tvc->f.states &= ~(CStatd | CUnique); - if ((tvc->f.states & CForeign) || (tvc->f.fid.Fid.Vnode & 1)) - osi_dnlc_purgedp(tvc); /* if it (could be) a directory */ + afs_StaleVCacheFlags(tvc, AFS_STALEVC_CBLOCKED | AFS_STALEVC_CLEARCB, + CUnique); } ReleaseWriteLock(&afs_xcbhash); if (tvp) @@ -2675,15 +2619,14 @@ afs_PutVCache(struct vcache *avc) void afs_ResetVCache(struct vcache *avc, afs_ucred_t *acred, afs_int32 skipdnlc) { - ObtainWriteLock(&afs_xcbhash, 456); - afs_DequeueCallback(avc); - avc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat */ - ReleaseWriteLock(&afs_xcbhash); + afs_stalevc_flags_t flags = 0; + if (skipdnlc) { + flags |= AFS_STALEVC_NODNLC; + } + + afs_StaleVCacheFlags(avc, flags, CDirty); /* next reference will re-stat */ /* now find the disk cache entries */ afs_TryToSmush(avc, acred, 1); - if (!skipdnlc) { - osi_dnlc_purgedp(avc); - } if (avc->linkData && !(avc->f.states & CCore)) { afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1); avc->linkData = NULL; @@ -3244,8 +3187,74 @@ afs_ClearAllStatdFlag(void) for (i = 0; i < VCSIZE; i++) { for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) { - tvc->f.states &= ~(CStatd|CUnique); + afs_StaleVCacheFlags(tvc, AFS_STALEVC_NODNLC | AFS_STALEVC_NOCB, + CUnique); } } ReleaseWriteLock(&afs_xvcache); } + +/** + * Mark a vcache as stale; our metadata for the relevant file may be out of + * date. + * + * @post Any subsequent access to this vcache will cause us to fetch the + * metadata for this vcache again. + */ +void +afs_StaleVCacheFlags(struct vcache *avc, afs_stalevc_flags_t flags, + afs_uint32 cflags) +{ + int do_dnlc = 1; + int do_filename = 0; + int do_dequeue = 1; + int lock_cbhash = 1; + + if ((flags & AFS_STALEVC_NODNLC)) { + do_dnlc = 0; + } + if ((flags & AFS_STALEVC_FILENAME)) { + do_filename = 1; + } + if ((flags & AFS_STALEVC_CBLOCKED)) { + lock_cbhash = 0; + } + if ((flags & AFS_STALEVC_NOCB)) { + do_dequeue = 0; + lock_cbhash = 0; + } + + if (lock_cbhash) { + ObtainWriteLock(&afs_xcbhash, 486); + } + if (do_dequeue) { + afs_DequeueCallback(avc); + } + + cflags |= CStatd; + avc->f.states &= ~cflags; + + if (lock_cbhash) { + ReleaseWriteLock(&afs_xcbhash); + } + + if ((flags & AFS_STALEVC_SKIP_DNLC_FOR_INIT_FLUSHED) && + (avc->f.states & (CVInit | CVFlushed))) { + do_dnlc = 0; + } + + if (flags & AFS_STALEVC_CLEARCB) { + avc->callback = NULL; + } + + if (do_dnlc) { + if ((avc->f.fid.Fid.Vnode & 1) || vType(avc) == VDIR || + (avc->f.states & CForeign)) { + /* This vcache is (or could be) a directory. */ + osi_dnlc_purgedp(avc); + + } else if (do_filename) { + osi_dnlc_purgevp(avc); + } + } +} diff --git a/src/afs/afs_volume.c b/src/afs/afs_volume.c index 0dcab6b..b731a59 100644 --- a/src/afs/afs_volume.c +++ b/src/afs/afs_volume.c @@ -537,13 +537,8 @@ loop: #endif ReleaseReadLock(&afs_xvcache); - ObtainWriteLock(&afs_xcbhash, 485); /* LOCKXXX: We aren't holding tvc write lock? */ - afs_DequeueCallback(tvc); - tvc->f.states &= ~CStatd; - ReleaseWriteLock(&afs_xcbhash); - if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR)) - osi_dnlc_purgedp(tvc); + afs_StaleVCache(tvc); #ifdef AFS_DARWIN80_ENV vnode_put(AFSTOV(tvc)); -- 1.9.4