split-dcache-fixes-20050604
[openafs.git] / src / afs / afs_dcache.c
index 11f59ce..b6496ab 100644 (file)
@@ -23,14 +23,31 @@ RCSID
 #include "afs/afs_osidnlc.h"
 
 /* Forward declarations. */
-static void afs_GetDownD(int anumber, int *aneedSpace);
+static void afs_GetDownD(int anumber, int *aneedSpace, afs_int32 buckethint);
 static void afs_FreeDiscardedDCache(void);
 static void afs_DiscardDCache(struct dcache *);
 static void afs_FreeDCache(struct dcache *);
+/* For split cache */
+static afs_int32 afs_DCGetBucket(struct vcache *);
+static void afs_DCAdjustSize(struct dcache *, afs_int32, afs_int32);
+static void afs_DCMoveBucket(struct dcache *, afs_int32, afs_int32);
+static void afs_DCSizeInit(void);
+static afs_int32 afs_DCWhichBucket(afs_int32, afs_int32);
+
 
 /*
  * --------------------- Exported definitions ---------------------
  */
+/* For split cache */
+afs_int32 afs_blocksUsed_0;    /*1K blocks in cache - in theory is zero */
+afs_int32 afs_blocksUsed_1;    /*1K blocks in cache */
+afs_int32 afs_blocksUsed_2;    /*1K blocks in cache */
+afs_int32 afs_pct1 = -1;
+afs_int32 afs_pct2 = -1;
+afs_uint32 afs_tpct1 = 0;
+afs_uint32 afs_tpct2 = 0;
+afs_uint32 splitdcache = 0;
+
 afs_lock_t afs_xdcache;                /*Lock: alloc new disk cache entries */
 afs_int32 afs_freeDCList;      /*Free list for disk cache entries */
 afs_int32 afs_freeDCCount;     /*Count of elts in freeDCList */
@@ -47,6 +64,7 @@ afs_int32 *afs_dchashTbl;     /*Data cache hash table */
 afs_int32 *afs_dvnextTbl;      /*Dcache hash table links */
 afs_int32 *afs_dcnextTbl;      /*Dcache hash table links */
 struct dcache **afs_indexTable;        /*Pointers to dcache entries */
+afs_hyper_t *afs_indexTimes;   /*Dcache entry Access times */
 afs_int32 *afs_indexUnique;    /*dcache entry Fid.Unique */
 unsigned char *afs_indexFlags; /*(only one) Is there data there? */
 afs_hyper_t afs_indexCounter;  /*Fake time for marking index
@@ -118,7 +136,110 @@ struct afs_cacheOps afs_MemCacheOps = {
 int cacheDiskType;             /*Type of backing disk for cache */
 struct afs_cacheOps *afs_cacheType;
 
