lock_ObtainMutex(&bufp->mx);
bufp->cmFlags &= ~CM_BUF_CMSTORING;
bufp->flags &= ~CM_BUF_DIRTY;
+ bufp->flags |= CM_BUF_ERROR;
+ bufp->error = VNOVNODE;
bufp->dataVersion = -1; /* bad */
bufp->dirtyCounter++;
if (bufp->flags & CM_BUF_WAITING) {
lock_ObtainMutex(&bufp->mx);
bufp->cmFlags &= ~CM_BUF_CMFETCHING;
bufp->flags &= ~CM_BUF_DIRTY;
+ bufp->flags |= CM_BUF_ERROR;
+ bufp->error = VNOVNODE;
bufp->dataVersion = -1; /* bad */
bufp->dirtyCounter++;
if (bufp->flags & CM_BUF_WAITING) {
buf_Release(bufp);
}
}
+ buf_CleanDirtyBuffers(scp);
} else {
/* look for things that shouldn't still be set */
osi_assert(scp->bufWritesp == NULL);
/* invalidate so next merge works fine;
* also initialize some flags */
scp->flags &= ~(CM_SCACHEFLAG_STATD
+ | CM_SCACHEFLAG_DELETED
| CM_SCACHEFLAG_RO
| CM_SCACHEFLAG_PURERO
| CM_SCACHEFLAG_OVERQUOTA
cm_scache_t *cm_GetNewSCache(void)
{
cm_scache_t *scp;
+ int retry = 0;
- start:
- if (cm_data.currentSCaches >= cm_data.maxSCaches) {
- for (scp = cm_data.scacheLRULastp;
- scp;
- scp = (cm_scache_t *) osi_QPrev(&scp->q)) {
- if (scp->refCount == 0)
- break;
- }
-
- if (scp) {
- osi_assert(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.hashTablep);
-
- if (!cm_RecycleSCache(scp, 0)) {
-
+ /* first pass - look for deleted objects */
+ for ( scp = cm_data.scacheLRULastp;
+ scp;
+ scp = (cm_scache_t *) osi_QPrev(&scp->q))
+ {
+ osi_assert(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.hashTablep);
+
+ if (scp->refCount == 0) {
+ if (scp->flags & CM_SCACHEFLAG_DELETED) {
+ osi_Log1(afsd_logp, "GetNewSCache attempting to recycle deleted scp 0x%x", scp);
+ if (!cm_RecycleSCache(scp, CM_SCACHE_RECYCLEFLAG_DESTROY_BUFFERS)) {
+
+ /* we found an entry, so return it */
+ /* now remove from the LRU queue and put it back at the
+ * head of the LRU queue.
+ */
+ cm_AdjustLRU(scp);
+
+ /* and we're done */
+ return scp;
+ }
+ osi_Log1(afsd_logp, "GetNewSCache recycled failed scp 0x%x", scp);
+ } else if (!(scp->flags & CM_SCACHEFLAG_INHASH)) {
/* we found an entry, so return it */
/* now remove from the LRU queue and put it back at the
- * head of the LRU queue.
- */
+ * head of the LRU queue.
+ */
cm_AdjustLRU(scp);
/* and we're done */
return scp;
+ }
+ }
+ }
+ osi_Log0(afsd_logp, "GetNewSCache no deleted or recycled entries available for reuse");
+
+ if (cm_data.currentSCaches >= cm_data.maxSCaches) {
+ /* There were no deleted scache objects that we could use. Try to find
+ * one that simply hasn't been used in a while.
+ */
+ while (1) {
+ for ( scp = cm_data.scacheLRULastp;
+ scp;
+ scp = (cm_scache_t *) osi_QPrev(&scp->q))
+ {
+ /* 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. */
+ if (scp->refCount == 0 && scp->bufReadsp == NULL && scp->bufWritesp == NULL) {
+ if (!buf_DirtyBuffersExist(&scp->fid)) {
+ if (!cm_RecycleSCache(scp, 0)) {
+ /* we found an entry, so return it */
+ /* now remove from the LRU queue and put it back at the
+ * head of the LRU queue.
+ */
+ cm_AdjustLRU(scp);
+
+ /* and we're done */
+ return scp;
+ }
+ } else {
+ osi_Log1(afsd_logp,"GetNewSCache dirty buffers exist scp 0x%x", scp);
+ }
+ }
+ }
+ osi_Log1(afsd_logp, "GetNewSCache all scache entries in use (retry = %d)", retry);
+
+ /* If get here it means that every scache is either in use or has dirty buffers.
+ * We used to panic. Now we will give up our lock and wait.
+ */
+ if (++retry < 10) {
+ lock_ReleaseWrite(&cm_scacheLock);
+ Sleep(1000);
+ lock_ObtainWrite(&cm_scacheLock);
} else {
- /* We don't like this entry, choose another one. */
- goto start;
+ return NULL;
}
- }
+ } /* forever */
}
/* if we get here, we should allocate a new scache entry. We either are below
cm_scache_t *scp;
hash = CM_SCACHE_HASH(fidp);
-
- osi_assert(fidp->cell != 0);
+
+ if (fidp->cell == 0) {
+#ifdef DEBUG
+ DebugBreak();
+#endif
+ return NULL;
+ }
lock_ObtainWrite(&cm_scacheLock);
for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
mp = "";
}
scp = cm_GetNewSCache();
-
+ if (scp == NULL) {
+ osi_Log0(afsd_logp,"cm_getSCache unable to obtain *new* scache entry");
+ lock_ReleaseWrite(&cm_scacheLock);
+ return CM_ERROR_WOULDBLOCK;
+ }
+
lock_ObtainMutex(&scp->mx);
scp->fid = *fidp;
scp->volp = cm_data.rootSCachep->volp;
/* now, if we don't have the fid, recycle something */
scp = cm_GetNewSCache();
+ if (scp == NULL) {
+ osi_Log0(afsd_logp,"cm_getSCache unable to obtain *new* scache entry");
+ lock_ReleaseWrite(&cm_scacheLock);
+ return CM_ERROR_WOULDBLOCK;
+ }
+
osi_assert(!(scp->flags & CM_SCACHEFLAG_INHASH));
lock_ObtainMutex(&scp->mx);
scp->fid = *fidp;
// yj: modified this so that callback only checked if we're
// not checking something on /afs
/* fix the conditional to match the one in cm_HaveCallback */
- if ( (flags & CM_SCACHESYNC_NEEDCALLBACK)
+ if ((flags & CM_SCACHESYNC_NEEDCALLBACK)
#ifdef AFS_FREELANCE_CLIENT
&& (!cm_freelanceEnabled ||
!(scp->fid.vnode==0x1 && scp->fid.unique==0x1) ||
scp);
if (bufLocked)
lock_ReleaseMutex(&bufp->mx);
- code = cm_GetCallback(scp, userp, reqp, 0);
+ code = cm_GetCallback(scp, userp, reqp, (flags & CM_SCACHESYNC_FORCECB)?1:0);
if (bufLocked) {
lock_ReleaseMutex(&scp->mx);
lock_ObtainMutex(&bufp->mx);
osi_QDFree(qdp);
}
if (bufp) {
+ int release = 0;
+ if (bufp->cmFlags & CM_BUF_CMFETCHING)
+ release = 1;
bufp->cmFlags &= ~(CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED);
if (bufp->flags & CM_BUF_WAITING) {
osi_Log2(afsd_logp, "CM SyncOpDone Waking [scp 0x%p] bufp 0x%p", scp, bufp);
osi_Wakeup((LONG_PTR) &bufp);
}
- buf_Release(bufp);
+ if (release)
+ buf_Release(bufp);
}
}
osi_QDFree(qdp);
}
if (bufp) {
+ int release = 0;
+ if (bufp->cmFlags & CM_BUF_CMSTORING)
+ release = 1;
bufp->cmFlags &= ~CM_BUF_CMSTORING;
if (bufp->flags & CM_BUF_WAITING) {
osi_Log2(afsd_logp, "CM SyncOpDone Waking [scp 0x%p] bufp 0x%p", scp, bufp);
osi_Wakeup((LONG_PTR) &bufp);
}
- buf_Release(bufp);
+ if (release)
+ buf_Release(bufp);
}
}