windows-scache-20080308
[openafs.git] / src / WINNT / afsd / cm_scache.c
index 9d7bdbc..403776e 100644 (file)
@@ -164,6 +164,7 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
                     | CM_SCACHEFLAG_EACCESS);
     scp->serverModTime = 0;
     scp->dataVersion = 0;
+    scp->bufDataVersionLow = 0;
     scp->bulkStatProgress = hzero;
     scp->waitCount = 0;
     scp->waitQueueT = NULL;
@@ -178,6 +179,7 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
     scp->fid.volume = 0;
     scp->fid.unique = 0;
     scp->fid.cell = 0;
+    scp->fid.hash = 0;
 
     /* remove from dnlc */
     cm_dnlcPurgedp(scp);
@@ -316,7 +318,7 @@ cm_scache_t *cm_GetNewSCache(void)
                 "invalid cm_scache_t address");
     memset(scp, 0, sizeof(cm_scache_t));
     scp->magic = CM_SCACHE_MAGIC;
-    lock_InitializeMutex(&scp->mx, "cm_scache_t mutex");
+    lock_InitializeRWLock(&scp->rw, "cm_scache_t rw");
     lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
 #ifdef USE_BPLUS
     lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock");
@@ -335,10 +337,21 @@ cm_scache_t *cm_GetNewSCache(void)
     return scp;
 }       
 
+void cm_SetFid(cm_fid_t *fidp, afs_uint32 cell, afs_uint32 volume, afs_uint32 vnode, afs_uint32 unique)
+{
+    fidp->cell = cell;
+    fidp->volume = volume;
+    fidp->vnode = vnode;
+    fidp->unique = unique;
+    fidp->hash = ((cell & 0xF) << 28) | ((volume & 0x3F) << 22) | ((vnode & 0x7FF) << 11) | (unique & 0x7FF);
+}
+
 /* like strcmp, only for fids */
-int cm_FidCmp(cm_fid_t *ap, cm_fid_t *bp)
+__inline int cm_FidCmp(cm_fid_t *ap, cm_fid_t *bp)
 {
-    if (ap->vnode != bp->vnode) 
+    if (ap->hash != bp->hash)
+        return 1;
+    if (ap->vnode != bp->vnode)
         return 1;
     if (ap->volume != bp->volume) 
         return 1;
@@ -361,7 +374,7 @@ void cm_fakeSCacheInit(int newFile)
         cm_data.fakeSCache.linkCount = 1;
         cm_data.fakeSCache.refCount = 1;
     }
-    lock_InitializeMutex(&cm_data.fakeSCache.mx, "cm_scache_t mutex");
+    lock_InitializeRWLock(&cm_data.fakeSCache.rw, "cm_scache_t rw");
 }
 
 long
@@ -448,6 +461,8 @@ cm_ValidateSCache(void)
 
     for ( i=0; i < cm_data.scacheHashTableSize; i++ ) {
         for ( scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp ) {
+            afs_uint32 hash;
+            hash = CM_SCACHE_HASH(&scp->fid);
             if (scp->magic != CM_SCACHE_MAGIC) {
                 afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
                 fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
@@ -468,6 +483,11 @@ cm_ValidateSCache(void)
                 fprintf(stderr, "cm_ValidateSCache failure: scp->volp->magic != CM_VOLUME_MAGIC\n");
                 return -12;
             }
+            if (hash != i) {
+                afsi_log("cm_ValidateSCache failure: scp hash != hash index");
+                fprintf(stderr, "cm_ValidateSCache failure: scp hash != hash index\n");
+                return -13;
+            }
         }
     }
 
@@ -492,7 +512,7 @@ cm_SuspendSCache(void)
      * without network, the stat cache item will still be
      * considered valid.
      */