+static afs_int32
+afs_DCGetBucket(struct vcache *avc) 
+{
+  /* This should be replaced with some sort of user configurable function */
+  if (avc->states & CRO) {
+      return 2;
+  } else if (avc->states & CBackup) {
+      return 1;
+  } else {
+    /* RW */
+  }
+  /* main bucket */
+  return 1;
+}
+
+static void 
+afs_DCAdjustSize(struct dcache *adc, afs_int32 oldSize, afs_int32 newSize)
+{
+    afs_int32 adjustSize = newSize - oldSize;
 
+    if (!splitdcache) 
+       return;
+
+    switch (adc->bucket) 
+    {
+    case 0:
+       afs_blocksUsed_0 += adjustSize;
+       afs_stats_cmperf.cacheBucket0_Discarded += oldSize;
+       break;
+    case 1:
+       afs_blocksUsed_1 += adjustSize;
+       afs_stats_cmperf.cacheBucket1_Discarded += oldSize;
+       break;
+    case 2:
+       afs_blocksUsed_2 += adjustSize;
+       afs_stats_cmperf.cacheBucket2_Discarded += oldSize;
+       break;
+    }
+
+    return;
+}
+
+static void 
+afs_DCMoveBucket(struct dcache *adc, afs_int32 size, afs_int32 newBucket)
+{
+    if (!splitdcache) 
+       return;
+
+    switch (adc->bucket) 
+    {
+    case 0:
+       afs_blocksUsed_0 -= size;
+       break;
+    case 1:
+       afs_blocksUsed_1 -= size;
+       break;
+    case 2:
+       afs_blocksUsed_2 -= size;
+       break;
+    }
+
+    adc->bucket = newBucket;
+
+    switch (adc->bucket) 
+    {
+    case 0:
+       afs_blocksUsed_0 += size;
+       break;
+    case 1:
+       afs_blocksUsed_1 += size;
+       break;
+    case 2:
+       afs_blocksUsed_2 += size;
+       break;
+    }
+    
+    return;
+}
+
+static void 
+afs_DCSizeInit(void) 
+{
+    afs_blocksUsed_0 = afs_blocksUsed_1 = afs_blocksUsed_2 = 0;
+}
+
+static afs_int32
+afs_DCWhichBucket(afs_int32 phase, afs_int32 bucket) 
+{
+    if (!splitdcache) 
+       return 0;
+
+    afs_pct1 = afs_blocksUsed_1*100/afs_cacheBlocks;    
+    afs_pct2 = afs_blocksUsed_2*100/afs_cacheBlocks;
+
+    /* Short cut: if we don't know about it, try to kill it */
+    if (phase < 2 && afs_blocksUsed_0) 
+       return 0;
+    
+    if (afs_pct1 > afs_tpct1) 
+       return 1;
+    if (afs_pct2 > afs_tpct2)
+       return 2;
+    return 0; /* unlikely */
+}
 
 
 /*
@@ -244,7 +365,7 @@ afs_CacheTruncateDaemon(void)
                    afs_blocksUsed - afs_blocksDiscarded - cb_lowat;
                slots_needed =
                    dc_hiwat - afs_freeDCCount - afs_discardDCCount;
-               afs_GetDownD(slots_needed, &space_needed);
+               afs_GetDownD(slots_needed, &space_needed, 0);
                if ((space_needed <= 0) && (slots_needed <= 0)) {
                    break;
                }
@@ -339,6 +460,7 @@ afs_AdjustSize(register struct dcache *adc, register afs_int32 newSize)
     if (!newSize)
        adc->validPos = 0;
     newSize = ((newSize + afs_fsfragsize) ^ afs_fsfragsize) >> 10;     /* round up */
