diff --git a/src/afs/DARWIN/osi_vnodeops.c b/src/afs/DARWIN/osi_vnodeops.c index 4190d8bea1..fb9627b023 100644 --- a/src/afs/DARWIN/osi_vnodeops.c +++ b/src/afs/DARWIN/osi_vnodeops.c @@ -2206,6 +2206,26 @@ afs_darwin_finalizevnode(struct vcache *avc, struct vnode *dvp, struct component } avc->v = nvp; avc->f.states &=~ CDeadVnode; + /* If we were carrying an extra ref for dirty, hold/push it. */ + if (avc->f.ddirty_flags) { + vnode_get(nvp); + vnode_ref(nvp); + } + /* If we were carrying an extra ref for shadow, hold/push it. */ + if (avc->f.shadow.vnode) { + vnode_get(nvp); + vnode_ref(nvp); + } + } + /* Drop any extra dirty ref on the old vnode */ + if (avc->f.ddirty_flags) { + vnode_put(ovp); + vnode_rele(ovp); + } + /* Drop any extra shadow ref on the old vnode */ + if (avc->f.shadow.vnode) { + vnode_put(ovp); + vnode_rele(ovp); } vnode_put(ovp); vnode_rele(ovp); diff --git a/src/afs/afs_dcache.c b/src/afs/afs_dcache.c index 246acdf08f..ea708f4a2b 100644 --- a/src/afs/afs_dcache.c +++ b/src/afs/afs_dcache.c @@ -3399,7 +3399,7 @@ afs_MakeShadowDir(struct vcache *avc, struct dcache *adc) ObtainWriteLock(&afs_xvcache, 763); ObtainWriteLock(&afs_disconDirtyLock, 765); QAdd(&afs_disconShadow, &avc->shadowq); - osi_vnhold(avc, 0); + osi_Assert((afs_RefVCache(avc) == 0)); ReleaseWriteLock(&afs_disconDirtyLock); ReleaseWriteLock(&afs_xvcache); diff --git a/src/afs/afs_prototypes.h b/src/afs/afs_prototypes.h index 362bed177c..9a877d019b 100644 --- a/src/afs/afs_prototypes.h +++ b/src/afs/afs_prototypes.h @@ -1044,6 +1044,7 @@ extern struct vcache *afs_GetVCache(register struct VenusFid *afid, struct vrequest *areq, afs_int32 * cached, struct vcache *avc); extern void afs_PutVCache(register struct vcache *avc); +extern int afs_RefVCache(struct vcache *avc); extern void afs_ProcessFS(register struct vcache *avc, register struct AFSFetchStatus *astat, struct vrequest *areq); diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index 117c919fa4..2d99644475 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -2531,6 +2531,45 @@ findvc_sleep(struct vcache *avc, int flag) } } } + +/*! + * Add a reference on an existing vcache entry. + * + * \param tvc Pointer to the vcache. + * + * \note Environment: Must be called with at least one reference from + * elsewhere on the vcache, even if that reference will be dropped. + * The global lock is required. + * + * \return 0 on success, -1 on failure. + */ + +int +afs_RefVCache(struct vcache *tvc) +{ +#ifdef AFS_DARWIN80_ENV + vnode_t tvp; +#endif + + /* AFS_STATCNT(afs_RefVCache); */ + +#ifdef AFS_DARWIN80_ENV + tvp = AFSTOV(tvc); + if (vnode_get(tvp)) + return -1; + if (vnode_ref(tvp)) { + AFS_GUNLOCK(); + /* AFSTOV(tvc) may be NULL */ + vnode_put(tvp); + AFS_GLOCK(); + return -1; + } +#else + osi_vnhold(tvc, 0); +#endif + return 0; +} /*afs_RefVCache */ + /*! * Find a vcache entry given a fid. * diff --git a/src/afs/discon.h b/src/afs/discon.h index dae6612f43..df342eda2a 100644 --- a/src/afs/discon.h +++ b/src/afs/discon.h @@ -56,7 +56,7 @@ static_inline void afs_DisconAddDirty(struct vcache *avc, int operation, int loc ObtainWriteLock(&afs_xvcache, 702); ObtainWriteLock(&afs_disconDirtyLock, 703); QAdd(&afs_disconDirty, &avc->dirtyq); - osi_vnhold(avc, 0); + osi_Assert((afs_RefVCache(avc) == 0)); ReleaseWriteLock(&afs_disconDirtyLock); if (lock) ReleaseWriteLock(&afs_xvcache);