/* Forward declarations. */
static void afs_GetDownD(int anumber, int *aneedSpace, afs_int32 buckethint);
-static void afs_FreeDiscardedDCache(void);
+static int afs_FreeDiscardedDCache(void);
static void afs_DiscardDCache(struct dcache *);
static void afs_FreeDCache(struct dcache *);
/* For split cache */
*/
while (afs_blocksDiscarded && !afs_WaitForCacheDrain
&& (afs_termState != AFSOP_STOP_TRUNCDAEMON)) {
- afs_FreeDiscardedDCache();
+ int code = afs_FreeDiscardedDCache();
+ if (code) {
+ /* If we can't free any discarded dcache entries, that's okay.
+ * We're just doing this in the background; if someone needs
+ * discarded entries freed, they will try it themselves and/or
+ * signal us that the cache is too full. In any case, we'll
+ * try doing this again the next time we run through the loop.
+ */
+ break;
+ }
}
/* See if we need to continue to run. Someone may have
/*!
* Free the next element on the list of discarded cache elements.
+ *
+ * Returns -1 if we encountered an error preventing us from freeing a
+ * discarded dcache, or 0 on success.
*/
-static void
+static int
afs_FreeDiscardedDCache(void)
{
struct dcache *tdc;
ObtainWriteLock(&afs_xdcache, 510);
if (!afs_blocksDiscarded) {
ReleaseWriteLock(&afs_xdcache);
- return;
+ return 0;
}
/*
* Get an entry from the list of discarded cache elements
*/
tdc = afs_GetDSlotFromList(&afs_discardDCList);
- osi_Assert(tdc);
+ if (!tdc) {
+ ReleaseWriteLock(&afs_xdcache);
+ return -1;
+ }
afs_discardDCCount--;
size = ((tdc->f.chunkBytes + afs_fsfragsize) ^ afs_fsfragsize) >> 10; /* round up */
ReleaseWriteLock(&tdc->lock);
afs_PutDCache(tdc);
ReleaseWriteLock(&afs_xdcache);
+
+ return 0;
}
/*!
while (afs_blocksDiscarded
&& (afs_blocksUsed >
PERCENT(CM_WAITFORDRAINPCT, afs_cacheBlocks))) {
- afs_FreeDiscardedDCache();
+ int code = afs_FreeDiscardedDCache();
+ if (code) {
+ /* Callers depend on us to get the afs_blocksDiscarded count down.
+ * If we cannot do that, the callers can spin by calling us over
+ * and over. Panic for now until we can figure out something
+ * better. */
+ osi_Panic("Error freeing discarded dcache");
+ }
}
return 0;
}
return NULL;
} /*afs_FindDCache */
+/* only call these from afs_AllocDCache() */
+static struct dcache *
+afs_AllocFreeDSlot(void)
+{
+ struct dcache *tdc;
+
+ tdc = afs_GetDSlotFromList(&afs_freeDCList);
+ if (!tdc) {
+ return NULL;
+ }
+ afs_indexFlags[tdc->index] &= ~IFFree;
+ ObtainWriteLock(&tdc->lock, 604);
+ afs_freeDCCount--;
+
+ return tdc;
+}
+static struct dcache *
+afs_AllocDiscardDSlot(afs_int32 lock)
+{
+ struct dcache *tdc;
+ afs_uint32 size = 0;
+ struct osi_file *file;
+
+ tdc = afs_GetDSlotFromList(&afs_discardDCList);
+ if (!tdc) {
+ return NULL;
+ }
+ afs_indexFlags[tdc->index] &= ~IFDiscarded;
+ ObtainWriteLock(&tdc->lock, 605);
+ afs_discardDCCount--;
+ size =
+ ((tdc->f.chunkBytes +
+ afs_fsfragsize) ^ afs_fsfragsize) >> 10;
+ tdc->f.states &= ~(DRO|DBackup|DRW);
+ afs_DCMoveBucket(tdc, size, 0);
+ afs_blocksDiscarded -= size;
+ afs_stats_cmperf.cacheBlocksDiscarded = afs_blocksDiscarded;
+ if ((lock & 2)) {
+ /* Truncate the chunk so zeroes get filled properly */
+ file = afs_CFileOpen(&tdc->f.inode);
+ afs_CFileTruncate(file, 0);
+ afs_CFileClose(file);
+ afs_AdjustSize(tdc, 0);
+ }
+
+ return tdc;
+}
/*!
* Get a fresh dcache from the free or discarded list.
struct VenusFid *ashFid)
{
struct dcache *tdc = NULL;
- afs_uint32 size = 0;
- struct osi_file *file;
- if (afs_discardDCList == NULLIDX
- || ((lock & 2) && afs_freeDCList != NULLIDX)) {
-
- tdc = afs_GetDSlotFromList(&afs_freeDCList);
- osi_Assert(tdc);
- afs_indexFlags[tdc->index] &= ~IFFree;
- ObtainWriteLock(&tdc->lock, 604);
- afs_freeDCCount--;
+ /* if (lock & 2), prefer 'free' dcaches; otherwise, prefer 'discard'
+ * dcaches. In either case, try both if our first choice doesn't work. */
+ if ((lock & 2)) {
+ tdc = afs_AllocFreeDSlot();
+ if (!tdc) {
+ tdc = afs_AllocDiscardDSlot(lock);
+ }
} else {
- tdc = afs_GetDSlotFromList(&afs_discardDCList);
- osi_Assert(tdc);
- afs_indexFlags[tdc->index] &= ~IFDiscarded;
- ObtainWriteLock(&tdc->lock, 605);
- afs_discardDCCount--;
- size =
- ((tdc->f.chunkBytes +
- afs_fsfragsize) ^ afs_fsfragsize) >> 10;
- tdc->f.states &= ~(DRO|DBackup|DRW);
- afs_DCMoveBucket(tdc, size, 0);
- afs_blocksDiscarded -= size;
- afs_stats_cmperf.cacheBlocksDiscarded = afs_blocksDiscarded;
- if (lock & 2) {
- /* Truncate the chunk so zeroes get filled properly */
- file = afs_CFileOpen(&tdc->f.inode);
- afs_CFileTruncate(file, 0);
- afs_CFileClose(file);
- afs_AdjustSize(tdc, 0);
+ tdc = afs_AllocDiscardDSlot(lock);
+ if (!tdc) {
+ tdc = afs_AllocFreeDSlot();
}
}
+ if (!tdc) {
+ return NULL;
+ }
/*
* Locks held:
goto done;
}
- /* Make sure there is a free dcache entry for us to use */
if (afs_discardDCList == NULLIDX && afs_freeDCList == NULLIDX) {
- while (1) {
- if (!setLocks)
- avc->f.states |= CDCLock;
- /* just need slots */
- afs_GetDownD(5, (int *)0, afs_DCGetBucket(avc));
- if (!setLocks)
- avc->f.states &= ~CDCLock;
- if (afs_discardDCList != NULLIDX
- || afs_freeDCList != NULLIDX)
- break;
- /* If we can't get space for 5 mins we give up and panic */
- if (++downDCount > 300) {
- osi_Panic("getdcache");
- }
- ReleaseWriteLock(&afs_xdcache);
- /*
- * Locks held:
- * avc->lock(R) if setLocks
- * avc->lock(W) if !setLocks
- */
- afs_osi_Wait(1000, 0, 0);
- goto RetryLookup;
- }
+ if (!setLocks)
+ avc->f.states |= CDCLock;
+ /* just need slots */
+ afs_GetDownD(5, (int *)0, afs_DCGetBucket(avc));
+ if (!setLocks)
+ avc->f.states &= ~CDCLock;
}
-
tdc = afs_AllocDCache(avc, chunk, aflags, NULL);
+ if (!tdc) {
+ /* If we can't get space for 5 mins we give up and panic */
+ if (++downDCount > 300)
+ osi_Panic("getdcache");
+ ReleaseWriteLock(&afs_xdcache);
+ /*
+ * Locks held:
+ * avc->lock(R) if setLocks
+ * avc->lock(W) if !setLocks
+ */
+ afs_osi_Wait(1000, 0, 0);
+ goto RetryLookup;
+ }
+
+ /*
+ * Locks held:
+ * avc->lock(R) if setLocks
+ * avc->lock(W) if !setLocks
+ * tdc->lock(W)
+ * afs_xdcache(W)
+ */
/*
* Now add to the two hash chains - note that i is still set
/* Get a fresh dcache. */
new_dc = afs_AllocDCache(avc, 0, 0, &shadow_fid);
+ osi_Assert(new_dc);
ObtainReadLock(&adc->mflock);