void cm_AdjustScacheLRU(cm_scache_t *scp)
{
lock_AssertWrite(&cm_scacheLock);
- osi_QRemoveHT((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
- if (scp->flags & CM_SCACHEFLAG_DELETED) {
- /* Since it has been deleted make it the first to be recycled. */
- osi_QAddT((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
- } else {
+ if (!(scp->flags & CM_SCACHEFLAG_DELETED)) {
+ osi_QRemoveHT((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
osi_QAddH((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
}
}
/* called with cm_scacheLock and scp write-locked; recycles an existing scp. */
long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
{
+ cm_fid_t fid;
+ afs_uint32 fileType;
+ int callback;
+
lock_AssertWrite(&cm_scacheLock);
lock_AssertWrite(&scp->rw);
return -1;
}
+ fid = scp->fid;
+ fileType = scp->fileType;
+ callback = scp->cbExpires ? 1 : 0;
+
cm_RemoveSCacheFromHashTable(scp);
+ if (scp->fileType == CM_SCACHETYPE_DIRECTORY &&
+ !cm_accessPerFileCheck) {
+ cm_volume_t *volp = cm_GetVolumeByFID(&scp->fid);
+
+ if (volp) {
+ if (!(volp->flags & CM_VOLUMEFLAG_DFS_VOLUME))
+ cm_EAccesClearParentEntries(&fid);
+
+ cm_PutVolume(volp);
+ }
+ }
+
/* invalidate so next merge works fine;
* also initialize some flags */
scp->fileType = 0;
_InterlockedAnd(&scp->flags,
- ~(CM_SCACHEFLAG_STATD
- | CM_SCACHEFLAG_DELETED
+ ~( CM_SCACHEFLAG_DELETED
| CM_SCACHEFLAG_RO
| CM_SCACHEFLAG_PURERO
| CM_SCACHEFLAG_OVERQUOTA
| CM_SCACHEFLAG_OUTOFSPACE
- | CM_SCACHEFLAG_EACCESS));
+ | CM_SCACHEFLAG_ASYNCSTORING));
scp->serverModTime = 0;
scp->dataVersion = CM_SCACHE_VERSION_BAD;
scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
scp->cbServerp = NULL;
}
scp->cbExpires = 0;
+ scp->cbIssued = 0;
scp->volumeCreationDate = 0;
scp->fid.vnode = 0;
scp->mask = 0;
/* discard symlink info */
+ scp->mpDataVersion = CM_SCACHE_VERSION_BAD;
scp->mountPointStringp[0] = '\0';
memset(&scp->mountRootFid, 0, sizeof(cm_fid_t));
memset(&scp->dotdotFid, 0, sizeof(cm_fid_t));
cm_FreeAllACLEnts(scp);
cm_ResetSCacheDirectory(scp, 0);
+
+ if (RDR_Initialized && callback) {
+ /*
+ * We drop the cm_scacheLock because it may be required to
+ * satisfy an ioctl request from the redirector. It should
+ * be safe to hold the scp->rw lock here because at this
+ * point (a) the object has just been recycled so the fid
+ * is nul and there are no requests that could possibly
+ * be issued by the redirector that would depend upon it.
+ */
+ lock_ReleaseWrite(&cm_scacheLock);
+ RDR_InvalidateObject( fid.cell, fid.volume, fid.vnode,
+ fid.unique, fid.hash,
+ fileType, AFS_INVALIDATE_EXPIRED);
+ lock_ObtainWrite(&cm_scacheLock);
+ }
+
return 0;
}
cm_GetNewSCache(afs_uint32 locked)
{
cm_scache_t *scp = NULL;
- int retry = 0;
+ cm_scache_t *scp_prev = NULL;
+ cm_scache_t *scp_next = NULL;
+ int attempt = 0;
if (locked)
lock_AssertWrite(&cm_scacheLock);
/* There were no deleted scache objects that we could use. Try to find
* one that simply hasn't been used in a while.
*/
- for (retry = 0 ; retry < 2; retry++) {
+ for (attempt = 0 ; attempt < 128; attempt++) {
+ afs_uint32 count = 0;
+
for ( scp = cm_data.scacheLRULastp;
scp;
scp = (cm_scache_t *) osi_QPrev(&scp->q))
{
+ /*
+ * We save the prev and next pointers in the
+ * LRU because we are going to drop the cm_scacheLock and
+ * the order of the list could change out from beneath us.
+ * If both changed, it means that this entry has been moved
+ * within the LRU and it should no longer be recycled.
+ */
+ scp_prev = (cm_scache_t *) osi_QPrev(&scp->q);
+ scp_next = (cm_scache_t *) osi_QNext(&scp->q);
+ count++;
+
/* It is possible for the refCount to be zero and for there still
* to be outstanding dirty buffers. If there are dirty buffers,
* we must not recycle the scp.
buf_dirty = buf_DirtyBuffersExist(&scp->fid);
if (!buf_dirty)
buf_rdr = buf_RDRBuffersExist(&scp->fid);
- lock_ObtainWrite(&cm_scacheLock);
if (!buf_dirty && !buf_rdr) {
cm_fid_t fid;
afs_uint32 fileType;
+ int success;
- if (!lock_TryWrite(&scp->rw))
- continue;
+ success = lock_TryWrite(&scp->rw);
+
+ lock_ObtainWrite(&cm_scacheLock);
+ if (scp_prev != (cm_scache_t *) osi_QPrev(&scp->q) &&
+ scp_next != (cm_scache_t *) osi_QNext(&scp->q))
+ {
+ osi_Log1(afsd_logp, "GetNewSCache scp 0x%p; LRU order changed", scp);
+ if (success)
+ lock_ReleaseWrite(&scp->rw);
+ break;
+ } else if (!success) {
+ osi_Log1(afsd_logp, "GetNewSCache failed to obtain lock scp 0x%p", scp);
+ continue;
+ }
/* Found a likely candidate. Save type and fid in case we succeed */
fid = scp->fid;
*/
cm_AdjustScacheLRU(scp);
- if (RDR_Initialized) {
- /*
- * We drop the cm_scacheLock because it may be required to
- * satisfy an ioctl request from the redirector. It should
- * be safe to hold the scp->rw lock here because at this
- * point (a) the object has just been recycled so the fid
- * is nul and there are no requests that could possibly
- * be issued by the redirector that would depend upon it.
- */
- lock_ReleaseWrite(&cm_scacheLock);
- RDR_InvalidateObject( fid.cell, fid.volume, fid.vnode,
- fid.unique, fid.hash,
- fileType, AFS_INVALIDATE_EXPIRED);
- lock_ObtainWrite(&cm_scacheLock);
- }
-
- /* and we're done */
+ /* and we're done - SUCCESS */
osi_assertx(!(scp->flags & CM_SCACHEFLAG_INHASH), "CM_SCACHEFLAG_INHASH set");
goto done;
}
lock_ReleaseWrite(&scp->rw);
} else {
- osi_Log1(afsd_logp,"GetNewSCache dirty buffers exist scp 0x%p", scp);
+ if (buf_rdr)
+ osi_Log1(afsd_logp,"GetNewSCache redirector is holding extents scp 0x%p", scp);
+ else
+ osi_Log1(afsd_logp, "GetNewSCache dirty buffers scp 0x%p", scp);
+
+ lock_ObtainWrite(&cm_scacheLock);
+ if (scp_prev != (cm_scache_t *) osi_QPrev(&scp->q) &&
+ scp_next != (cm_scache_t *) osi_QNext(&scp->q))
+ {
+ osi_Log1(afsd_logp, "GetNewSCache scp 0x%p; LRU order changed", scp);
+ break;
+ }
}
}
+ } /* for */
+
+ osi_Log2(afsd_logp, "GetNewSCache all scache entries in use (attempt = %d, count = %u)", attempt, count);
+ if (scp == NULL) {
+ /*
+ * The entire LRU queue was walked and no available cm_scache_t was
+ * found. Drop the cm_scacheLock and sleep for a moment to give a
+ * chance for cm_scache_t objects to be released.
+ */
+ lock_ReleaseWrite(&cm_scacheLock);
+ Sleep(50);
+ lock_ObtainWrite(&cm_scacheLock);
}
- osi_Log1(afsd_logp, "GetNewSCache all scache entries in use (retry = %d)", retry);
}
+ /* FAILURE */
+ scp = NULL;
goto done;
}
/* if we get here, we should allocate a new scache entry. We either are below
* quota or we have a leak and need to allocate a new one to avoid panicing.
*/
- scp = cm_data.scacheBaseAddress + cm_data.currentSCaches;
+ scp = cm_data.scacheBaseAddress + InterlockedIncrement(&cm_data.currentSCaches) - 1;
osi_assertx(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.scacheHashTablep,
"invalid cm_scache_t address");
memset(scp, 0, sizeof(cm_scache_t));
#endif
lock_InitializeMutex(&scp->redirMx, "cm_scache_t redirMx", LOCK_HIERARCHY_SCACHE_REDIRMX);
scp->serverLock = -1;
+ scp->dataVersion = CM_SCACHE_VERSION_BAD;
+ scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
+ scp->lockDataVersion = CM_SCACHE_VERSION_BAD;
+ scp->mpDataVersion = CM_SCACHE_VERSION_BAD;
/* and put it in the LRU queue */
osi_QAddH((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **)&cm_data.scacheLRULastp, &scp->q);
- cm_data.currentSCaches++;
cm_dnlcPurgedp(scp); /* make doubly sure that this is not in dnlc */
cm_dnlcPurgevp(scp);
scp->allNextp = cm_data.allSCachesp;
cm_data.fakeSCache.magic = CM_SCACHE_MAGIC;
cm_data.fakeSCache.cbServerp = (struct cm_server *)(-1);
cm_data.fakeSCache.cbExpires = (time_t)-1;
+ cm_data.fakeSCache.cbExpires = time(NULL);
/* can leave clientModTime at 0 */
cm_data.fakeSCache.fileType = CM_SCACHETYPE_FILE;
cm_data.fakeSCache.unixModeBits = 0777;
scp->cbServerp = NULL;
}
scp->cbExpires = 0;
- _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_CALLBACK);
+ scp->cbIssued = 0;
lock_ReleaseWrite(&scp->rw);
#ifdef USE_BPLUS
#endif
scp->cbServerp = NULL;
scp->cbExpires = 0;
+ scp->cbIssued = 0;
scp->volumeCreationDate = 0;
scp->fileLocksH = NULL;
scp->fileLocksT = NULL;
scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
#endif
scp->waitQueueT = NULL;
- _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_CALLBACK | CM_SCACHEFLAG_WAITING | CM_SCACHEFLAG_RDR_IN_USE));
+ _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_WAITING | CM_SCACHEFLAG_RDR_IN_USE));
scp->redirBufCount = 0;
scp->redirQueueT = NULL;
}
#ifdef DEBUG_REFCOUNT
-long cm_GetSCacheDbg(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
+long cm_GetSCacheDbg(cm_fid_t *fidp, cm_fid_t *parentFidp, cm_scache_t **outScpp, cm_user_t *userp,
cm_req_t *reqp, char * file, long line)
#else
-long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
+long cm_GetSCache(cm_fid_t *fidp, cm_fid_t *parentFidp, cm_scache_t **outScpp, cm_user_t *userp,
cm_req_t *reqp)
#endif
{
cm_data.fakeDirVersion != scp->dataVersion)
break;
#endif
+ if (parentFidp && scp->parentVnode == 0) {
+ scp->parentVnode = parentFidp->vnode;
+ scp->parentUnique = parentFidp->unique;
+ }
cm_HoldSCacheNoLock(scp);
*outScpp = scp;
lock_ConvertRToW(&cm_scacheLock);
lock_ObtainWrite(&scp->rw);
}
scp->fid = *fidp;
- scp->dotdotFid.cell=AFS_FAKE_ROOT_CELL_ID;
- scp->dotdotFid.volume=AFS_FAKE_ROOT_VOL_ID;
- scp->dotdotFid.unique=1;
- scp->dotdotFid.vnode=1;
+ cm_SetFid(&scp->dotdotFid,AFS_FAKE_ROOT_CELL_ID,AFS_FAKE_ROOT_VOL_ID,1,1);
+ if (parentFidp) {
+ scp->parentVnode = parentFidp->vnode;
+ scp->parentUnique = parentFidp->unique;
+ }
_InterlockedOr(&scp->flags, (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO));
lock_ObtainWrite(&cm_scacheLock);
if (!(scp->flags & CM_SCACHEFLAG_INHASH)) {
afsi_log("%s:%d cm_GetSCache (3) scp 0x%p ref %d", file, line, scp, scp->refCount);
osi_Log1(afsd_logp,"cm_GetSCache (3) scp 0x%p", scp);
#endif
+ if (parentFidp && scp->parentVnode == 0) {
+ scp->parentVnode = parentFidp->vnode;
+ scp->parentUnique = parentFidp->unique;
+ }
if (volp)
cm_PutVolume(volp);
cm_HoldSCacheNoLock(scp);
scp->fid = *fidp;
if (!cm_freelanceEnabled || !isRoot) {
/* if this scache entry represents a volume root then we need
- * to copy the dotdotFipd from the volume structure where the
+ * to copy the dotdotFid from the volume structure where the
* "master" copy is stored (defect 11489)
*/
if (volp->vol[ROVOL].ID == fidp->volume) {
scp->dotdotFid = cm_VolumeStateByType(volp, RWVOL)->dotdotFid;
}
}
+ if (parentFidp) {
+ scp->parentVnode = parentFidp->vnode;
+ scp->parentUnique = parentFidp->unique;
+ }
if (volp)
cm_PutVolume(volp);
cm_fid_t parent_fid;
cm_scache_t * pscp = NULL;
+ if (scp->parentVnode == 0)
+ return NULL;
+
lock_ObtainWrite(&cm_scacheLock);
cm_SetFid(&parent_fid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique);
afs_uint32 sleep_buf_cmflags = 0;
afs_uint32 sleep_scp_bufs = 0;
int wakeupCycle;
+ afs_int32 waitCount;
+ afs_int32 waitRequests;
lock_AssertWrite(&scp->rw);
if ((flags & CM_SCACHESYNC_FORCECB) || !cm_HaveCallback(scp)) {
osi_Log1(afsd_logp, "CM SyncOp getting callback on scp 0x%p",
scp);
+
+ if (cm_EAccesFindEntry(userp, &scp->fid))
+ return CM_ERROR_NOACCESS;
+
if (bufLocked)
lock_ReleaseMutex(&bufp->mx);
code = cm_GetCallback(scp, userp, reqp, (flags & CM_SCACHESYNC_FORCECB)?1:0);
/* wait here, then try again */
osi_Log1(afsd_logp, "CM SyncOp sleeping scp 0x%p", scp);
- if ( scp->flags & CM_SCACHEFLAG_WAITING ) {
- scp->waitCount++;
- scp->waitRequests++;
+
+ waitCount = InterlockedIncrement(&scp->waitCount);
+ waitRequests = InterlockedIncrement(&scp->waitRequests);
+ if (waitCount > 1) {
osi_Log3(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING already set for 0x%p; %d threads; %d requests",
- scp, scp->waitCount, scp->waitRequests);
+ scp, waitCount, waitRequests);
} else {
osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING set for 0x%p", scp);
_InterlockedOr(&scp->flags, CM_SCACHEFLAG_WAITING);
- scp->waitCount = scp->waitRequests = 1;
}
cm_SyncOpAddToWaitQueue(scp, flags, bufp);
cm_UpdateServerPriority();
- scp->waitCount--;
+ waitCount = InterlockedDecrement(&scp->waitCount);
osi_Log3(afsd_logp, "CM SyncOp woke! scp 0x%p; still waiting %d threads of %d requests",
- scp, scp->waitCount, scp->waitRequests);
- if (scp->waitCount == 0) {
+ scp, waitCount, scp->waitRequests);
+ if (waitCount == 0) {
osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING reset for 0x%p", scp);
_InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_WAITING);
scp->waitRequests = 0;
}
/* and wakeup anyone who is waiting */
- if (scp->flags & CM_SCACHEFLAG_WAITING) {
+ if ((scp->flags & CM_SCACHEFLAG_WAITING) ||
+ !osi_QIsEmpty(&scp->waitQueueH)) {
osi_Log3(afsd_logp, "CM SyncOpDone 0x%x Waking scp 0x%p bufp 0x%p", flags, scp, bufp);
osi_Wakeup((LONG_PTR) &scp->flags);
}
}
+static afs_uint32
+dv_diff(afs_uint64 dv1, afs_uint64 dv2)
+{
+ if ( dv1 - dv2 > 0x7FFFFFFF )
+ return (afs_uint32)(dv2 - dv1);
+ else
+ return (afs_uint32)(dv1 - dv2);
+}
+
+long
+cm_IsStatusValid(AFSFetchStatus *statusp)
+{
+ if (statusp->InterfaceVersion != 0x1 ||
+ !(statusp->FileType > 0 && statusp->FileType <= SymbolicLink)) {
+ return 0;
+ }
+
+ return 1;
+}
+
/* merge in a response from an RPC. The scp must be locked, and the callback
* is optional.
*
* handled after the callback breaking is done, but only one of whose calls
* started before that, can cause old info to be merged from the first call.
*/
-void cm_MergeStatus(cm_scache_t *dscp,
+long cm_MergeStatus(cm_scache_t *dscp,
cm_scache_t *scp, AFSFetchStatus *statusp,
AFSVolSync *volsyncp,
cm_user_t *userp, cm_req_t *reqp, afs_uint32 flags)
}
#endif /* AFS_FREELANCE_CLIENT */
+ if (!cm_IsStatusValid(statusp)) {
+ osi_Log3(afsd_logp, "Merge: Bad Status scp 0x%p Invalid InterfaceVersion %d FileType %d",
+ scp, statusp->InterfaceVersion, statusp->FileType);
+ return CM_ERROR_INVAL;
+ }
+
if (statusp->errorCode != 0) {
switch (statusp->errorCode) {
case EACCES:
case UAEACCES:
case EPERM:
case UAEPERM:
- _InterlockedOr(&scp->flags, CM_SCACHEFLAG_EACCESS);
+ cm_EAccesAddEntry(userp, &scp->fid, &dscp->fid);
}
osi_Log2(afsd_logp, "Merge, Failure scp 0x%p code 0x%x", scp, statusp->errorCode);
if (scp->fid.vnode & 0x1)
scp->fileType = CM_SCACHETYPE_DIRECTORY;
else
- scp->fileType = 0; /* unknown */
+ scp->fileType = CM_SCACHETYPE_UNKNOWN;
scp->serverModTime = 0;
scp->clientModTime = 0;
scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
scp->fsLockCount = 0;
- if (dscp) {
+ if (dscp && dscp != scp) {
scp->parentVnode = dscp->fid.vnode;
scp->parentUnique = dscp->fid.unique;
} else {
if (RDR_Initialized)
rdr_invalidate = 1;
- } else {
- _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_EACCESS);
}
dataVersion = statusp->dataVersionHigh;
scp->cbServerp->addr.sin_addr.s_addr,
volp ? volp->namep : "(unknown)");
}
+
osi_Log3(afsd_logp, "Bad merge, scp 0x%p, scp dv %d, RPC dv %d",
scp, scp->dataVersion, dataVersion);
/* we have a number of data fetch/store operations running
goto done;
}
- if (cm_readonlyVolumeVersioning)
+ /*
+ * The first field of the volsync parameter is supposed to be the
+ * volume creation date. Unfortunately, pre-OpenAFS 1.4.11 and 1.6.0
+ * file servers do not populate the VolSync structure for BulkStat and
+ * InlineBulkStat RPCs. As a result, the volume creation date is not
+ * trustworthy when status is obtained via [Inline]BulkStatus RPCs.
+ * If cm_readonlyVolumeVersioning is set, it is assumed that all file
+ * servers populate the VolSync structure at all times.
+ */
+ if (cm_readonlyVolumeVersioning || !(flags & CM_MERGEFLAG_BULKSTAT))
scp->volumeCreationDate = volsyncp->spare1; /* volume creation date */
+ else
+ scp->volumeCreationDate = 0;
scp->serverModTime = statusp->ServerModTime;
cm_AddACLCache(scp, userp, statusp->CallerAccess);
}
- if (dataVersion != 0 &&
- (!(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && dataVersion != scp->dataVersion ||
- (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && dataVersion - scp->dataVersion > activeRPCs)) {
+ if (dataVersion != 0 && scp->dataVersion != CM_SCACHE_VERSION_BAD &&
+ (!(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && (dataVersion != scp->dataVersion) ||
+ (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) &&
+ (dv_diff(dataVersion, scp->dataVersion) > activeRPCs))) {
/*
* We now know that all of the data buffers that we have associated
* with this scp are invalid. Subsequent operations will go faster
lock_ReleaseWrite(&buf_globalLock);
}
- /*
- * If the dataVersion has changed, the mountPointStringp must be cleared
- * in order to force a re-evaluation by cm_HandleLink(). The Windows CM
- * does not update a mountpoint or symlink by altering the contents of
- * the file data; but the Unix CM does.
- */
if (scp->dataVersion != dataVersion && !(flags & CM_MERGEFLAG_FETCHDATA)) {
- scp->mountPointStringp[0] = '\0';
-
osi_Log5(afsd_logp, "cm_MergeStatus data version change scp 0x%p cell %u vol %u vn %u uniq %u",
scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
* object during an uncontested storeData operation. As a result this
* merge status no longer has performance characteristics derived from
* the size of the file.
+ *
+ * For directory buffers, only current dataVersion values are up to date.
*/
- if (((flags & CM_MERGEFLAG_STOREDATA) && dataVersion - scp->dataVersion > activeRPCs) ||
- (!(flags & CM_MERGEFLAG_STOREDATA) && scp->dataVersion != dataVersion) ||
- scp->bufDataVersionLow == 0)
+ if (((flags & (CM_MERGEFLAG_STOREDATA|CM_MERGEFLAG_DIROP)) && (dv_diff(dataVersion, scp->dataVersion) > activeRPCs)) ||
+ (!(flags & (CM_MERGEFLAG_STOREDATA|CM_MERGEFLAG_DIROP)) && (scp->dataVersion != dataVersion)) ||
+ scp->bufDataVersionLow == CM_SCACHE_VERSION_BAD ||
+ scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ flags & CM_MERGEFLAG_CACHE_BYPASS) {
scp->bufDataVersionLow = dataVersion;
+ }
if (RDR_Initialized) {
- if (scp->dataVersion != CM_SCACHE_VERSION_BAD) {
- rdr_invalidate = 1;
- } else if ( ( !(reqp->flags & CM_REQ_SOURCE_REDIR) || !(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA))) &&
- scp->dataVersion != dataVersion && (dataVersion - scp->dataVersion > activeRPCs - 1)) {
+ /*
+ * The redirector maintains its own cached status information which
+ * must be updated when a DV change occurs that is not the result
+ * of a redirector initiated data change.
+ *
+ * If the current old DV is BAD, send a DV change notification.
+ *
+ * If the DV has changed and request was not initiated by the
+ * redirector, send a DV change notification.
+ *
+ * If the request was initiated by the redirector, send a notification
+ * for store and directory operations that result in a DV change greater
+ * than the number of active RPCs or any other operation that results
+ * in an unexpected DV change such as FetchStatus.
+ */
+
+ if (scp->dataVersion == CM_SCACHE_VERSION_BAD && dataVersion != 0) {
rdr_invalidate = 1;
- } else if ( (reqp->flags & CM_REQ_SOURCE_REDIR) && (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) &&
- dataVersion - scp->dataVersion > activeRPCs) {
+ } else if (!(reqp->flags & CM_REQ_SOURCE_REDIR) && scp->dataVersion != dataVersion) {
rdr_invalidate = 1;
+ } else if (reqp->flags & CM_REQ_SOURCE_REDIR) {
+ if (!(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) &&
+ (dv_diff(dataVersion, scp->dataVersion) > activeRPCs - 1)) {
+ rdr_invalidate = 1;
+ } else if ((flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) &&
+ dv_diff(dataVersion, scp->dataVersion) > activeRPCs) {
+ rdr_invalidate = 1;
+ }
}
}
scp->dataVersion = dataVersion;
}
}
+ /* Remove cached EACCES / EPERM errors if the file is a directory */
+ if (scp->fileType == CM_SCACHETYPE_DIRECTORY &&
+ !(volp && (volp->flags & CM_VOLUMEFLAG_DFS_VOLUME)) &&
+ !cm_accessPerFileCheck)
+ {
+ cm_EAccesClearParentEntries(&scp->fid);
+ }
+
done:
if (volp)
cm_PutVolume(volp);
scp->fileType, AFS_INVALIDATE_DATA_VERSION);
lock_ObtainWrite(&scp->rw);
}
+
+ return 0;
}
/* note that our stat cache info is incorrect, so force us eventually
scp->cbServerp = NULL;
}
scp->cbExpires = 0;
- scp->volumeCreationDate = 0;
- _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_CALLBACK | CM_SCACHEFLAG_LOCAL | CM_SCACHEFLAG_RDR_IN_USE));
+ scp->cbIssued = 0;
+ _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_LOCAL | CM_SCACHEFLAG_RDR_IN_USE));
cm_dnlcPurgedp(scp);
cm_dnlcPurgevp(scp);
cm_FreeAllACLEnts(scp);
if (scp->fileType == CM_SCACHETYPE_DFSLINK)
cm_VolStatus_Invalidate_DFS_Mapping(scp);
-
- /* Force mount points and symlinks to be re-evaluated */
- scp->mountPointStringp[0] = '\0';
}
void cm_AFSFidFromFid(AFSFid *afsFidp, cm_fid_t *fidp)
}
sprintf(output,
"%s scp=0x%p, fid (cell=%d, volume=%d, vnode=%d, unique=%d) type=%d dv=%I64d len=0x%I64x "
- "mp='%s' Locks (server=0x%x shared=%d excl=%d clnt=%d) fsLockCount=%d linkCount=%d anyAccess=0x%x "
+ "mpDV=%I64d mp='%s' Locks (server=0x%x shared=%d excl=%d clnt=%d) fsLockCount=%d linkCount=%d anyAccess=0x%x "
"flags=0x%x cbServer='%s' cbExpires='%s' volumeCreationDate='%s' refCount=%u\r\n",
cookie, scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
- scp->fileType, scp->dataVersion, scp->length.QuadPart, scp->mountPointStringp,
+ scp->fileType, scp->dataVersion, scp->length.QuadPart, scp->mpDataVersion, scp->mountPointStringp,
scp->serverLock, scp->sharedLocks, scp->exclusiveLocks, scp->clientLocks, scp->fsLockCount,
scp->linkCount, scp->anyAccess, scp->flags, srvStr ? srvStr : "<none>", cbt ? cbt : "<none>",
cdrot ? cdrot : "<none>", scp->refCount);