-    now = osi_Time();
+    now = time(NULL);
 
     lock_ObtainWrite(&cm_scacheLock);
     for ( scp = cm_data.allSCachesp; scp; scp = scp->allNextp ) {
@@ -518,9 +538,9 @@ cm_ShutdownSCache(void)
     for ( scp = cm_data.allSCachesp; scp;
           scp = scp->allNextp ) {
         if (scp->randomACLp) {
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
             cm_FreeAllACLEnts(scp);
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
         }
 
         if (scp->cbServerp) {
@@ -537,7 +557,7 @@ cm_ShutdownSCache(void)
         scp->dirDataVersion = -1;
         lock_FinalizeRWLock(&scp->dirlock);
 #endif
-        lock_FinalizeMutex(&scp->mx);
+        lock_FinalizeRWLock(&scp->rw);
         lock_FinalizeRWLock(&scp->bufCreateLock);
     }
     lock_ReleaseWrite(&cm_scacheLock);
@@ -564,7 +584,7 @@ void cm_InitSCache(int newFile, long maxSCaches)
 
             for ( scp = cm_data.allSCachesp; scp;
                   scp = scp->allNextp ) {
-                lock_InitializeMutex(&scp->mx, "cm_scache_t mutex");
+                lock_InitializeRWLock(&scp->rw, "cm_scache_t rw");
                 lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
 #ifdef USE_BPLUS
                 lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock");
@@ -612,16 +632,17 @@ cm_scache_t *cm_FindSCache(cm_fid_t *fidp)
        return NULL;
     }
 
-    lock_ObtainWrite(&cm_scacheLock);
+    lock_ObtainRead(&cm_scacheLock);
     for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
         if (cm_FidCmp(fidp, &scp->fid) == 0) {
             cm_HoldSCacheNoLock(scp);
+            lock_ConvertRToW(&cm_scacheLock);
             cm_AdjustScacheLRU(scp);
             lock_ReleaseWrite(&cm_scacheLock);
             return scp;
         }
     }
-    lock_ReleaseWrite(&cm_scacheLock);
+    lock_ReleaseRead(&cm_scacheLock);
     return NULL;
 }
 
@@ -638,9 +659,8 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
     long code;
     cm_volume_t *volp = NULL;
     cm_cell_t *cellp;
-    char* mp = NULL;
-    int special; // yj: boolean variable to test if file is on root.afs
-    int isRoot;
+    int special = 0; // yj: boolean variable to test if file is on root.afs
+    int isRoot = 0;
     extern cm_fid_t cm_rootFid;
         
     hash = CM_SCACHE_HASH(fidp);
