afs: avoid afs_GetDownDSlot panic on afs_WriteDCache failure
[openafs.git] / src / afs / afs_dcache.c
index 3c437bd..15e63ff 100644 (file)
@@ -1282,8 +1282,6 @@ afs_GetDownDSlot(int anumber)
        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) {
@@ -1305,12 +1303,23 @@ afs_GetDownDSlot(int anumber)
                    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;
@@ -2489,13 +2498,18 @@ afs_GetDCache(struct vcache *avc, afs_size_t abyte,
                        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;
@@ -3319,7 +3333,7 @@ afs_InitCacheFile(char *afile, ino_t ainode)
  * \param aflags
  *
  */
-void
+int
 afs_dcacheInit(int afiles, int ablocks, int aDentries, int achunk, int aflags)
 {
     struct dcache *tdp;
@@ -3446,6 +3460,7 @@ afs_dcacheInit(int afiles, int ablocks, int aDentries, int achunk, int aflags)
            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);
@@ -3453,6 +3468,7 @@ afs_dcacheInit(int afiles, int ablocks, int aDentries, int achunk, int aflags)
        cacheDiskType = AFS_FCACHE_TYPE_UFS;
        afs_cacheType = &afs_UfsCacheOps;
     }
+    return 0;
 }
 
 /*!