diff --git a/src/afs/DARWIN/osi_vnodeops.c b/src/afs/DARWIN/osi_vnodeops.c index db02aa528d..3f248179aa 100644 --- a/src/afs/DARWIN/osi_vnodeops.c +++ b/src/afs/DARWIN/osi_vnodeops.c @@ -1624,7 +1624,7 @@ afs_vop_reclaim(ap) * } */ *ap; { int error = 0; - int sl; + int sl, writelocked; register struct vnode *vp = ap->a_vp; struct vcache *tvc = VTOAFS(vp); @@ -1632,25 +1632,40 @@ afs_vop_reclaim(ap) cache_purge(vp); /* just in case... */ if (tvc) { AFS_GLOCK(); - ObtainWriteLock(&afs_xvcache, 335); - error = afs_FlushVCache(tvc, &sl); /* toss our stuff from vnode */ - if (tvc->states & (CVInit + writelocked = (0 == NBObtainWriteLock(&afs_xvcache, 335)); + if (!writelocked) { + ObtainWriteLock(&afs_xvreclaim, 176); #ifdef AFS_DARWIN80_ENV - | CDeadVnode + vnode_clearfsnode(AFSTOV(tvc)); + vnode_removefsref(AFSTOV(tvc)); +#else + tvc->v->v_data = NULL; /* remove from vnode */ #endif - )) { - tvc->states &= ~(CVInit + AFSTOV(tvc) = NULL; /* also drop the ptr to vnode */ + tvc->states |= CVInit; /* also CDeadVnode? */ + tvc->nextfree = ReclaimedVCList; + ReclaimedVCList = tvc; + ReleaseWriteLock(&afs_xvreclaim); + } else { + error = afs_FlushVCache(tvc, &sl); /* toss our stuff from vnode */ + if (tvc->states & (CVInit #ifdef AFS_DARWIN80_ENV - | CDeadVnode + | CDeadVnode #endif - ); - afs_osi_Wakeup(&tvc->states); + )) { + tvc->states &= ~(CVInit +#ifdef AFS_DARWIN80_ENV + | CDeadVnode +#endif + ); + afs_osi_Wakeup(&tvc->states); + } + if (!error && vnode_fsnode(vp)) + panic("afs_reclaim: vnode not cleaned"); + if (!error && (tvc->v != NULL)) + panic("afs_reclaim: vcache not cleaned"); + ReleaseWriteLock(&afs_xvcache); } - if (!error && vnode_fsnode(vp)) - panic("afs_reclaim: vnode not cleaned"); - if (!error && (tvc->v != NULL)) - panic("afs_reclaim: vcache not cleaned"); - ReleaseWriteLock(&afs_xvcache); AFS_GUNLOCK(); } return error; diff --git a/src/afs/afs_callback.c b/src/afs/afs_callback.c index e54d8850df..3ab7a434d9 100644 --- a/src/afs/afs_callback.c +++ b/src/afs/afs_callback.c @@ -59,7 +59,9 @@ static struct ltable { "afs_xosi", (char *)&afs_xosi}, #endif { - "afs_xsrvAddr", (char *)&afs_xsrvAddr} + "afs_xsrvAddr", (char *)&afs_xsrvAddr}, + { + "afs_xvreclaim", (char *)&afs_xvreclaim} }; unsigned long lastCallBack_vnode; unsigned int lastCallBack_dv; diff --git a/src/afs/afs_daemons.c b/src/afs/afs_daemons.c index 9f40c3a9c0..cf64703e10 100644 --- a/src/afs/afs_daemons.c +++ b/src/afs/afs_daemons.c @@ -175,6 +175,9 @@ afs_Daemon(void) /* things to do every minute */ DFlush(); /* write out dir buffers */ afs_WriteThroughDSlots(); /* write through cacheinfo entries */ + ObtainWriteLock(&afs_xvcache, 736); + afs_FlushReclaimedVcaches(); + ReleaseWriteLock(&afs_xvcache); afs_FlushActiveVcaches(1); /* keep flocks held & flush nfs writes */ #ifdef AFS_DISCON_ENV afs_StoreDirtyVcaches(); diff --git a/src/afs/afs_prototypes.h b/src/afs/afs_prototypes.h index f637226d03..dca36e9e56 100644 --- a/src/afs/afs_prototypes.h +++ b/src/afs/afs_prototypes.h @@ -811,6 +811,7 @@ extern afs_int32 afs_data_pointer_to_int32(const void *p); extern afs_int32 afs_maxvcount; extern afs_int32 afs_vcount; extern int afsvnumbers; +extern afs_rwlock_t afs_xvreclaim; extern afs_rwlock_t afs_xvcache; extern afs_lock_t afs_xvcb; extern struct afs_q VLRU; @@ -819,6 +820,7 @@ extern unsigned int afs_paniconwarn; extern struct afs_q afs_vhashTV[VCSIZE]; extern afs_int32 afs_bulkStatsLost; extern int afs_norefpanic; +extern struct vcache *ReclaimedVCList; void afs_vcacheInit(int astatSize); extern struct vcache *afs_FindVCache(struct VenusFid *afid, afs_int32 * retry, diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index 1d2e08db5f..2cd6b53e53 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -62,9 +62,11 @@ char *makesname(); /* Exported variables */ afs_rwlock_t afs_xvcache; /*Lock: alloc new stat cache entries */ +afs_rwlock_t afs_xvreclaim; /*Lock: entries reclaimed, not on free list */ afs_lock_t afs_xvcb; /*Lock: fids on which there are callbacks */ #if !defined(AFS_LINUX22_ENV) static struct vcache *freeVCList; /*Free list for stat cache entries */ +struct vcache *ReclaimedVCList; /*Reclaimed list for stat entries */ static struct vcache *Initial_freeVCList; /*Initial list for above */ #endif struct afs_q VLRU; /*vcache LRU */ @@ -572,6 +574,38 @@ afs_RemoveVCB(struct VenusFid *afid) MReleaseWriteLock(&afs_xvcb); } +void +afs_FlushReclaimedVcaches(void) +{ +#if !defined(AFS_LINUX22_ENV) + struct vcache *tvc; + int code, fv_slept; + struct vcache *tmpReclaimedVCList = NULL; + + ObtainWriteLock(&afs_xvreclaim, 76); + while (ReclaimedVCList) { + tvc = ReclaimedVCList; /* take from free list */ + ReclaimedVCList = tvc->nextfree; + tvc->nextfree = NULL; + code = afs_FlushVCache(tvc, &fv_slept); + if (code) { + /* Ok, so, if we got code != 0, uh, wtf do we do? */ + /* Probably, build a temporary list and then put all back when we + get to the end of the list */ + /* This is actually really crappy, but we need to not leak these. + We probably need a way to be smarter about this. */ + tvc->nextfree = tmpReclaimedVCList; + tmpReclaimedVCList = tvc; + printf("Reclaim list flush %x failed: %d\n", tvc, code); + } + } + if (tmpReclaimedVCList) + ReclaimedVCList = tmpReclaimedVCList; + + ReleaseWriteLock(&afs_xvreclaim); +#endif +} + /* * afs_NewVCache * @@ -603,6 +637,9 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp) int code, fv_slept; AFS_STATCNT(afs_NewVCache); + + afs_FlushReclaimedVcaches(); + #if defined(AFS_OSF_ENV) || defined(AFS_LINUX22_ENV) #if defined(AFS_OSF30_ENV) || defined(AFS_LINUX22_ENV) if (afs_vcount >= afs_maxvcount)