require_64bit_ops = 1;
}
+ InterlockedIncrement(&scp->activeRPCs);
lock_ReleaseWrite(&scp->rw);
/* now we're ready to do the store operation */
cm_MergeStatus(NULL, scp, &outStatus, &volSync, userp, reqp, CM_MERGEFLAG_STOREDATA);
} else {
+ InterlockedDecrement(&scp->activeRPCs);
if (code == CM_ERROR_SPACE)
_InterlockedOr(&scp->flags, CM_SCACHEFLAG_OUTOFSPACE);
else if (code == CM_ERROR_QUOTA)
require_64bit_ops = 1;
}
+ InterlockedIncrement(&scp->activeRPCs);
lock_ReleaseWrite(&scp->rw);
cm_AFSFidFromFid(&tfid, &scp->fid);
if (LargeIntegerGreaterThanOrEqualTo(t, scp->length))
_InterlockedAnd(&scp->mask, ~CM_SCACHEMASK_LENGTH);
cm_MergeStatus(NULL, scp, &outStatus, &volSync, userp, reqp, CM_MERGEFLAG_STOREDATA);
+ } else {
+ InterlockedDecrement(&scp->activeRPCs);
}
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL);
return 0;
}
+ InterlockedIncrement(&scp->activeRPCs);
lock_ReleaseWrite(&scp->rw);
scp_locked = 0;
if (code == 0)
cm_MergeStatus(NULL, scp, &afsStatus, &volSync, userp, reqp, CM_MERGEFLAG_FETCHDATA);
+ else
+ InterlockedDecrement(&scp->activeRPCs);
return code;
}
require_64bit_ops = 1;
}
+ InterlockedIncrement(&scp->activeRPCs);
osi_Log2(afsd_logp, "cm_GetData: fetching data scp %p DV 0x%x", scp, scp->dataVersion);
#ifdef AFS_FREELANCE_CLIENT
if (code == 0)
cm_MergeStatus(NULL, scp, &afsStatus, &volSync, userp, reqp, CM_MERGEFLAG_FETCHDATA);
+ else
+ InterlockedDecrement(&scp->activeRPCs);
return code;
}
scp->openShares = 0;
scp->openExcls = 0;
scp->waitCount = 0;
+ scp->activeRPCs = 0;
#ifdef USE_BPLUS
scp->dirBplus = NULL;
scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
afs_uint64 dataVersion;
struct cm_volume *volp = NULL;
struct cm_cell *cellp = NULL;
+ int rdr_invalidate = 0;
+ afs_uint32 activeRPCs;
lock_AssertWrite(&scp->rw);
+ activeRPCs = 1 + InterlockedDecrement(&scp->activeRPCs);
+
// yj: i want to create some fake status for the /afs directory and the
// entries under that directory
#ifdef AFS_FREELANCE_CLIENT
if (scp->dataVersion != 0 &&
(!(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && dataVersion != scp->dataVersion ||
- (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && dataVersion - scp->dataVersion > 1)) {
+ (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && 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
* if the buffers are removed from the hash tables.
*
- * We do not remove directory buffers if the dataVersion delta is 1 because
+ * We do not remove directory buffers if the dataVersion delta is 'activeRPCs' because
* those version numbers will be updated as part of the directory operation.
*
* We do not remove storedata buffers because they will still be valid.
* merge status no longer has performance characteristics derived from
* the size of the file.
*/
- if (((flags & CM_MERGEFLAG_STOREDATA) && dataVersion - scp->dataVersion > 1) ||
+ if (((flags & CM_MERGEFLAG_STOREDATA) && dataVersion - scp->dataVersion > activeRPCs) ||
(!(flags & CM_MERGEFLAG_STOREDATA) && scp->dataVersion != dataVersion) ||
scp->bufDataVersionLow == 0)
scp->bufDataVersionLow = dataVersion;
if (RDR_Initialized && scp->dataVersion != CM_SCACHE_VERSION_BAD) {
if ( ( !(reqp->flags & CM_REQ_SOURCE_REDIR) || !(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA))) &&
- scp->dataVersion != dataVersion ) {
- RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
- scp->fid.unique, scp->fid.hash,
- scp->fileType, AFS_INVALIDATE_DATA_VERSION);
+ scp->dataVersion != dataVersion && (dataVersion - scp->dataVersion > activeRPCs - 1)) {
+ rdr_invalidate = 1;
} else if ( (reqp->flags & CM_REQ_SOURCE_REDIR) && (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) &&
- dataVersion - scp->dataVersion > 1) {
- RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
- scp->fid.unique, scp->fid.hash,
- scp->fileType, AFS_INVALIDATE_DATA_VERSION);
+ dataVersion - scp->dataVersion > activeRPCs) {
+ rdr_invalidate = 1;
}
}
scp->dataVersion = dataVersion;
lock_ReleaseWrite(&volp->rw);
}
}
+
done:
if (volp)
cm_PutVolume(volp);
+ /*
+ * The scache rw lock cannot be held across the invalidation.
+ * Doing so can result in deadlocks with other threads processing
+ * requests initiated by the afs redirector.
+ */
+ if (rdr_invalidate) {
+ lock_ReleaseWrite(&scp->rw);
+ RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+ scp->fid.unique, scp->fid.hash,
+ scp->fileType, AFS_INVALIDATE_DATA_VERSION);
+ lock_ObtainWrite(&scp->rw);
+ }
}
/* note that our stat cache info is incorrect, so force us eventually
}
/* make the RPC */
+ InterlockedIncrement(&dscp->activeRPCs);
+
afsFid.Volume = dscp->fid.volume;
afsFid.Vnode = dscp->fid.vnode;
afsFid.Unique = dscp->fid.unique;
RDR_InvalidateObject(dscp->fid.cell, dscp->fid.volume, dscp->fid.vnode,
dscp->fid.unique, dscp->fid.hash,
dscp->fileType, AFS_INVALIDATE_DATA_VERSION);
- } else if (code == CM_ERROR_NOSUCHFILE) {
- /* windows would not have allowed the request to delete the file
- * if it did not believe the file existed. therefore, we must
- * have an inconsistent view of the world.
- */
- dscp->cbServerp = NULL;
+ } else {
+ InterlockedDecrement(&scp->activeRPCs);
+ if (code == CM_ERROR_NOSUCHFILE) {
+ /* windows would not have allowed the request to delete the file
+ * if it did not believe the file existed. therefore, we must
+ * have an inconsistent view of the world.
+ */
+ dscp->cbServerp = NULL;
+ }
}
cm_SyncOpDone(dscp, NULL, sflags);
lock_ReleaseWrite(&dscp->rw);
&bbp->callbacks[j],
&volSync,
CM_CALLBACK_MAINTAINCOUNT);
+ InterlockedIncrement(&scp->activeRPCs);
cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, reqp, 0);
lock_ReleaseWrite(&scp->rw);
} else {
lock_ReleaseRead(&scp->rw);
/* now make the RPC */
+ InterlockedIncrement(&scp->activeRPCs);
+
osi_Log1(afsd_logp, "CALL StoreStatus scp 0x%p", scp);
do {
code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
if (code == 0)
cm_MergeStatus(NULL, scp, &afsOutStatus, &volSync, userp, reqp,
CM_MERGEFLAG_FORCE|CM_MERGEFLAG_STOREDATA);
+ else
+ InterlockedDecrement(&scp->activeRPCs);
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
/* if we're changing the mode bits, discard the ACL cache,
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL CreateFile scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
lock_ObtainWrite(&dscp->rw);
if (code == 0)
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ else
+ InterlockedDecrement(&dscp->activeRPCs);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
if (!cm_HaveCallback(scp)) {
cm_EndCallbackGrantingCall(scp, &cbReq,
&newFileCallback, &volSync, 0);
+ InterlockedIncrement(&scp->activeRPCs);
cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
userp, reqp, 0);
didEnd = 1;
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL MakeDir scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
lock_ObtainWrite(&dscp->rw);
if (code == 0)
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ else
+ InterlockedDecrement(&dscp->activeRPCs);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
if (!cm_HaveCallback(scp)) {
cm_EndCallbackGrantingCall(scp, &cbReq,
&newDirCallback, &volSync, 0);
+ InterlockedIncrement(&scp->activeRPCs);
cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
userp, reqp, 0);
didEnd = 1;
fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL Link scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
RDR_InvalidateObject(dscp->fid.cell, dscp->fid.volume, dscp->fid.vnode,
dscp->fid.unique, dscp->fid.hash,
dscp->fileType, AFS_INVALIDATE_DATA_VERSION);
+ } else {
+ InterlockedDecrement(&dscp->activeRPCs);
}
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
/* Update the linked object status */
if (code == 0) {
lock_ObtainWrite(&sscp->rw);
+ InterlockedIncrement(&sscp->activeRPCs);
cm_MergeStatus(NULL, sscp, &newLinkStatus, &volSync, userp, reqp, 0);
lock_ReleaseWrite(&sscp->rw);
}
cm_StatusFromAttr(&inStatus, NULL, attrp);
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL Symlink scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
lock_ObtainWrite(&dscp->rw);
if (code == 0)
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ else
+ InterlockedDecrement(&dscp->activeRPCs);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
if (code == 0) {
lock_ObtainWrite(&scp->rw);
if (!cm_HaveCallback(scp)) {
+ InterlockedIncrement(&scp->activeRPCs);
cm_MergeStatus(dscp, scp, &newLinkStatus, &volSync,
userp, reqp, 0);
}
didEnd = 0;
/* try the RPC now */
+ InterlockedIncrement(&dscp->activeRPCs);
osi_Log1(afsd_logp, "CALL RemoveDir scp 0x%p", dscp);
do {
code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
if (code == 0) {
cm_dnlcRemove(dscp, cnamep);
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+ } else {
+ InterlockedDecrement(&dscp->activeRPCs);
}
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
newNamep = cm_ClientStringToFsStringAlloc(cNewNamep, -1, NULL);
/* try the RPC now */
+ InterlockedIncrement(&oldDscp->activeRPCs);
+ if (!oneDir)
+ InterlockedIncrement(&newDscp->activeRPCs);
osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p",
oldDscp, newDscp);
do {
if (code == 0)
cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
userp, reqp, CM_MERGEFLAG_DIROP);
+ else
+ InterlockedDecrement(&oldDscp->activeRPCs);
cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&oldDscp->rw);
if (code == 0)
cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
userp, reqp, CM_MERGEFLAG_DIROP);
+ else
+ InterlockedIncrement(&newDscp->activeRPCs);
cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&newDscp->rw);