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);
}
}
| CM_SCACHEFLAG_RO
| CM_SCACHEFLAG_PURERO
| CM_SCACHEFLAG_OVERQUOTA
- | CM_SCACHEFLAG_OUTOFSPACE));
+ | CM_SCACHEFLAG_OUTOFSPACE
+ | CM_SCACHEFLAG_ASYNCSTORING));
scp->serverModTime = 0;
scp->dataVersion = CM_SCACHE_VERSION_BAD;
scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
/* 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));
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;
for ( scp = cm_data.scacheLRUFirstp, lscp = NULL, i = 0;
scp;
lscp = scp, scp = (cm_scache_t *) osi_QNext(&scp->q), i++ ) {
+
+ if ( scp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+ scp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+ afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+ fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+ return -18;
+ }
+
if (scp->magic != CM_SCACHE_MAGIC) {
afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
return -1;
}
+
+ if ( scp->nextp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+ scp->nextp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+ afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+ fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+ return -21;
+ }
+
if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
return -2;
}
+
+ if ( scp->randomACLp < (cm_aclent_t *)cm_data.aclBaseAddress ||
+ scp->randomACLp >= (cm_aclent_t *)cm_data.scacheBaseAddress) {
+ afsi_log("cm_ValidateSCache failure: out of range cm_aclent_t pointers");
+ fprintf(stderr, "cm_ValidateSCache failure: out of range cm_aclent_t pointers\n");
+ return -32;
+ }
+
if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
for ( scp = cm_data.scacheLRULastp, lscp = NULL, i = 0; scp;
lscp = scp, scp = (cm_scache_t *) osi_QPrev(&scp->q), i++ ) {
+
+ if ( scp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+ scp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+ afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+ fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+ return -19;
+ }
+
if (scp->magic != CM_SCACHE_MAGIC) {
afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
return -5;
}
+
+ if ( scp->nextp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+ scp->nextp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+ afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+ fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+ return -22;
+ }
+
if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
return -6;
}
+
+ if ( scp->randomACLp < (cm_aclent_t *)cm_data.aclBaseAddress ||
+ scp->randomACLp >= (cm_aclent_t *)cm_data.scacheBaseAddress) {
+ afsi_log("cm_ValidateSCache failure: out of range cm_aclent_t pointers");
+ fprintf(stderr, "cm_ValidateSCache failure: out of range cm_aclent_t pointers\n");
+ return -31;
+ }
+
if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
for ( i=0; i < cm_data.scacheHashTableSize; i++ ) {
for ( scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp ) {
afs_uint32 hash;
+
+ if ( scp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+ scp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+ afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+ fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+ return -20;
+ }
+
hash = CM_SCACHE_HASH(&scp->fid);
+
if (scp->magic != CM_SCACHE_MAGIC) {
afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
return -9;
}
+
+ if ( scp->nextp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+ scp->nextp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+ afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+ fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+ return -23;
+ }
+
if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
return -10;
}
+
+ if ( scp->randomACLp < (cm_aclent_t *)cm_data.aclBaseAddress ||
+ scp->randomACLp >= (cm_aclent_t *)cm_data.scacheBaseAddress) {
+ afsi_log("cm_ValidateSCache failure: out of range cm_aclent_t pointers");
+ fprintf(stderr, "cm_ValidateSCache failure: out of range cm_aclent_t pointers\n");
+ return -30;
+ }
+
if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
if (!cellp) {
/* put back newScp so it can be reused */
lock_ObtainWrite(&cm_scacheLock);
- newScp->flags |= CM_SCACHEFLAG_DELETED;
+ _InterlockedOr(&newScp->flags, CM_SCACHEFLAG_DELETED);
cm_AdjustScacheLRU(newScp);
lock_ReleaseWrite(&newScp->rw);
lock_ReleaseWrite(&cm_scacheLock);
if (code) {
/* put back newScp so it can be reused */
lock_ObtainWrite(&cm_scacheLock);
- newScp->flags |= CM_SCACHEFLAG_DELETED;
+ _InterlockedOr(&newScp->flags, CM_SCACHEFLAG_DELETED);
cm_AdjustScacheLRU(newScp);
lock_ReleaseWrite(&newScp->rw);
lock_ReleaseWrite(&cm_scacheLock);
cm_AdjustScacheLRU(scp);
/* put back newScp so it can be reused */
- newScp->flags |= CM_SCACHEFLAG_DELETED;
+ _InterlockedOr(&newScp->flags, CM_SCACHEFLAG_DELETED);
cm_AdjustScacheLRU(newScp);
lock_ReleaseWrite(&newScp->rw);
lock_ReleaseWrite(&cm_scacheLock);
afs_uint32 sleep_buf_cmflags = 0;
afs_uint32 sleep_scp_bufs = 0;
int wakeupCycle;
+ afs_int32 waitCount;
+ afs_int32 waitRequests;
lock_AssertWrite(&scp->rw);
osi_Log1(afsd_logp, "CM SyncOp getting callback on scp 0x%p",
scp);
- if (cm_EAccesFindEntry(userp, &scp->fid))
- return CM_ERROR_NOACCESS;
+ if (cm_EAccesFindEntry(userp, &scp->fid)) {
+ code = CM_ERROR_NOACCESS;
+ goto on_error;
+ }
if (bufLocked)
lock_ReleaseMutex(&bufp->mx);
lock_ObtainWrite(&scp->rw);
}
if (code)
- return code;
+ goto on_error;
+
flags &= ~CM_SCACHESYNC_FORCECB; /* only force once */
continue;
}
/* can't check access rights without a callback */
osi_assertx(flags & CM_SCACHESYNC_NEEDCALLBACK, "!CM_SCACHESYNC_NEEDCALLBACK");
- if ((rights & (PRSFS_WRITE|PRSFS_DELETE)) && (scp->flags & CM_SCACHEFLAG_RO))
- return CM_ERROR_READONLY;
+ if ((rights & (PRSFS_WRITE|PRSFS_DELETE)) && (scp->flags & CM_SCACHEFLAG_RO)) {
+ code = CM_ERROR_READONLY;
+ goto on_error;
+ }
if (cm_HaveAccessRights(scp, userp, reqp, rights, &outRights)) {
- if (~outRights & rights)
- return CM_ERROR_NOACCESS;
+ if (~outRights & rights) {
+ code = CM_ERROR_NOACCESS;
+ goto on_error;
+ }
}
else {
/* we don't know the required access rights */
lock_ObtainWrite(&scp->rw);
}
if (code)
- return code;
+ goto on_error;
continue;
}
}
/* first check if we're not supposed to wait: fail
* in this case, returning with everything still locked.
*/
- if (flags & CM_SCACHESYNC_NOWAIT)
- return CM_ERROR_WOULDBLOCK;
+ if (flags & CM_SCACHESYNC_NOWAIT) {
+ code = CM_ERROR_WOULDBLOCK;
+ goto on_error;
+ }
/* These are used for minidump debugging */
sleep_scp_flags = scp->flags; /* so we know why we slept */
/* 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;
_InterlockedOr(&bufp->cmFlags, CM_BUF_CMWRITING);
}
- return 0;
+ return 0; /* Success */
+
+ on_error:
+ /*
+ * This thread may have been a waiter that was woken up.
+ * If cm_SyncOp completes due to an error, cm_SyncOpDone() will
+ * never be called. If there are additional threads waiting on
+ * scp those threads will never be woken. Make sure we wake the
+ * next waiting thread before we leave.
+ */
+ if ((scp->flags & CM_SCACHEFLAG_WAITING) ||
+ !osi_QIsEmpty(&scp->waitQueueH)) {
+ osi_Log3(afsd_logp, "CM SyncOp 0x%x Waking scp 0x%p bufp 0x%p",
+ flags, scp, bufp);
+ osi_Wakeup((LONG_PTR) &scp->flags);
+ }
+ return code;
}
/* for those syncops that setup for RPCs.
}
/* 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);
}
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 (statusp->InterfaceVersion != 0x1) {
- osi_Log2(afsd_logp, "Merge, Failure scp 0x%p Invalid InterfaceVersion %u",
- scp, statusp->InterfaceVersion);
- return;
+ 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) {
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;
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)
+ scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ flags & CM_MERGEFLAG_CACHE_BYPASS) {
scp->bufDataVersionLow = dataVersion;
+ }
if (RDR_Initialized) {
/*
scp->fileType, AFS_INVALIDATE_DATA_VERSION);
lock_ObtainWrite(&scp->rw);
}
+
+ return 0;
}
/* note that our stat cache info is incorrect, so force us eventually
osi_Log2(afsd_logp,"cm_ReleaseSCacheNoLock scp 0x%p ref %d",scp, refCount);
afsi_log("%s:%d cm_ReleaseSCacheNoLock scp 0x%p ref %d", file, line, scp, refCount);
#endif
-
- if (refCount == 0 && (scp->flags & CM_SCACHEFLAG_DELETED)) {
- int deleted = 0;
- long lockstate;
-
- lockstate = lock_GetRWLockState(&cm_scacheLock);
- if (lockstate != OSI_RWLOCK_WRITEHELD)
- lock_ReleaseRead(&cm_scacheLock);
- else
- lock_ReleaseWrite(&cm_scacheLock);
-
- lock_ObtainWrite(&scp->rw);
- if (scp->flags & CM_SCACHEFLAG_DELETED)
- deleted = 1;
-
- if (refCount == 0 && deleted) {
- lock_ObtainWrite(&cm_scacheLock);
- cm_RecycleSCache(scp, 0);
- if (lockstate != OSI_RWLOCK_WRITEHELD)
- lock_ConvertWToR(&cm_scacheLock);
- } else {
- if (lockstate != OSI_RWLOCK_WRITEHELD)
- lock_ObtainRead(&cm_scacheLock);
- else
- lock_ObtainWrite(&cm_scacheLock);
- }
- lock_ReleaseWrite(&scp->rw);
- }
}
#ifdef DEBUG_REFCOUNT
afsi_log("%s:%d cm_ReleaseSCache scp 0x%p ref %d", file, line, scp, refCount);
#endif
lock_ReleaseRead(&cm_scacheLock);
-
- if (scp->flags & CM_SCACHEFLAG_DELETED) {
- int deleted = 0;
- lock_ObtainWrite(&scp->rw);
- if (scp->flags & CM_SCACHEFLAG_DELETED)
- deleted = 1;
- if (deleted) {
- lock_ObtainWrite(&cm_scacheLock);
- cm_RecycleSCache(scp, 0);
- lock_ReleaseWrite(&cm_scacheLock);
- }
- lock_ReleaseWrite(&scp->rw);
- }
}
/* just look for the scp entry to get filetype */