}
/* called with cm_scacheLock and scp write-locked */
-void cm_ResetSCacheDirectory(cm_scache_t *scp)
+void cm_ResetSCacheDirectory(cm_scache_t *scp, afs_int32 dirlock)
{
#ifdef USE_BPLUS
/* destroy directory Bplus Tree */
if (scp->dirBplus) {
LARGE_INTEGER start, end;
+
+ if (!dirlock && !lock_TryWrite(&scp->dirlock)) {
+ /*
+ * We are not holding the dirlock and obtaining it
+ * requires that we drop the scp->rw. As a result
+ * we will leave the dirBplus tree intact but
+ * invalidate the version number so that whatever
+ * operation is currently active can safely complete
+ * but the contents will be ignored on the next
+ * directory operation.
+ */
+ scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
+ return;
+ }
+
QueryPerformanceCounter(&start);
bplus_free_tree++;
freeBtree(scp->dirBplus);
scp->dirBplus = NULL;
+ scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
QueryPerformanceCounter(&end);
+
+ if (!dirlock)
+ lock_ReleaseWrite(&scp->dirlock);
bplus_free_time += (end.QuadPart - start.QuadPart);
}
bufp->dirty_length = 0;
bufp->flags |= CM_BUF_ERROR;
bufp->error = VNOVNODE;
- bufp->dataVersion = -1; /* bad */
+ bufp->dataVersion = CM_BUF_VERSION_BAD; /* bad */
bufp->dirtyCounter++;
if (bufp->flags & CM_BUF_WAITING) {
osi_Log2(afsd_logp, "CM RecycleSCache Waking [scp 0x%x] bufp 0x%x", scp, bufp);
bufp->dirty_length = 0;
bufp->flags |= CM_BUF_ERROR;
bufp->error = VNOVNODE;
- bufp->dataVersion = -1; /* bad */
+ bufp->dataVersion = CM_BUF_VERSION_BAD; /* bad */
bufp->dirtyCounter++;
if (bufp->flags & CM_BUF_WAITING) {
osi_Log2(afsd_logp, "CM RecycleSCache Waking [scp 0x%x] bufp 0x%x", scp, bufp);
| CM_SCACHEFLAG_OUTOFSPACE
| CM_SCACHEFLAG_EACCESS);
scp->serverModTime = 0;
- scp->dataVersion = 0;
- scp->bufDataVersionLow = 0;
+ scp->dataVersion = CM_SCACHE_VERSION_BAD;
+ scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
scp->bulkStatProgress = hzero;
scp->waitCount = 0;
scp->waitQueueT = NULL;
scp->serverLock = (-1);
scp->exclusiveLocks = 0;
scp->sharedLocks = 0;
- scp->lockDataVersion = -1;
+ scp->lockDataVersion = CM_SCACHE_VERSION_BAD;
/* not locked, but there can be no references to this guy
* while we hold the global refcount lock.
*/
cm_FreeAllACLEnts(scp);
- cm_ResetSCacheDirectory(scp);
+ cm_ResetSCacheDirectory(scp, 0);
return 0;
}
if (scp->dirBplus)
freeBtree(scp->dirBplus);
scp->dirBplus = NULL;
- scp->dirDataVersion = -1;
+ scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
lock_FinalizeRWLock(&scp->dirlock);
#endif
lock_FinalizeRWLock(&scp->rw);
scp->waitCount = 0;
#ifdef USE_BPLUS
scp->dirBplus = NULL;
- scp->dirDataVersion = -1;
+ scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
#endif
scp->waitQueueT = NULL;
scp->flags &= ~CM_SCACHEFLAG_WAITING;
void cm_MergeStatus(cm_scache_t *dscp,
cm_scache_t *scp, AFSFetchStatus *statusp,
AFSVolSync *volsyncp,
- cm_user_t *userp, afs_uint32 flags)
+ cm_user_t *userp, cm_req_t *reqp, afs_uint32 flags)
{
afs_uint64 dataVersion;
scp->group = 0;
scp->unixModeBits = 0;
scp->anyAccess = 0;
- scp->dataVersion = 0;
- scp->bufDataVersionLow = 0;
+ scp->dataVersion = CM_SCACHE_VERSION_BAD;
+ scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
if (dscp) {
scp->parentVnode = dscp->fid.vnode;
dataVersion <<= 32;
dataVersion |= statusp->DataVersion;
- if (!(flags & CM_MERGEFLAG_FORCE) && dataVersion < scp->dataVersion) {
+ if (!(flags & CM_MERGEFLAG_FORCE) &&
+ dataVersion < scp->dataVersion &&
+ scp->dataVersion != CM_SCACHE_VERSION_BAD) {
struct cm_cell *cellp;
cellp = cm_FindCellByID(scp->fid.cell, 0);
if (scp->cbServerp) {
struct cm_volume *volp = NULL;
-
cm_FindVolumeByID(cellp, scp->fid.volume, userp,
- (cm_req_t *) NULL, CM_GETVOL_FLAG_CREATE, &volp);
+ reqp, CM_GETVOL_FLAG_CREATE, &volp);
osi_Log2(afsd_logp, "old data from server %x volume %s",
scp->cbServerp->addr.sin_addr.s_addr,
volp ? volp->namep : "(unknown)");