afs: Handle easy GetValidDSlot errors
[openafs.git] / src / afs / afs_dcache.c
index 6dafb01..388a413 100644 (file)
@@ -1087,7 +1087,8 @@ afs_FreeDiscardedDCache(void)
     /*
      * Get an entry from the list of discarded cache elements
      */
-    tdc = afs_GetNewDSlot(afs_discardDCList);
+    tdc = afs_GetUnusedDSlot(afs_discardDCList);
+    osi_Assert(tdc);
     osi_Assert(tdc->refCount == 1);
     ReleaseReadLock(&tdc->tlock);
 
@@ -1314,7 +1315,12 @@ afs_TryToSmush(struct vcache *avc, afs_ucred_t *acred, int sync)
        if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) {
            int releaseTlock = 1;
            tdc = afs_GetValidDSlot(index);
-           if (!tdc) osi_Panic("afs_TryToSmush tdc");
+           if (!tdc) {
+               /* afs_TryToSmush is best-effort; we may not actually discard
+                * everything, so failure to discard a dcache due to an i/o
+                * error is okay. */
+               continue;
+           }
            if (!FidCmp(&tdc->f.fid, &avc->f.fid)) {
                if (sync) {
                    if ((afs_indexFlags[index] & IFDataMod) == 0
@@ -1456,17 +1462,21 @@ afs_FindDCache(struct vcache *avc, afs_size_t abyte)
      */
     i = DCHash(&avc->f.fid, chunk);
     ObtainWriteLock(&afs_xdcache, 278);
-    for (index = afs_dchashTbl[i]; index != NULLIDX;) {
+    for (index = afs_dchashTbl[i]; index != NULLIDX; index = afs_dcnextTbl[index]) {
        if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) {
            tdc = afs_GetValidDSlot(index);
-           if (!tdc) osi_Panic("afs_FindDCache tdc");
+           if (!tdc) {
+               /* afs_FindDCache is best-effort; we may not find the given
+                * file/offset, so if we cannot find the given dcache due to
+                * i/o errors, that is okay. */
+               continue;
+           }
            ReleaseReadLock(&tdc->tlock);
            if (!FidCmp(&tdc->f.fid, &avc->f.fid) && chunk == tdc->f.chunk) {
                break;          /* leaving refCount high for caller */
            }
            afs_PutDCache(tdc);
        }
-       index = afs_dcnextTbl[index];
     }
     if (index != NULLIDX) {
        hset(afs_indexTimes[tdc->index], afs_indexCounter);
@@ -1507,7 +1517,8 @@ afs_AllocDCache(struct vcache *avc, afs_int32 chunk, afs_int32 lock,
        || ((lock & 2) && afs_freeDCList != NULLIDX)) {
 
        afs_indexFlags[afs_freeDCList] &= ~IFFree;
-       tdc = afs_GetNewDSlot(afs_freeDCList);
+       tdc = afs_GetUnusedDSlot(afs_freeDCList);
+       osi_Assert(tdc);
        osi_Assert(tdc->refCount == 1);
        ReleaseReadLock(&tdc->tlock);
        ObtainWriteLock(&tdc->lock, 604);
@@ -1515,7 +1526,8 @@ afs_AllocDCache(struct vcache *avc, afs_int32 chunk, afs_int32 lock,
        afs_freeDCCount--;
     } else {
        afs_indexFlags[afs_discardDCList] &= ~IFDiscarded;
-       tdc = afs_GetNewDSlot(afs_discardDCList);
+       tdc = afs_GetUnusedDSlot(afs_discardDCList);
+       osi_Assert(tdc);
        osi_Assert(tdc->refCount == 1);
        ReleaseReadLock(&tdc->tlock);
        ObtainWriteLock(&tdc->lock, 605);
@@ -1755,6 +1767,7 @@ afs_GetDCache(struct vcache *avc, afs_size_t abyte,
      */
 
     if (!tdc) {                        /* If the hint wasn't the right dcache entry */
+       int dslot_error = 0;
        /*
         * Hash on the [fid, chunk] and get the corresponding dcache index
         * after write-locking the dcache.
@@ -1772,12 +1785,16 @@ afs_GetDCache(struct vcache *avc, afs_size_t abyte,
 
        ObtainWriteLock(&afs_xdcache, 280);
        us = NULLIDX;
-       for (index = afs_dchashTbl[i]; index != NULLIDX;) {
+       for (index = afs_dchashTbl[i]; index != NULLIDX; us = index, index = afs_dcnextTbl[index]) {
            if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) {
                tdc = afs_GetValidDSlot(index);
                if (!tdc) {
-                   ReleaseWriteLock(&afs_xdcache);
-                   goto done;
+                   /* we got an i/o error when trying to get the given dslot,
+                    * but do not bail out just yet; it is possible the dcache
+                    * we're looking for is elsewhere, so it doesn't matter if
+                    * we can't load this one. */
+                   dslot_error = 1;
+                   continue;
                }
                ReleaseReadLock(&tdc->tlock);
                /*
@@ -1800,8 +1817,6 @@ afs_GetDCache(struct vcache *avc, afs_size_t abyte,
                afs_PutDCache(tdc);
                tdc = 0;
            }
-           us = index;
-           index = afs_dcnextTbl[index];
        }
 
        /*
@@ -1817,6 +1832,16 @@ afs_GetDCache(struct vcache *avc, afs_size_t abyte,
            afs_Trace2(afs_iclSetp, CM_TRACE_GETDCACHE1, ICL_TYPE_POINTER,
                       avc, ICL_TYPE_INT32, chunk);
 
+           if (dslot_error) {
+               /* We couldn't find the dcache we want, but we hit some i/o
+                * errors when trying to find it, so we're not sure if the
+                * dcache we want is in the cache or not. Error out, so we
+                * don't try to possibly create 2 separate dcaches for the
+                * same exact data. */
+               ReleaseWriteLock(&afs_xdcache);
+               goto done;
+           }
+
            /* Make sure there is a free dcache entry for us to use */
            if (afs_discardDCList == NULLIDX && afs_freeDCList == NULLIDX) {
                while (1) {
@@ -2605,7 +2630,7 @@ afs_WriteThroughDSlots(void)
  */
 
 struct dcache *
-afs_MemGetDSlot(afs_int32 aslot, int needvalid)
+afs_MemGetDSlot(afs_int32 aslot, int indexvalid, int datavalid)
 {
     struct dcache *tdc;
     int existing = 0;
@@ -2626,10 +2651,10 @@ afs_MemGetDSlot(afs_int32 aslot, int needvalid)
        return tdc;
     }
 
-    /* if 'needvalid' is true, the slot must already exist and be populated
+    /* if 'indexvalid' is true, the slot must already exist and be populated
      * somewhere. for memcache, the only place that dcache entries exist is
      * in memory, so if we did not find it above, something is very wrong. */
-    osi_Assert(!needvalid);
+    osi_Assert(!indexvalid);
 
     if (!afs_freeDSList)
        afs_GetDownDSlot(4);
@@ -2690,13 +2715,20 @@ unsigned int last_error = 0, lasterrtime = 0;
  *
  * Parameters:
  *     aslot : Dcache slot to look at.
- *      needvalid : Whether the specified slot should already exist
+ *      indexvalid : 1 if we know the slot we're giving is valid, and thus
+ *                   reading the dcache from the disk index should succeed. 0
+ *                   if we are initializing a new dcache, and so reading from
+ *                   the disk index may fail.
+ *      datavalid : 0 if we are loading a dcache entry from the free or
+ *                  discard list, so we know the data in the given dcache is
+ *                  not valid. 1 if we are loading a known used dcache, so the
+ *                  data in the dcache must be valid.
  *
  * Environment:
  *     afs_xdcache lock write-locked.
  */
 struct dcache *
-afs_UFSGetDSlot(afs_int32 aslot, int needvalid)
+afs_UFSGetDSlot(afs_int32 aslot, int indexvalid, int datavalid)
 {
     afs_int32 code;
     struct dcache *tdc;
@@ -2759,7 +2791,7 @@ afs_UFSGetDSlot(afs_int32 aslot, int needvalid)
        last_error = code;
 #endif
        lasterrtime = osi_Time();
-       if (needvalid) {
+       if (indexvalid) {
            struct osi_stat tstat;
            if (afs_osi_Stat(afs_cacheInodep, &tstat)) {
                tstat.size = -1;
@@ -2779,19 +2811,19 @@ afs_UFSGetDSlot(afs_int32 aslot, int needvalid)
     }
     if (!afs_CellNumValid(tdc->f.fid.Cell)) {
        entryok = 0;
-       if (needvalid) {
+       if (datavalid) {
            osi_Panic("afs: needed valid dcache but index %d off %d has "
                      "invalid cell num %d\n",
                      (int)aslot, off, (int)tdc->f.fid.Cell);
        }
     }
 
-    if (needvalid && tdc->f.fid.Fid.Volume == 0) {
+    if (datavalid && tdc->f.fid.Fid.Volume == 0) {
        osi_Panic("afs: invalid zero-volume dcache entry at slot %d off %d",
                  (int)aslot, off);
     }
 
-    if (!entryok) {
+    if (!entryok || !datavalid) {
        tdc->f.fid.Cell = 0;
        tdc->f.fid.Fid.Volume = 0;
        tdc->f.chunk = -1;