@@ -695,14 +715,24 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
     }
          
     if (cm_freelanceEnabled && special) {
+        char mp[MOUNTPOINTLEN] = "";
+        afs_uint32 fileType;
+
         osi_Log0(afsd_logp,"cm_GetSCache Freelance and special");
-        if (fidp->vnode > 1 && fidp->vnode <= cm_noLocalMountPoints + 2) {
-           lock_ObtainMutex(&cm_Freelance_Lock);
-            mp =(cm_localMountPoints+fidp->vnode-2)->mountPointStringp;
-            lock_ReleaseMutex(&cm_Freelance_Lock);
+        lock_ObtainMutex(&cm_Freelance_Lock);
+        if (fidp->vnode >= 2 && fidp->vnode - 2 < cm_noLocalMountPoints) {
+            strncpy(mp,(cm_localMountPoints+fidp->vnode-2)->mountPointStringp, MOUNTPOINTLEN);
+            mp[MOUNTPOINTLEN-1] = '\0';
+            if ( !strnicmp(mp, "msdfs:", strlen("msdfs:")) )
+                fileType = CM_SCACHETYPE_DFSLINK;
+            else
+                fileType = (cm_localMountPoints+fidp->vnode-2)->fileType;
         } else {
-            mp = "";
+            fileType = CM_SCACHETYPE_INVALID;
+
         }
+        lock_ReleaseMutex(&cm_Freelance_Lock);
+
         scp = cm_GetNewSCache();
        if (scp == NULL) {
            osi_Log0(afsd_logp,"cm_GetSCache unable to obtain *new* scache entry");
@@ -717,12 +747,13 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
         * assume that no one else is using the one this is returned.
         */
        lock_ReleaseWrite(&cm_scacheLock);
-       lock_ObtainMutex(&scp->mx);
+       lock_ObtainWrite(&scp->rw);
        lock_ObtainWrite(&cm_scacheLock);
 #endif
         scp->fid = *fidp;
         scp->volp = cm_data.rootSCachep->volp;
-       cm_GetVolume(scp->volp);        /* grab an additional reference */
+        if (scp->volp)
+           cm_GetVolume(scp->volp);    /* grab an additional reference */
         scp->dotdotFid.cell=AFS_FAKE_ROOT_CELL_ID;
         scp->dotdotFid.volume=AFS_FAKE_ROOT_VOL_ID;
         scp->dotdotFid.unique=1;
@@ -733,18 +764,10 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
         scp->flags |= CM_SCACHEFLAG_INHASH;
         scp->refCount = 1;
        osi_Log1(afsd_logp,"cm_GetSCache (freelance) sets refCount to 1 scp 0x%x", scp);
-        if (fidp->vnode > 1 && fidp->vnode <= cm_noLocalMountPoints + 2)
-            scp->fileType = (cm_localMountPoints+fidp->vnode-2)->fileType;
-        else 
-            scp->fileType = CM_SCACHETYPE_INVALID;
-
-        lock_ObtainMutex(&cm_Freelance_Lock);
+        scp->fileType = fileType;
         scp->length.LowPart = (DWORD)strlen(mp)+4;
         scp->length.HighPart = 0;
         strncpy(scp->mountPointStringp,mp,MOUNTPOINTLEN);
-        scp->mountPointStringp[MOUNTPOINTLEN-1] = '\0';
-        lock_ReleaseMutex(&cm_Freelance_Lock);
-
         scp->owner=0x0;
         scp->unixModeBits=0777;
         scp->clientModTime=FakeFreelanceModTime;
@@ -753,9 +776,10 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
         scp->parentVnode=0x1;
         scp->group=0;
         scp->dataVersion=cm_data.fakeDirVersion;
+        scp->bufDataVersionLow=cm_data.fakeDirVersion;
         scp->lockDataVersion=-1; /* no lock yet */
 #if not_too_dangerous
-       lock_ReleaseMutex(&scp->mx);
+       lock_ReleaseWrite(&scp->rw);
 #endif
        *outScpp = scp;
         lock_ReleaseWrite(&cm_scacheLock);
@@ -771,7 +795,7 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
     /* otherwise, we need to find the volume */
     if (!cm_freelanceEnabled || !isRoot) {
         lock_ReleaseWrite(&cm_scacheLock);     /* for perf. reasons */
-        cellp = cm_FindCellByID(fidp->cell);
+        cellp = cm_FindCellByID(fidp->cell, 0);
         if (!cellp) 
             return CM_ERROR_NOSUCHCELL;
 
@@ -821,7 +845,7 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
      * assume that no one else is using the one this is returned.
      */
     lock_ReleaseWrite(&cm_scacheLock);
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     lock_ObtainWrite(&cm_scacheLock);
 #endif
     scp->fid = *fidp;
@@ -847,7 +871,7 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
     scp->refCount = 1;
     osi_Log1(afsd_logp,"cm_GetSCache sets refCount to 1 scp 0x%x", scp);
 #if not_too_dangerous
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
 #endif
 
     /* XXX - The following fields in the cm_scache are 
@@ -876,10 +900,8 @@ cm_scache_t * cm_FindSCacheParent(cm_scache_t * scp)
     cm_fid_t    parent_fid;
     cm_scache_t * pscp = NULL;
 
-    lock_ObtainRead(&cm_scacheLock);
-    parent_fid = scp->fid;
-    parent_fid.vnode = scp->parentVnode;
-    parent_fid.unique = scp->parentUnique;
+    lock_ObtainWrite(&cm_scacheLock);
+    cm_SetFid(&parent_fid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique);
 
     if (cm_FidCmp(&scp->fid, &parent_fid)) {
        i = CM_SCACHE_HASH(&parent_fid);
@@ -891,7 +913,7 @@ cm_scache_t * cm_FindSCacheParent(cm_scache_t * scp)
        }
     }
 
-    lock_ReleaseRead(&cm_scacheLock);
+    lock_ReleaseWrite(&cm_scacheLock);
 
     return pscp;
 }
@@ -900,6 +922,10 @@ void cm_SyncOpAddToWaitQueue(cm_scache_t * scp, afs_int32 flags, cm_buf_t * bufp
 {
     cm_scache_waiter_t * w;
 
+    /* Do not use the queue for asynchronous store operations */
+    if (flags == CM_SCACHESYNC_ASYNCSTORE)
+        return;
+
     lock_ObtainWrite(&cm_scacheLock);
     if (cm_allFreeWaiters == NULL) {
         w = malloc(sizeof(*w));
@@ -926,6 +952,10 @@ int cm_SyncOpCheckContinue(cm_scache_t * scp, afs_int32 flags, cm_buf_t * bufp)
     cm_scache_waiter_t * w;
     int this_is_me;
 
+    /* Do not use the queue for asynchronous store operations */
+    if (flags == CM_SCACHESYNC_ASYNCSTORE)
+        return 1;
+
     osi_Log0(afsd_logp, "cm_SyncOpCheckContinue checking for continuation");
 
     lock_ObtainRead(&cm_scacheLock);
@@ -1210,9 +1240,9 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
                    lock_ReleaseMutex(&bufp->mx);
                 code = cm_GetCallback(scp, userp, reqp, (flags & CM_SCACHESYNC_FORCECB)?1:0);
                 if (bufLocked) {
-                    lock_ReleaseMutex(&scp->mx);
+                    lock_ReleaseWrite(&scp->rw);
                     lock_ObtainMutex(&bufp->mx);
-                    lock_ObtainMutex(&scp->mx);
+                    lock_ObtainWrite(&scp->rw);
                 }
                 if (code) 
                     return code;
@@ -1237,9 +1267,9 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
                 if (bufLocked) lock_ReleaseMutex(&bufp->mx);
                 code = cm_GetAccessRights(scp, userp, reqp);
                 if (bufLocked) {
-                    lock_ReleaseMutex(&scp->mx);
+                    lock_ReleaseWrite(&scp->rw);
                     lock_ObtainMutex(&bufp->mx);
-                    lock_ObtainMutex(&scp->mx);
+                    lock_ObtainWrite(&scp->rw);
                 }
                 if (code) 
                     return code;
@@ -1275,22 +1305,19 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
             scp->waitCount = scp->waitRequests = 1;
         }
 
-        if (bufLocked) 
-            lock_ReleaseMutex(&bufp->mx);
-
         cm_SyncOpAddToWaitQueue(scp, flags, bufp);
         wakeupCycle = 0;
         do {
-            if (wakeupCycle++ != 0)
-                lock_ObtainMutex(&scp->mx);
-            osi_SleepM((LONG_PTR) &scp->flags, &scp->mx);
+            if (bufLocked) 
+                lock_ReleaseMutex(&bufp->mx);
+            osi_SleepW((LONG_PTR) &scp->flags, &scp->rw);
+            if (bufLocked) 
+                lock_ObtainMutex(&bufp->mx);
+            lock_ObtainWrite(&scp->rw);
         } while (!cm_SyncOpCheckContinue(scp, flags, bufp));
 
        smb_UpdateServerPriority();
 
-        if (bufLocked) 
-            lock_ObtainMutex(&bufp->mx);
-        lock_ObtainMutex(&scp->mx);
         scp->waitCount--;
         osi_Log3(afsd_logp, "CM SyncOp woke! scp 0x%p; still waiting %d threads of %d requests", 
                  scp, scp->waitCount, scp->waitRequests);
@@ -1374,7 +1401,7 @@ void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, afs_uint32 flags)
     osi_queueData_t *qdp;
     cm_buf_t *tbufp;
 
-    lock_AssertMutex(&scp->mx);
+    lock_AssertWrite(&scp->rw);
 
     /* now, update the recorded state for RPC-type calls */
     if (flags & CM_SCACHESYNC_FETCHSTATUS)
@@ -1502,7 +1529,7 @@ void cm_MergeStatus(cm_scache_t *dscp,
         statusp->Group = 0;
         statusp->SyncCounter = 0;
         statusp->dataVersionHigh = (afs_uint32)(cm_data.fakeDirVersion >> 32);
-       statusp->errorCode = 0;
+        statusp->errorCode = 0;
     }
 #endif /* AFS_FREELANCE_CLIENT */
 
@@ -1524,6 +1551,7 @@ void cm_MergeStatus(cm_scache_t *dscp,
        scp->unixModeBits = 0;
        scp->anyAccess = 0;
        scp->dataVersion = 0;
+        scp->bufDataVersionLow = 0;
 
        if (dscp) {
             scp->parentVnode = dscp->fid.vnode;
@@ -1544,7 +1572,7 @@ void cm_MergeStatus(cm_scache_t *dscp,
     if (!(flags & CM_MERGEFLAG_FORCE) && dataVersion < scp->dataVersion) {
         struct cm_cell *cellp;
 
-        cellp = cm_FindCellByID(scp->fid.cell);
+        cellp = cm_FindCellByID(scp->fid.cell, 0);
         if (scp->cbServerp) {
             struct cm_volume *volp = NULL;
 
@@ -1556,7 +1584,7 @@ void cm_MergeStatus(cm_scache_t *dscp,
             if (volp)
                 cm_PutVolume(volp);
         }
-        osi_Log3(afsd_logp, "Bad merge, scp %x, scp dv %I64d, RPC dv %I64d",
+        osi_Log3(afsd_logp, "Bad merge, scp %x, scp dv %d, RPC dv %d",
                   scp, scp->dataVersion, dataVersion);
         /* we have a number of data fetch/store operations running
          * concurrently, and we can tell which one executed last at the
@@ -1634,17 +1662,79 @@ void cm_MergeStatus(cm_scache_t *dscp,
         cm_AddACLCache(scp, userp, statusp->CallerAccess);
     }
 
-    if ((flags & CM_MERGEFLAG_STOREDATA) && dataVersion - scp->dataVersion == 1) {
-       cm_buf_t *bp;
-
-       for (bp = cm_data.buf_fileHashTablepp[BUF_FILEHASH(&scp->fid)]; bp; bp=bp->fileHashp)
+    if (scp->dataVersion != 0 &&
+        (!(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && dataVersion != scp->dataVersion ||
+         (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && dataVersion - scp->dataVersion > 1)) {
+        /* 
+         * We now know that all of the data buffers that we have associated
+         * with this scp are invalid.  Subsequent operations will go faster
+         * if the buffers are removed from the hash tables.
+         *
+         * We do not remove directory buffers if the dataVersion delta is 1 because
+         * those version numbers will be updated as part of the directory operation.
+         *
+         * We do not remove storedata buffers because they will still be valid.
+         */
+        int i, j;
+        cm_buf_t **lbpp;
+        cm_buf_t *tbp;
+        cm_buf_t *bp, *prevBp, *nextBp;
+
+        lock_ObtainWrite(&buf_globalLock);
+        i = BUF_FILEHASH(&scp->fid);
+               for (bp = cm_data.buf_fileHashTablepp[i]; bp; bp=nextBp)
        {
-           if (cm_FidCmp(&scp->fid, &bp->fid) == 0 && 
-               bp->dataVersion == scp->dataVersion)
-               bp->dataVersion = dataVersion;
-       }
+            nextBp = bp->fileHashp;
+            /* 
+             * if the buffer belongs to this stat cache entry
+             * and the buffer mutex can be obtained, check the
+             * reference count and if it is zero, remove the buffer
+             * from the hash tables.  If there are references,
+             * the buffer might be updated to the current version
+             * so leave it in place.
+             */
+            if (cm_FidCmp(&scp->fid, &bp->fid) == 0 &&
+                 lock_TryMutex(&bp->mx)) {
+                if (bp->refCount == 0 && 
+                    !(bp->flags & CM_BUF_READING | CM_BUF_WRITING | CM_BUF_DIRTY)) {
+                    prevBp = bp->fileHashBackp;
+                    bp->fileHashBackp = bp->fileHashp = NULL;
+                    if (prevBp)
+                        prevBp->fileHashp = nextBp;
+                    else
+                        cm_data.buf_fileHashTablepp[i] = nextBp;
+                    if (nextBp)
+                        nextBp->fileHashBackp = prevBp;
+
+                    j = BUF_HASH(&bp->fid, &bp->offset);
+                    lbpp = &(cm_data.buf_scacheHashTablepp[j]);
+                    for(tbp = *lbpp; tbp; lbpp = &tbp->hashp, tbp = *lbpp) {
+                        if (tbp == bp) 
+                            break;
+                    }
 
+                    *lbpp = bp->hashp; /* hash out */
+                    bp->hashp = NULL;
+
+                    bp->flags &= ~CM_BUF_INHASH;
+                }
+                lock_ReleaseMutex(&bp->mx);
+            }
+       }
+        lock_ReleaseWrite(&buf_globalLock);
     }
+
+    /* We maintain a range of buffer dataVersion values which are considered 
+     * valid.  This avoids the need to update the dataVersion on each buffer
+     * object during an uncontested storeData operation.  As a result this 
+     * merge status no longer has performance characteristics derived from
+     * the size of the file.
+     */
+    if (((flags & CM_MERGEFLAG_STOREDATA) && dataVersion - scp->dataVersion > 1) || 
+         (!(flags & CM_MERGEFLAG_STOREDATA) && scp->dataVersion != dataVersion) ||
+         scp->bufDataVersionLow == 0)
+        scp->bufDataVersionLow = dataVersion;
+    
     scp->dataVersion = dataVersion;
 }
 
@@ -1658,7 +1748,7 @@ void cm_MergeStatus(cm_scache_t *dscp,
  */
 void cm_DiscardSCache(cm_scache_t *scp)
 {
-    lock_AssertMutex(&scp->mx);
+    lock_AssertWrite(&scp->rw);
     if (scp->cbServerp) {
         cm_PutServer(scp->cbServerp);
        scp->cbServerp = NULL;
@@ -1669,6 +1759,9 @@ void cm_DiscardSCache(cm_scache_t *scp)
     cm_dnlcPurgevp(scp);
     cm_FreeAllACLEnts(scp);
 
+    if (scp->fileType == CM_SCACHETYPE_DFSLINK)
+        cm_VolStatus_Invalidate_DFS_Mapping(scp);
+
     /* Force mount points and symlinks to be re-evaluated */
     scp->mountPointStringp[0] = '\0';
 }
@@ -1685,12 +1778,15 @@ void cm_HoldSCacheNoLockDbg(cm_scache_t *scp, char * file, long line)
 #else
 void cm_HoldSCacheNoLock(cm_scache_t *scp)
 #endif
-{
+{     
+    afs_int32 refCount;
+
     osi_assertx(scp != NULL, "null cm_scache_t");
-    scp->refCount++;
+    lock_AssertAny(&cm_scacheLock);
+    refCount = InterlockedIncrement(&scp->refCount);
 #ifdef DEBUG_REFCOUNT
-    osi_Log2(afsd_logp,"cm_HoldSCacheNoLock scp 0x%p ref %d",scp, scp->refCount);
-    afsi_log("%s:%d cm_HoldSCacheNoLock scp 0x%p, ref %d", file, line, scp, scp->refCount);
+    osi_Log2(afsd_logp,"cm_HoldSCacheNoLock scp 0x%p ref %d",scp, refCount);
+    afsi_log("%s:%d cm_HoldSCacheNoLock scp 0x%p, ref %d", file, line, scp, refCount);
 #endif
 }
 
@@ -1700,14 +1796,16 @@ void cm_HoldSCacheDbg(cm_scache_t *scp, char * file, long line)
 void cm_HoldSCache(cm_scache_t *scp)
 #endif
 {
+    afs_int32 refCount;
+
     osi_assertx(scp != NULL, "null cm_scache_t");
-    lock_ObtainWrite(&cm_scacheLock);
-    scp->refCount++;
+    lock_ObtainRead(&cm_scacheLock);
+    refCount = InterlockedIncrement(&scp->refCount);
 #ifdef DEBUG_REFCOUNT
-    osi_Log2(afsd_logp,"cm_HoldSCache scp 0x%p ref %d",scp, scp->refCount);
-    afsi_log("%s:%d cm_HoldSCache scp 0x%p ref %d", file, line, scp, scp->refCount);
+    osi_Log2(afsd_logp,"cm_HoldSCache scp 0x%p ref %d",scp, refCount);
+    afsi_log("%s:%d cm_HoldSCache scp 0x%p ref %d", file, line, scp, refCount);
 #endif
-    lock_ReleaseWrite(&cm_scacheLock);
+    lock_ReleaseRead(&cm_scacheLock);
 }
 
 #ifdef DEBUG_REFCOUNT
@@ -1716,13 +1814,18 @@ void cm_ReleaseSCacheNoLockDbg(cm_scache_t *scp, char * file, long line)
 void cm_ReleaseSCacheNoLock(cm_scache_t *scp)
 #endif
 {
+    afs_int32 refCount;
     osi_assertx(scp != NULL, "null cm_scache_t");
-    if (scp->refCount == 0)
+    lock_AssertAny(&cm_scacheLock);
+    refCount = InterlockedDecrement(&scp->refCount);
+#ifdef DEBUG_REFCOUNT
+    if (refCount < 0)
        osi_Log1(afsd_logp,"cm_ReleaseSCacheNoLock about to panic scp 0x%x",scp);
-    osi_assertx(scp->refCount-- >= 0, "cm_scache_t refCount 0");
+#endif
+    osi_assertx(refCount >= 0, "cm_scache_t refCount 0");
 #ifdef DEBUG_REFCOUNT
-    osi_Log2(afsd_logp,"cm_ReleaseSCacheNoLock scp 0x%p ref %d",scp,scp->refCount);
-    afsi_log("%s:%d cm_ReleaseSCacheNoLock scp 0x%p ref %d", file, line, scp, scp->refCount);
+    osi_Log2(afsd_logp,"cm_ReleaseSCacheNoLock scp 0x%p ref %d",scp, refCount);
+    afsi_log("%s:%d cm_ReleaseSCacheNoLock scp 0x%p ref %d", file, line, scp, refCount);
 #endif
 }
 
@@ -1731,18 +1834,22 @@ void cm_ReleaseSCacheDbg(cm_scache_t *scp, char * file, long line)
 #else
 void cm_ReleaseSCache(cm_scache_t *scp)
 #endif
-{
+{     
+    afs_int32 refCount;
+
     osi_assertx(scp != NULL, "null cm_scache_t");
-    lock_ObtainWrite(&cm_scacheLock);
-    if (scp->refCount == 0)
+    lock_ObtainRead(&cm_scacheLock);
+    refCount = InterlockedDecrement(&scp->refCount);
+#ifdef DEBUG_REFCOUNT
+    if (refCount < 0)
        osi_Log1(afsd_logp,"cm_ReleaseSCache about to panic scp 0x%x",scp);
-    osi_assertx(scp->refCount != 0, "cm_scache_t refCount 0");
-    scp->refCount--;
+#endif
+    osi_assertx(refCount >= 0, "cm_scache_t refCount 0");
 #ifdef DEBUG_REFCOUNT
-    osi_Log2(afsd_logp,"cm_ReleaseSCache scp 0x%p ref %d",scp,scp->refCount);
-    afsi_log("%s:%d cm_ReleaseSCache scp 0x%p ref %d", file, line, scp, scp->refCount);
+    osi_Log2(afsd_logp,"cm_ReleaseSCache scp 0x%p ref %d",scp, refCount);
+    afsi_log("%s:%d cm_ReleaseSCache scp 0x%p ref %d", file, line, scp, refCount);
 #endif
-    lock_ReleaseWrite(&cm_scacheLock);
+    lock_ReleaseRead(&cm_scacheLock);
 }
 
 /* just look for the scp entry to get filetype */
@@ -1786,7 +1893,7 @@ int cm_DumpSCache(FILE *outputFile, char *cookie, int lock)
   
     for (scp = cm_data.allSCachesp; scp; scp = scp->allNextp) 
     {
-        sprintf(output, "%s scp=0x%p, fid (cell=%d, volume=%d, vnode=%d, unique=%d) volp=0x%p type=%d dv=%d len=0x%I64x mp='%s' flags=0x%x cb=0x%x refCount=%u\r\n", 
+        sprintf(output, "%s scp=0x%p, fid (cell=%d, volume=%d, vnode=%d, unique=%d) volp=0x%p type=%d dv=%I64d len=0x%I64x mp='%s' flags=0x%x cb=0x%x refCount=%u\r\n", 
                 cookie, scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique, 
                 scp->volp, scp->fileType, scp->dataVersion, scp->length.QuadPart, scp->mountPointStringp, scp->flags,
                 (unsigned long)scp->cbExpires, scp->refCount);