afs: Traverse discard/free dslot list if errors
authorAndrew Deason <adeason@sinenomine.net>
Thu, 1 Nov 2012 18:41:06 +0000 (13:41 -0500)
committerDerrick Brashear <shadow@your-file-system.com>
Tue, 13 Nov 2012 18:38:01 +0000 (10:38 -0800)
Currently, when we pull a dslot off of the discard or free list, we
just try to get the first entry from the list, and panic if we cannot
get it. Instead, traverse through the whole list, trying to find an
entry we can successfully get. This introduces the helper function
afs_GetDSlotFromList to do this traversal.

This does not yet address the case where we cannot get any entry on
the relevant list.

Change-Id: Iedbcffcbeb5dda61fde8e1d526e793f68c3200b3
Reviewed-on: http://gerrit.openafs.org/8376
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@your-file-system.com>

src/afs/afs_dcache.c

index 388a413..a932553 100644 (file)
@@ -1066,6 +1066,34 @@ afs_DiscardDCache(struct dcache *adc)
 
 }                              /*afs_DiscardDCache */
 
+/**
+ * Get a dcache entry from the discard or free list
+ *
+ * @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.
+ *
+ * @pre afs_xdcache is write-locked
+ */
+static struct dcache *
+afs_GetDSlotFromList(afs_int32 *indexp)
+{
+    struct dcache *tdc;
+
+    for ( ; *indexp != NULLIDX; indexp = &afs_dvnextTbl[*indexp]) {
+       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;
+       }
+    }
+    return NULL;
+}
+
 /*!
  * Free the next element on the list of discarded cache elements.
  */
@@ -1087,13 +1115,9 @@ afs_FreeDiscardedDCache(void)
     /*
      * Get an entry from the list of discarded cache elements
      */
-    tdc = afs_GetUnusedDSlot(afs_discardDCList);
+    tdc = afs_GetDSlotFromList(&afs_discardDCList);
     osi_Assert(tdc);
-    osi_Assert(tdc->refCount == 1);
-    ReleaseReadLock(&tdc->tlock);
 
-    afs_discardDCList = afs_dvnextTbl[tdc->index];
-    afs_dvnextTbl[tdc->index] = NULLIDX;
     afs_discardDCCount--;
     size = ((tdc->f.chunkBytes + afs_fsfragsize) ^ afs_fsfragsize) >> 10;      /* round up */
     afs_blocksDiscarded -= size;
@@ -1516,22 +1540,16 @@ afs_AllocDCache(struct vcache *avc, afs_int32 chunk, afs_int32 lock,
     if (afs_discardDCList == NULLIDX
        || ((lock & 2) && afs_freeDCList != NULLIDX)) {
 
-       afs_indexFlags[afs_freeDCList] &= ~IFFree;
-       tdc = afs_GetUnusedDSlot(afs_freeDCList);
+       tdc = afs_GetDSlotFromList(&afs_freeDCList);
        osi_Assert(tdc);
-       osi_Assert(tdc->refCount == 1);
-       ReleaseReadLock(&tdc->tlock);
+       afs_indexFlags[tdc->index] &= ~IFFree;
        ObtainWriteLock(&tdc->lock, 604);
-       afs_freeDCList = afs_dvnextTbl[tdc->index];
        afs_freeDCCount--;
     } else {
-       afs_indexFlags[afs_discardDCList] &= ~IFDiscarded;
-       tdc = afs_GetUnusedDSlot(afs_discardDCList);
+       tdc = afs_GetDSlotFromList(&afs_discardDCList);
        osi_Assert(tdc);
-       osi_Assert(tdc->refCount == 1);
-       ReleaseReadLock(&tdc->tlock);
+       afs_indexFlags[tdc->index] &= ~IFDiscarded;
        ObtainWriteLock(&tdc->lock, 605);
-       afs_discardDCList = afs_dvnextTbl[tdc->index];
        afs_discardDCCount--;
        size =
            ((tdc->f.chunkBytes +