/**
* Get a dcache entry from the discard or free list
*
+ * @param[out] adc On success, a dcache from the given list. Otherwise, NULL.
* @param[in] indexp A pointer to the head of the dcache free list or discard
* list (afs_freeDCList, or afs_discardDCList)
*
- * @return A dcache from that list, or NULL if none could be retrieved.
+ * @return 0 on success. If there are no dcache slots available, return ENOSPC.
+ * If we encountered an error in disk i/o while trying to find a
+ * dcache, return EIO.
*
* @pre afs_xdcache is write-locked
*/
-static struct dcache *
-afs_GetDSlotFromList(afs_int32 *indexp)
+static int
+afs_GetDSlotFromList(struct dcache **adc, afs_int32 *indexp)
{
struct dcache *tdc;
- if (*indexp != NULLIDX) {
- tdc = afs_GetUnusedDSlot(*indexp);
- if (tdc) {
- osi_Assert(tdc->refCount == 1);
- ReleaseReadLock(&tdc->tlock);
- *indexp = afs_dvnextTbl[tdc->index];
- afs_dvnextTbl[tdc->index] = NULLIDX;
- return tdc;
- }
+ *adc = NULL;
+
+ if (*indexp == NULLIDX) {
+ return ENOSPC;
}
- return NULL;
+
+ tdc = afs_GetUnusedDSlot(*indexp);
+ if (tdc == NULL) {
+ return EIO;
+ }
+
+ osi_Assert(tdc->refCount == 1);
+ ReleaseReadLock(&tdc->tlock);
+ *indexp = afs_dvnextTbl[tdc->index];
+ afs_dvnextTbl[tdc->index] = NULLIDX;
+
+ *adc = tdc;
+ return 0;
}
/*!
/*
* Get an entry from the list of discarded cache elements
*/
- tdc = afs_GetDSlotFromList(&afs_discardDCList);
+ (void)afs_GetDSlotFromList(&tdc, &afs_discardDCList);
if (!tdc) {
ReleaseWriteLock(&afs_xdcache);
return -1;
if (tdc->refCount == 0) {
if ((ix = tdc->index) == NULLIDX)
osi_Panic("getdowndslot");
- /* pull the entry out of the lruq and put it on the free list */
- QRemove(&tdc->lruq);
/* write-through if modified */
if (tdc->dflags & DFEntryMod) {
AFS_GLOCK();
}
#else
+ int code;
+
+ code = afs_WriteDCache(tdc, 1);
+ if (code) {
+ /*
+ * We couldn't flush it at this time; return early because
+ * if afs_WriteDCache() failed once it is likely to
+ * continue failing for subsequent dcaches.
+ */
+ return;
+ }
tdc->dflags &= ~DFEntryMod;
- osi_Assert(afs_WriteDCache(tdc, 1) == 0);
#endif
}
- /* finally put the entry in the free list */
+ /* pull the entry out of the lruq and put it on the free list */
+ QRemove(&tdc->lruq);
afs_indexTable[ix] = NULL;
afs_indexFlags[ix] &= ~IFEverUsed;
tdc->index = NULLIDX;
} /*afs_FindDCache */
/* only call these from afs_AllocDCache() */
-static struct dcache *
-afs_AllocFreeDSlot(void)
+static int
+afs_AllocFreeDSlot(struct dcache **adc)
{
+ int code;
struct dcache *tdc;
- tdc = afs_GetDSlotFromList(&afs_freeDCList);
- if (!tdc) {
- return NULL;
+ code = afs_GetDSlotFromList(&tdc, &afs_freeDCList);
+ if (code) {
+ return code;
}
afs_indexFlags[tdc->index] &= ~IFFree;
ObtainWriteLock(&tdc->lock, 604);
afs_freeDCCount--;
- return tdc;
+ *adc = tdc;
+ return 0;
}
-static struct dcache *
-afs_AllocDiscardDSlot(afs_int32 lock)
+static int
+afs_AllocDiscardDSlot(struct dcache **adc, afs_int32 lock)
{
+ int code;
struct dcache *tdc;
afs_uint32 size = 0;
struct osi_file *file;
- tdc = afs_GetDSlotFromList(&afs_discardDCList);
- if (!tdc) {
- return NULL;
+ code = afs_GetDSlotFromList(&tdc, &afs_discardDCList);
+ if (code) {
+ return code;
}
afs_indexFlags[tdc->index] &= ~IFDiscarded;
ObtainWriteLock(&tdc->lock, 605);
afs_AdjustSize(tdc, 0);
}
- return tdc;
+ *adc = tdc;
+ return 0;
}
/*!
* Get a fresh dcache from the free or discarded list.
*
+ * \param adc Set to the new dcache on success, and NULL on error.
* \param avc Who's dcache is this going to be?
* \param chunk The position where it will be placed in.
* \param lock How are locks held.
* - avc (R if (lock & 1) set and W otherwise)
* \note It write locks the new dcache. The caller must unlock it.
*
- * \return The new dcache.
+ * \return If we're out of dslots, ENOSPC. If we encountered disk errors, EIO.
+ * On success, return 0.
*/
-static struct dcache *
-afs_AllocDCache(struct vcache *avc, afs_int32 chunk, afs_int32 lock,
- struct VenusFid *ashFid)
+static int
+afs_AllocDCache(struct dcache **adc, struct vcache *avc, afs_int32 chunk,
+ afs_int32 lock, struct VenusFid *ashFid)
{
+ int code;
struct dcache *tdc = NULL;
+ *adc = NULL;
+
/* if (lock & 2), prefer 'free' dcaches; otherwise, prefer 'discard'
- * dcaches. In either case, try both if our first choice doesn't work. */
+ * dcaches. In either case, try both if our first choice doesn't work due
+ * to ENOSPC. */
if ((lock & 2)) {
- tdc = afs_AllocFreeDSlot();
- if (!tdc) {
- tdc = afs_AllocDiscardDSlot(lock);
+ code = afs_AllocFreeDSlot(&tdc);
+ if (code == ENOSPC) {
+ code = afs_AllocDiscardDSlot(&tdc, lock);
}
} else {
- tdc = afs_AllocDiscardDSlot(lock);
- if (!tdc) {
- tdc = afs_AllocFreeDSlot();
+ code = afs_AllocDiscardDSlot(&tdc, lock);
+ if (code == ENOSPC) {
+ code = afs_AllocFreeDSlot(&tdc);
}
}
- if (!tdc) {
- return NULL;
+ if (code) {
+ return code;
}
/*
if (tdc->lruq.prev == &tdc->lruq)
osi_Panic("lruq 1");
- return tdc;
+ *adc = tdc;
+ return 0;
}
/*
if (!setLocks)
avc->f.states &= ~CDCLock;
}
- tdc = afs_AllocDCache(avc, chunk, aflags, NULL);
- if (!tdc) {
+ code = afs_AllocDCache(&tdc, avc, chunk, aflags, NULL);
+ if (code) {
ReleaseWriteLock(&afs_xdcache);
- if (afs_discardDCList == NULLIDX && afs_freeDCList == NULLIDX) {
+ if (code == ENOSPC) {
/* It looks like afs_AllocDCache failed because we don't
* have any free dslots to use. Maybe if we wait a little
* while, we'll be able to free up some slots, so try for 5
ReleaseWriteLock(&tdc->lock);
afs_PutDCache(tdc);
tdc = 0;
- ReleaseReadLock(&avc->lock);
- if (tc) {
- /* If we have a connection, we must put it back,
- * since afs_Analyze will not be called here. */
- afs_PutConn(tc, rxconn, SHARED_LOCK);
- }
+ /*
+ * Call afs_Analyze to manage the connection references
+ * and handle the error code (possibly mark servers
+ * down, etc). We are going to retry getting the
+ * dcache regardless, so we just ignore the retry hint
+ * returned by afs_Analyze on this call.
+ */
+ (void)afs_Analyze(tc, rxconn, code, &avc->f.fid, areq,
+ AFS_STATS_FS_RPCIDX_FETCHDATA, SHARED_LOCK, NULL);
+
+ ReleaseReadLock(&avc->lock);
slowPass = 1;
goto RetryGetDCache;
* \param aflags
*
*/
-void
+int
afs_dcacheInit(int afiles, int ablocks, int aDentries, int achunk, int aflags)
{
struct dcache *tdp;
afs_warn("afsd: memory cache too large for available memory.\n");
afs_warn("afsd: AFS files cannot be accessed.\n\n");
dcacheDisabled = 1;
+ return code;
} else
afs_warn("Memory cache: Allocating %d dcache entries...",
aDentries);
cacheDiskType = AFS_FCACHE_TYPE_UFS;
afs_cacheType = &afs_UfsCacheOps;
}
+ return 0;
}
/*!
ObtainWriteLock(&afs_xdcache, 716);
/* Get a fresh dcache. */
- new_dc = afs_AllocDCache(avc, 0, 0, &shadow_fid);
+ (void)afs_AllocDCache(&new_dc, avc, 0, 0, &shadow_fid);
osi_Assert(new_dc);
ObtainReadLock(&adc->mflock);