+    afs_DCAdjustSize(adc, oldSize, newSize);
     if (newSize > oldSize) {
        /* We're growing the file, wakeup the daemon */
        afs_MaybeWakeupTruncateDaemon();
@@ -375,7 +497,7 @@ afs_AdjustSize(register struct dcache *adc, register afs_int32 newSize)
 
 #define        MAXATONCE   16          /* max we can obtain at once */
 static void
-afs_GetDownD(int anumber, int *aneedSpace)
+afs_GetDownD(int anumber, int *aneedSpace, afs_int32 buckethint)
 {
 
     struct dcache *tdc;
@@ -391,6 +513,7 @@ afs_GetDownD(int anumber, int *aneedSpace)
     afs_hyper_t maxVictimTime; /* youngest (largest LRU time) victim */
     afs_uint32 maxVictimPtr;   /* where it is */
     int discard;
+    int curbucket;
 
     AFS_STATCNT(afs_GetDownD);
     if (CheckLock(&afs_xdcache) != -1)
@@ -407,12 +530,20 @@ afs_GetDownD(int anumber, int *aneedSpace)
     if (anumber > MAXATONCE)
        anumber = MAXATONCE;    /* all we can do */
 
+    /* rewrite so phases include a better eligiblity for gc test*/
     /*
      * The phase variable manages reclaims.  Set to 0, the first pass,
-     * we don't reclaim active entries.  Set to 1, we reclaim even active
-     * ones.
+     * we don't reclaim active entries, or other than target bucket.  
+     * Set to 1, we reclaim even active ones in target bucket.
+     * Set to 2, we reclaim any inactive one.
+     * Set to 3, we reclaim even active ones.
      */
-    phase = 0;
+    if (splitdcache) {
+       phase = 0;
+    } else {
+       phase = 4;
+    }
+
     for (i = 0; i < afs_cacheFiles; i++)
        /* turn off all flags */
        afs_indexFlags[i] &= ~IFFlag;
@@ -421,17 +552,24 @@ afs_GetDownD(int anumber, int *aneedSpace)
        /* find oldest entries for reclamation */
        maxVictimPtr = victimPtr = 0;
        hzero(maxVictimTime);
+       curbucket = afs_DCWhichBucket(phase, buckethint);
        /* select victims from access time array */
        for (i = 0; i < afs_cacheFiles; i++) {
            if (afs_indexFlags[i] & (IFDataMod | IFFree | IFDiscarded)) {
                /* skip if dirty or already free */
                continue;
            }
-           if (tdc) {
-               if (tdc->refCount != 0)         /* Referenced; can't use it! */
-                   continue;
-                hset(tdc->atime, vtime);
+           tdc = afs_indexTable[i];
+           if (tdc && (curbucket != tdc->bucket) && (phase < 4))
+           {
+               /* Wrong bucket; can't use it! */
+               continue;
+           }
+           if (tdc && (tdc->refCount != 0)) {
+               /* Referenced; can't use it! */
+               continue;
            }
+           hset(vtime, afs_indexTimes[i]);
 
            /* if we've already looked at this one, skip it */
            if (afs_indexFlags[i] & IFFlag)
@@ -508,12 +646,12 @@ afs_GetDownD(int anumber, int *aneedSpace)
                if (tvc) {
                    tchunkoffset = AFS_CHUNKTOBASE(tdc->f.chunk);
                    chunkFlags = afs_indexFlags[tdc->index];
-                   if (phase == 0 && osi_Active(tvc))
-                       skip = 1;
-                   if (phase > 0 && osi_Active(tvc)
-                       && (tvc->states & CDCLock)
-                       && (chunkFlags & IFAnyPages))
-                       skip = 1;
+                   if (((phase & 1) == 0) && osi_Active(tvc))
+                        skip = 1;
+                   if (((phase & 1) == 1) && osi_Active(tvc)
+                        && (tvc->states & CDCLock)
+                        && (chunkFlags & IFAnyPages))
+                        skip = 1;
                    if (chunkFlags & IFDataMod)
                        skip = 1;
                    afs_Trace4(afs_iclSetp, CM_TRACE_GETDOWND,
@@ -623,9 +761,7 @@ afs_GetDownD(int anumber, int *aneedSpace)
                               ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, 3,
                               ICL_TYPE_INT32, tdc->index, ICL_TYPE_OFFSET,
                               ICL_HANDLE_OFFSET(tchunkoffset));
-#ifndef        AFS_DEC_ENV
                    AFS_STATCNT(afs_gget);
-#endif
                    afs_HashOutDCache(tdc);
                    if (tdc->f.chunkBytes != 0) {
                        discard = 1;
@@ -647,18 +783,18 @@ afs_GetDownD(int anumber, int *aneedSpace)
            afs_PutDCache(tdc);
        }
 
-       if (phase == 0) {
+       if (phase < 5) {
            /* Phase is 0 and no one was found, so try phase 1 (ignore
             * osi_Active flag) */
            if (j == 0) {
-               phase = 1;
+               phase++;
                for (i = 0; i < afs_cacheFiles; i++)
                    /* turn off all flags */
                    afs_indexFlags[i] &= ~IFFlag;
            }
        } else {
-           /* found no one in phase 1, we're hosed */
-           if (victimPtr == 0)
+           /* found no one in phases 0-5, we're hosed */
+           if (j == 0)
                break;
        }
     }                          /* big while loop */
@@ -680,9 +816,7 @@ afs_HashOutDCache(struct dcache *adc)
 {
     int i, us;
 
-#ifndef        AFS_DEC_ENV
     AFS_STATCNT(afs_glink);
-#endif
     /* we know this guy's in the LRUQ.  We'll move dude into DCQ below */
     DZap(adc);
     /* if this guy is in the hash table, pull him out */
@@ -918,6 +1052,8 @@ afs_FreeDiscardedDCache(void)
     afs_CFileTruncate(tfile, 0);
     afs_CFileClose(tfile);
     afs_AdjustSize(tdc, 0);
+    tdc->f.states &= ~(DRO|DBackup|DRW);
+    afs_DCMoveBucket(tdc, 0, 0);
 
     /*
      * Free the element we just truncated
@@ -1022,17 +1158,6 @@ afs_GetDownDSlot(int anumber)
 #endif
            }
 
-           tdc->stamp = 0;
-#ifdef IHINT
-           if (tdc->ihint) {
-               struct osi_file *f = (struct osi_file *)tdc->ihint;
-               tdc->ihint = 0;
-               afs_UFSClose(f);
-               nihints--;
-           }
-#endif /* IHINT */
-
-
            /* finally put the entry in the free list */
            afs_indexTable[ix] = NULL;
            afs_indexFlags[ix] &= ~IFEverUsed;
@@ -1216,12 +1341,13 @@ afs_FindDCache(register struct vcache *avc, afs_size_t abyte)
                break;          /* leaving refCount high for caller */
            }
            afs_PutDCache(tdc);
+           tdc = NULL;
        }
        index = afs_dcnextTbl[index];
     }
     MReleaseWriteLock(&afs_xdcache);
     if (index != NULLIDX) {
-       hset(tdc->atime, afs_indexCounter);
+       hset(afs_indexTimes[tdc->index], afs_indexCounter);
        hadd32(afs_indexCounter, 1);
        return tdc;
     } else
@@ -1299,8 +1425,9 @@ afs_UFSCacheStoreProc(register struct rx_call *acall, struct osi_file *afile,
        (*abytesXferredP) += code;
 #endif /* AFS_NOSTATS */
        if (code != got) {
+           code = rx_Error(acall);
            osi_FreeLargeSpace(tbuffer);
-           return -33;
+           return code ? code : -33;
        }
        alen -= got;
        /*
@@ -1484,14 +1611,8 @@ void
 updateV2DC(int lockVc, struct vcache *v, struct dcache *d, int src)
 {
     if (!lockVc || 0 == NBObtainWriteLock(&v->lock, src)) {
-       if (hsame(v->m.DataVersion, d->f.versionNo) && v->callback) {
-           v->quick.dc = d;
-           v->quick.stamp = d->stamp = MakeStamp();
-           v->quick.minLoc = AFS_CHUNKTOBASE(d->f.chunk);
-           /* Don't think I need these next two lines forever */
-           v->quick.len = d->f.chunkBytes;
-           v->h1.dchint = d;
-       }
+       if (hsame(v->m.DataVersion, d->f.versionNo) && v->callback)
+           v->dchint = d;
        if (lockVc)
            ReleaseWriteLock(&v->lock);
     }
@@ -1583,7 +1704,7 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
     shortcut = 0;
 
     /* check hints first! (might could use bcmp or some such...) */
-    if ((tdc = avc->h1.dchint)) {
+    if ((tdc = avc->dchint)) {
        int dcLocked;
 
        /*
@@ -1708,7 +1829,8 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
                while (1) {
                    if (!setLocks)
                        avc->states |= CDCLock;
-                   afs_GetDownD(5, (int *)0);  /* just need slots */
+                   /* just need slots */
+                   afs_GetDownD(5, (int *)0, afs_DCGetBucket(avc));
                    if (!setLocks)
                        avc->states &= ~CDCLock;
                    if (afs_discardDCList != NULLIDX
@@ -1749,6 +1871,8 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
                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 (aflags & 2) {
@@ -1773,6 +1897,13 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
             */
            afs_indexFlags[tdc->index] &= ~(IFDirtyPages | IFAnyPages);
            tdc->f.fid = avc->fid;
+           if (avc->states & CRO) 
+               tdc->f.states = DRO;
+           else if (avc->states & CBackup) 
+               tdc->f.states = DBackup;
+           else 
+               tdc->f.states = DRW;
+           afs_DCMoveBucket(tdc, 0, afs_DCGetBucket(avc));
            afs_indexUnique[tdc->index] = tdc->f.fid.Fid.Unique;
            hones(tdc->f.versionNo);    /* invalid value */
            tdc->f.chunk = chunk;
@@ -1792,7 +1923,6 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
            afs_dvhashTbl[i] = tdc->index;
            tdc->dflags = DFEntryMod;
            tdc->mflags = 0;
-           tdc->f.states = 0;
            afs_MaybeWakeupTruncateDaemon();
            MReleaseWriteLock(&afs_xdcache);
            ConvertWToSLock(&tdc->lock);
@@ -1854,7 +1984,7 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
 #endif /* AFS_SGI_ENV */
        if (AFS_CHUNKTOBASE(chunk) + adjustsize >= avc->m.Length &&
 #else /* defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV) */
-#if    defined(AFS_SUN_ENV)  || defined(AFS_OSF_ENV)
+#if    defined(AFS_SUN5_ENV)  || defined(AFS_OSF_ENV)
        if ((doAdjustSize || (AFS_CHUNKTOBASE(chunk) >= avc->m.Length)) &&
 #else
        if (AFS_CHUNKTOBASE(chunk) >= avc->m.Length &&
@@ -1885,7 +2015,7 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
     if (aflags & 2) {
        /* don't need data, just a unique dcache entry */
        ObtainWriteLock(&afs_xdcache, 608);
-       hset(tdc->atime, afs_indexCounter);
+       hset(afs_indexTimes[tdc->index], afs_indexCounter);
        hadd32(afs_indexCounter, 1);
        ReleaseWriteLock(&afs_xdcache);
 
@@ -2037,20 +2167,7 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
         * fetch the whole file.
         */
        DZap(tdc);      /* pages in cache may be old */
-#ifdef  IHINT
-       if (file = tdc->ihint) {
-           if (tdc->f.inode == file->inum)
-               usedihint++;
-           else {
-               tdc->ihint = 0;
-               afs_UFSClose(file);
-               file = 0;
-               nihints--;
-               file = osi_UFSOpen(tdc->f.inode);
-           }
-       } else
-#endif /* IHINT */
-           file = afs_CFileOpen(tdc->f.inode);
+       file = afs_CFileOpen(tdc->f.inode);
        afs_RemoveVCB(&avc->fid);
        tdc->f.states |= DWriting;
        tdc->dflags |= DFFetching;
@@ -2415,6 +2532,8 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
            if (vType(avc) == VDIR) {
                DZap(tdc);
            }
+           tdc->f.states &= ~(DRO|DBackup|DRW);
+           afs_DCMoveBucket(tdc, 0, 0);
            ReleaseWriteLock(&tdc->lock);
            afs_PutDCache(tdc);
            ObtainWriteLock(&afs_xcbhash, 454);
@@ -2428,6 +2547,8 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
             * avc->lock(W); assert(!setLocks || slowPass)
             */
            osi_Assert(!setLocks || slowPass);
+           tdc->f.states &= ~(DRO|DBackup|DRW);
+           afs_DCMoveBucket(tdc, 0, 0);
            tdc = NULL;
            goto done;
        }
@@ -2478,7 +2599,7 @@ afs_GetDCache(register struct vcache *avc, afs_size_t abyte,
 
     if (tdc) {
        MObtainWriteLock(&afs_xdcache, 602);
-       hset(tdc->atime, afs_indexCounter);
+       hset(afs_indexTimes[tdc->index], afs_indexCounter);
        hadd32(afs_indexCounter, 1);
        MReleaseWriteLock(&afs_xdcache);
 
@@ -2810,7 +2931,6 @@ afs_UFSGetDSlot(register afs_int32 aslot, register struct dcache *tmpdc)
     } else {
        tdc = tmpdc;
        tdc->f.states = 0;
-       tdc->ihint = 0;
     }
 
     /*
@@ -2838,6 +2958,18 @@ afs_UFSGetDSlot(register afs_int32 aslot, register struct dcache *tmpdc)
 #endif
        lasterrtime = osi_Time();
        afs_indexUnique[aslot] = tdc->f.fid.Fid.Unique;
+       tdc->f.states &= ~(DRO|DBackup|DRW);
+       afs_DCMoveBucket(tdc, 0, 0);
+    } else {
+       if (&tdc->f != 0) {
+           if (tdc->f.states & DRO) {
+               afs_DCMoveBucket(tdc, 0, 2);
+           } else if (tdc->f.states & DBackup) {
+               afs_DCMoveBucket(tdc, 0, 1);
+           } else {
+               afs_DCMoveBucket(tdc, 0, 1); 
+           }
+       } 
     }
     tdc->refCount = 1;
     tdc->index = aslot;
@@ -3005,7 +3137,7 @@ afs_InitCacheFile(char *afile, ino_t ainode)
     ObtainWriteLock(&tdc->lock, 621);
     MObtainWriteLock(&afs_xdcache, 622);
     if (afile) {
-       code = gop_lookupname(afile, AFS_UIOSYS, 0, NULL, &filevp);
+       code = gop_lookupname(afile, AFS_UIOSYS, 0, &filevp);
        if (code) {
            ReleaseWriteLock(&afs_xdcache);
            ReleaseWriteLock(&tdc->lock);
@@ -3022,11 +3154,7 @@ afs_InitCacheFile(char *afile, ino_t ainode)
        dput(filevp);
 #else
        tdc->f.inode = afs_vnodeToInumber(filevp);
-#ifdef AFS_DEC_ENV
-       grele(filevp);
-#else
        AFS_RELE(filevp);
-#endif
 #endif /* AFS_LINUX22_ENV */
     } else {
        tdc->f.inode = ainode;
@@ -3065,6 +3193,8 @@ afs_InitCacheFile(char *afile, ino_t ainode)
        tdc->f.fid.Fid.Volume = 0;      /* not in the hash table */
        if (tstat.size != 0)
            osi_UFSTruncate(tfile, 0);
+       tdc->f.states &= ~(DRO|DBackup|DRW);
+       afs_DCMoveBucket(tdc, 0, 0);
        /* put entry in free cache slot list */
        afs_dvnextTbl[tdc->index] = afs_freeDCList;
        afs_freeDCList = index;
@@ -3091,7 +3221,7 @@ afs_InitCacheFile(char *afile, ino_t ainode)
         * Initialize index times to file's mod times; init indexCounter
         * to max thereof
         */
-       hset32(tdc->atime, tstat.atime);
+       hset32(afs_indexTimes[index], tstat.atime);
        if (hgetlo(afs_indexCounter) < tstat.atime) {
            hset32(afs_indexCounter, tstat.atime);
        }
@@ -3196,6 +3326,9 @@ afs_dcacheInit(int afiles, int ablocks, int aDentries, int achunk, int aflags)
     afs_indexTable = (struct dcache **)
        afs_osi_Alloc(sizeof(struct dcache *) * afiles);
     memset((char *)afs_indexTable, 0, sizeof(struct dcache *) * afiles);
+    afs_indexTimes =
+       (afs_hyper_t *) afs_osi_Alloc(afiles * sizeof(afs_hyper_t));
+    memset((char *)afs_indexTimes, 0, afiles * sizeof(afs_hyper_t));
     afs_indexUnique =
        (afs_int32 *) afs_osi_Alloc(afiles * sizeof(afs_uint32));
     memset((char *)afs_indexUnique, 0, afiles * sizeof(afs_uint32));
@@ -3208,6 +3341,7 @@ afs_dcacheInit(int afiles, int ablocks, int aDentries, int achunk, int aflags)
     memset((char *)tdp, 0, aDentries * sizeof(struct dcache));
 #ifdef KERNEL_HAVE_PIN
     pin((char *)afs_indexTable, sizeof(struct dcache *) * afiles);     /* XXX */
+    pin((char *)afs_indexTimes, sizeof(afs_hyper_t) * afiles); /* XXX */
     pin((char *)afs_indexFlags, sizeof(char) * afiles);        /* XXX */
     pin((char *)afs_indexUnique, sizeof(afs_int32) * afiles);  /* XXX */
     pin((char *)tdp, aDentries * sizeof(struct dcache));       /* XXX */
@@ -3220,8 +3354,14 @@ afs_dcacheInit(int afiles, int ablocks, int aDentries, int achunk, int aflags)
     afs_freeDSList = &tdp[0];
     for (i = 0; i < aDentries - 1; i++) {
        tdp[i].lruq.next = (struct afs_q *)(&tdp[i + 1]);
+        RWLOCK_INIT(&tdp[i].lock, "dcache lock");
+        RWLOCK_INIT(&tdp[i].tlock, "dcache tlock");
+        RWLOCK_INIT(&tdp[i].mflock, "dcache flock");
     }
     tdp[aDentries - 1].lruq.next = (struct afs_q *)0;
+    RWLOCK_INIT(&tdp[aDentries - 1].lock, "dcache lock");
+    RWLOCK_INIT(&tdp[aDentries - 1].tlock, "dcache tlock");
+    RWLOCK_INIT(&tdp[aDentries - 1].mflock, "dcache flock");
 
     afs_stats_cmperf.cacheBlocksOrig = afs_stats_cmperf.cacheBlocksTotal =
        afs_cacheBlocks = ablocks;
@@ -3229,6 +3369,10 @@ afs_dcacheInit(int afiles, int ablocks, int aDentries, int achunk, int aflags)
 
     afs_dcentries = aDentries;
     afs_blocksUsed = 0;
+    afs_stats_cmperf.cacheBucket0_Discarded = 
+       afs_stats_cmperf.cacheBucket1_Discarded = 
+       afs_stats_cmperf.cacheBucket2_Discarded = 0;
+    afs_DCSizeInit();
     QInit(&afs_DLRU);
 }
 
@@ -3244,6 +3388,7 @@ shutdown_dcache(void)
     afs_osi_Free(afs_dvnextTbl, afs_cacheFiles * sizeof(afs_int32));
     afs_osi_Free(afs_dcnextTbl, afs_cacheFiles * sizeof(afs_int32));
     afs_osi_Free(afs_indexTable, afs_cacheFiles * sizeof(struct dcache *));
+    afs_osi_Free(afs_indexTimes, afs_cacheFiles * sizeof(afs_hyper_t));
     afs_osi_Free(afs_indexUnique, afs_cacheFiles * sizeof(afs_uint32));
     afs_osi_Free(afs_indexFlags, afs_cacheFiles * sizeof(u_char));
     afs_osi_Free(afs_Initial_freeDSList,
@@ -3252,6 +3397,7 @@ shutdown_dcache(void)
     unpin((char *)afs_dcnextTbl, afs_cacheFiles * sizeof(afs_int32));
     unpin((char *)afs_dvnextTbl, afs_cacheFiles * sizeof(afs_int32));
     unpin((char *)afs_indexTable, afs_cacheFiles * sizeof(struct dcache *));
+    unpin((char *)afs_indexTimes, afs_cacheFiles * sizeof(afs_hyper_t));
     unpin((char *)afs_indexUnique, afs_cacheFiles * sizeof(afs_uint32));
     unpin((u_char *) afs_indexFlags, afs_cacheFiles * sizeof(u_char));
     unpin(afs_Initial_freeDSList, afs_dcentries * sizeof(struct dcache));
@@ -3267,6 +3413,9 @@ shutdown_dcache(void)
     afs_osi_Free(afs_dchashTbl, afs_dhashsize * sizeof(afs_int32));
 
     afs_blocksUsed = afs_dcentries = 0;
+    afs_stats_cmperf.cacheBucket0_Discarded = 
+       afs_stats_cmperf.cacheBucket1_Discarded = 
+       afs_stats_cmperf.cacheBucket2_Discarded = 0;
     hzero(afs_indexCounter);
 
     afs_freeDCCount = 0;