Windows: cm_RemoveSCacheFromHashTable scp not found
[openafs.git] / src / WINNT / afsd / cm_scache.c
index 61c1519..a2432b5 100644 (file)
@@ -66,37 +66,67 @@ cm_RootSCachep(cm_user_t *userp, cm_req_t *reqp)
 void cm_AdjustScacheLRU(cm_scache_t *scp)
 {
     lock_AssertWrite(&cm_scacheLock);
-    osi_QRemoveHT((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
-    if (scp->flags & CM_SCACHEFLAG_DELETED) {
-        /* Since it has been deleted make it the first to be recycled. */
-        osi_QAddT((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
-    } else {
+    if (!(scp->flags & CM_SCACHEFLAG_DELETED)) {
+        osi_QRemoveHT((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
         osi_QAddH((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
     }
 }
 
-/* call with cm_scacheLock write-locked and scp rw held */
-void cm_RemoveSCacheFromHashTable(cm_scache_t *scp)
+static int
+cm_RemoveSCacheFromHashChain(cm_scache_t *scp, int index)
 {
     cm_scache_t **lscpp;
     cm_scache_t *tscp;
-    int i;
+    int found = 0;
+
+    for (lscpp = &cm_data.scacheHashTablep[index], tscp = cm_data.scacheHashTablep[index];
+         tscp;
+         lscpp = &tscp->nextp, tscp = tscp->nextp) {
+       if (tscp == scp) {
+           *lscpp = scp->nextp;
+           scp->nextp = NULL;
+           found = 1;
+           break;
+       }
+    }
 
+    return found;
+}
+
+/* call with cm_scacheLock write-locked and scp rw held */
+void cm_RemoveSCacheFromHashTable(cm_scache_t *scp)
+{
     lock_AssertWrite(&cm_scacheLock);
     lock_AssertWrite(&scp->rw);
     if (scp->flags & CM_SCACHEFLAG_INHASH) {
+       int h,i;
+       int found = 0;
+
        /* hash it out first */
-       i = CM_SCACHE_HASH(&scp->fid);
-       for (lscpp = &cm_data.scacheHashTablep[i], tscp = cm_data.scacheHashTablep[i];
-            tscp;
-            lscpp = &tscp->nextp, tscp = tscp->nextp) {
-           if (tscp == scp) {
-               *lscpp = scp->nextp;
-                scp->nextp = NULL;
-               _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_INHASH);
-               break;
+       h = CM_SCACHE_HASH(&scp->fid);
+       found = cm_RemoveSCacheFromHashChain(scp, h);
+
+       if (!found) {
+           /*
+            * The CM_SCACHEFLAG_INHASH is set on the cm_scache_t but
+            * we didn't find the entry in the expected hash chain.
+            * Did the fid change?
+            * In any case, we will search the entire hashtable for
+            * the object.  If we don't find it, then we know it is
+            * safe to remove the flag.
+            */
+           for (i=0; !found && i<cm_data.scacheHashTableSize; i++) {
+               if (i != h)
+                   found = cm_RemoveSCacheFromHashChain(scp, i);
            }
+
+           if (found)
+               osi_Log1(afsd_logp,"cm_RemoveSCacheFromHashTable scp 0x%p found in wrong hash chain", scp);
+           else
+               osi_Log1(afsd_logp,"cm_RemoveSCacheFromHashTable scp 0x%p not found in hash table", scp);
        }
+
+       _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_INHASH);
     }
 }
 
@@ -185,12 +215,12 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
      * also initialize some flags */
     scp->fileType = 0;
     _InterlockedAnd(&scp->flags,
-                    ~(CM_SCACHEFLAG_STATD
-                    | CM_SCACHEFLAG_DELETED
+                    ~( CM_SCACHEFLAG_DELETED
                     | CM_SCACHEFLAG_RO
                     | CM_SCACHEFLAG_PURERO
                     | CM_SCACHEFLAG_OVERQUOTA
-                    | CM_SCACHEFLAG_OUTOFSPACE));
+                    | CM_SCACHEFLAG_OUTOFSPACE
+                     | CM_SCACHEFLAG_ASYNCSTORING));
     scp->serverModTime = 0;
     scp->dataVersion = CM_SCACHE_VERSION_BAD;
     scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
@@ -391,7 +421,7 @@ cm_GetNewSCache(afs_uint32 locked)
     /* if we get here, we should allocate a new scache entry.  We either are below
      * quota or we have a leak and need to allocate a new one to avoid panicing.
      */
-    scp = cm_data.scacheBaseAddress + cm_data.currentSCaches;
+    scp = cm_data.scacheBaseAddress + InterlockedIncrement(&cm_data.currentSCaches) - 1;
     osi_assertx(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.scacheHashTablep,
                 "invalid cm_scache_t address");
     memset(scp, 0, sizeof(cm_scache_t));
@@ -407,10 +437,10 @@ cm_GetNewSCache(afs_uint32 locked)
     scp->dataVersion = CM_SCACHE_VERSION_BAD;
     scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
     scp->lockDataVersion = CM_SCACHE_VERSION_BAD;
+    scp->mpDataVersion = CM_SCACHE_VERSION_BAD;
 
     /* and put it in the LRU queue */
     osi_QAddH((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **)&cm_data.scacheLRULastp, &scp->q);
-    cm_data.currentSCaches++;
     cm_dnlcPurgedp(scp); /* make doubly sure that this is not in dnlc */
     cm_dnlcPurgevp(scp);
     scp->allNextp = cm_data.allSCachesp;
@@ -487,16 +517,40 @@ cm_ValidateSCache(void)
     for ( scp = cm_data.scacheLRUFirstp, lscp = NULL, i = 0;
           scp;
           lscp = scp, scp = (cm_scache_t *) osi_QNext(&scp->q), i++ ) {
+
+       if ( scp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+            scp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+           afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+           fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+           return -18;
+       }
+
         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");
             return -1;
         }
+
+       if ( scp->nextp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+            scp->nextp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+           afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+           fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+           return -21;
+       }
+
         if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
             afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
             fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
             return -2;
         }
+
+       if ( scp->randomACLp < (cm_aclent_t *)cm_data.aclBaseAddress ||
+            scp->randomACLp >= (cm_aclent_t *)cm_data.scacheBaseAddress) {
+           afsi_log("cm_ValidateSCache failure: out of range cm_aclent_t pointers");
+           fprintf(stderr, "cm_ValidateSCache failure: out of range cm_aclent_t pointers\n");
+           return -32;
+       }
+
         if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
             afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
             fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
@@ -516,16 +570,40 @@ cm_ValidateSCache(void)
 
     for ( scp = cm_data.scacheLRULastp, lscp = NULL, i = 0; scp;
           lscp = scp, scp = (cm_scache_t *) osi_QPrev(&scp->q), i++ ) {
+
+       if ( scp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+            scp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+           afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+           fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+           return -19;
+       }
+
         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");
             return -5;
         }
+
+       if ( scp->nextp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+            scp->nextp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+           afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+           fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+           return -22;
+       }
+
         if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
             afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
             fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
             return -6;
         }
+
+       if ( scp->randomACLp < (cm_aclent_t *)cm_data.aclBaseAddress ||
+            scp->randomACLp >= (cm_aclent_t *)cm_data.scacheBaseAddress) {
+           afsi_log("cm_ValidateSCache failure: out of range cm_aclent_t pointers");
+           fprintf(stderr, "cm_ValidateSCache failure: out of range cm_aclent_t pointers\n");
+           return -31;
+       }
+
         if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
             afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
             fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
@@ -546,17 +624,42 @@ cm_ValidateSCache(void)
     for ( i=0; i < cm_data.scacheHashTableSize; i++ ) {
         for ( scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp ) {
             afs_uint32 hash;
+
+           if ( scp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+                scp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+               afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+               fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+               return -20;
+           }
+
             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");
                 return -9;
             }
+
+           if ( scp->nextp < (cm_scache_t *)cm_data.scacheBaseAddress ||
+                scp->nextp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
+               afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
+               fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
+               return -23;
+           }
+
             if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
                 afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
                 fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
                 return -10;
             }
+
+           if ( scp->randomACLp < (cm_aclent_t *)cm_data.aclBaseAddress ||
+                scp->randomACLp >= (cm_aclent_t *)cm_data.scacheBaseAddress) {
+               afsi_log("cm_ValidateSCache failure: out of range cm_aclent_t pointers");
+               fprintf(stderr, "cm_ValidateSCache failure: out of range cm_aclent_t pointers\n");
+               return -30;
+           }
+
             if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
                 afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
                 fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
@@ -639,7 +742,6 @@ cm_ShutdownSCache(void)
         }
         scp->cbExpires = 0;
         scp->cbIssued = 0;
-        _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_CALLBACK);
         lock_ReleaseWrite(&scp->rw);
 
 #ifdef USE_BPLUS
@@ -702,7 +804,7 @@ void cm_InitSCache(int newFile, long maxSCaches)
                 scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
 #endif
                 scp->waitQueueT = NULL;
-                _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_CALLBACK | CM_SCACHEFLAG_WAITING | CM_SCACHEFLAG_RDR_IN_USE));
+                _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_WAITING | CM_SCACHEFLAG_RDR_IN_USE));
 
                 scp->redirBufCount = 0;
                 scp->redirQueueT = NULL;
@@ -903,7 +1005,7 @@ long cm_GetSCache(cm_fid_t *fidp, cm_fid_t *parentFidp, cm_scache_t **outScpp, c
         if (!cellp) {
             /* put back newScp so it can be reused */
             lock_ObtainWrite(&cm_scacheLock);
-            newScp->flags |= CM_SCACHEFLAG_DELETED;
+           _InterlockedOr(&newScp->flags, CM_SCACHEFLAG_DELETED);
             cm_AdjustScacheLRU(newScp);
             lock_ReleaseWrite(&newScp->rw);
             lock_ReleaseWrite(&cm_scacheLock);
@@ -914,7 +1016,7 @@ long cm_GetSCache(cm_fid_t *fidp, cm_fid_t *parentFidp, cm_scache_t **outScpp, c
         if (code) {
             /* put back newScp so it can be reused */
             lock_ObtainWrite(&cm_scacheLock);
-            newScp->flags |= CM_SCACHEFLAG_DELETED;
+           _InterlockedOr(&newScp->flags, CM_SCACHEFLAG_DELETED);
             cm_AdjustScacheLRU(newScp);
             lock_ReleaseWrite(&newScp->rw);
             lock_ReleaseWrite(&cm_scacheLock);
@@ -945,7 +1047,7 @@ long cm_GetSCache(cm_fid_t *fidp, cm_fid_t *parentFidp, cm_scache_t **outScpp, c
             cm_AdjustScacheLRU(scp);
 
             /* put back newScp so it can be reused */
-            newScp->flags |= CM_SCACHEFLAG_DELETED;
+           _InterlockedOr(&newScp->flags, CM_SCACHEFLAG_DELETED);
             cm_AdjustScacheLRU(newScp);
             lock_ReleaseWrite(&newScp->rw);
             lock_ReleaseWrite(&cm_scacheLock);
@@ -1172,6 +1274,8 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
     afs_uint32 sleep_buf_cmflags = 0;
     afs_uint32 sleep_scp_bufs = 0;
     int wakeupCycle;
+    afs_int32 waitCount;
+    afs_int32 waitRequests;
 
     lock_AssertWrite(&scp->rw);
 
@@ -1346,8 +1450,10 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
                 osi_Log1(afsd_logp, "CM SyncOp getting callback on scp 0x%p",
                           scp);
 
-                if (cm_EAccesFindEntry(userp, &scp->fid))
-                    return CM_ERROR_NOACCESS;
+               if (cm_EAccesFindEntry(userp, &scp->fid)) {
+                   code = CM_ERROR_NOACCESS;
+                   goto on_error;
+               }
 
                 if (bufLocked)
                    lock_ReleaseMutex(&bufp->mx);
@@ -1358,7 +1464,8 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
                     lock_ObtainWrite(&scp->rw);
                 }
                 if (code)
-                    return code;
+                   goto on_error;
+
                flags &= ~CM_SCACHESYNC_FORCECB;        /* only force once */
                 continue;
             }
@@ -1368,12 +1475,16 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
             /* can't check access rights without a callback */
             osi_assertx(flags & CM_SCACHESYNC_NEEDCALLBACK, "!CM_SCACHESYNC_NEEDCALLBACK");
 
-            if ((rights & (PRSFS_WRITE|PRSFS_DELETE)) && (scp->flags & CM_SCACHEFLAG_RO))
-                return CM_ERROR_READONLY;
+           if ((rights & (PRSFS_WRITE|PRSFS_DELETE)) && (scp->flags & CM_SCACHEFLAG_RO)) {
+               code = CM_ERROR_READONLY;
+               goto on_error;
+           }
 
             if (cm_HaveAccessRights(scp, userp, reqp, rights, &outRights)) {
-                if (~outRights & rights)
-                   return CM_ERROR_NOACCESS;
+               if (~outRights & rights) {
+                   code = CM_ERROR_NOACCESS;
+                   goto on_error;
+               }
             }
             else {
                 /* we don't know the required access rights */
@@ -1385,7 +1496,7 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
                     lock_ObtainWrite(&scp->rw);
                 }
                 if (code)
-                    return code;
+                   goto on_error;
                 continue;
             }
         }
@@ -1405,8 +1516,10 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
         /* first check if we're not supposed to wait: fail
          * in this case, returning with everything still locked.
          */
-        if (flags & CM_SCACHESYNC_NOWAIT)
-            return CM_ERROR_WOULDBLOCK;
+       if (flags & CM_SCACHESYNC_NOWAIT) {
+           code = CM_ERROR_WOULDBLOCK;
+           goto on_error;
+       }
 
         /* These are used for minidump debugging */
        sleep_scp_flags = scp->flags;           /* so we know why we slept */
@@ -1415,15 +1528,15 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
 
         /* wait here, then try again */
         osi_Log1(afsd_logp, "CM SyncOp sleeping scp 0x%p", scp);
-        if ( scp->flags & CM_SCACHEFLAG_WAITING ) {
-            scp->waitCount++;
-            scp->waitRequests++;
+
+        waitCount = InterlockedIncrement(&scp->waitCount);
+        waitRequests = InterlockedIncrement(&scp->waitRequests);
+        if (waitCount > 1) {
             osi_Log3(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING already set for 0x%p; %d threads; %d requests",
-                     scp, scp->waitCount, scp->waitRequests);
+                     scp, waitCount, waitRequests);
         } else {
             osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING set for 0x%p", scp);
             _InterlockedOr(&scp->flags, CM_SCACHEFLAG_WAITING);
-            scp->waitCount = scp->waitRequests = 1;
         }
 
         cm_SyncOpAddToWaitQueue(scp, flags, bufp);
@@ -1439,10 +1552,10 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
 
        cm_UpdateServerPriority();
 
-        scp->waitCount--;
+        waitCount = InterlockedDecrement(&scp->waitCount);
         osi_Log3(afsd_logp, "CM SyncOp woke! scp 0x%p; still waiting %d threads of %d requests",
-                 scp, scp->waitCount, scp->waitRequests);
-        if (scp->waitCount == 0) {
+                 scp, waitCount, scp->waitRequests);
+        if (waitCount == 0) {
             osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING reset for 0x%p", scp);
             _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_WAITING);
             scp->waitRequests = 0;
@@ -1509,7 +1622,23 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
         _InterlockedOr(&bufp->cmFlags, CM_BUF_CMWRITING);
     }
 
-    return 0;
+    return 0;   /* Success */
+
+  on_error:
+    /*
+     * This thread may have been a waiter that was woken up.
+     * If cm_SyncOp completes due to an error, cm_SyncOpDone() will
+     * never be called.  If there are additional threads waiting on
+     * scp those threads will never be woken.  Make sure we wake the
+     * next waiting thread before we leave.
+     */
+    if ((scp->flags & CM_SCACHEFLAG_WAITING) ||
+        !osi_QIsEmpty(&scp->waitQueueH)) {
+       osi_Log3(afsd_logp, "CM SyncOp 0x%x Waking scp 0x%p bufp 0x%p",
+                flags, scp, bufp);
+       osi_Wakeup((LONG_PTR) &scp->flags);
+    }
+    return code;
 }
 
 /* for those syncops that setup for RPCs.
@@ -1595,7 +1724,8 @@ void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, afs_uint32 flags)
     }
 
     /* and wakeup anyone who is waiting */
-    if (scp->flags & CM_SCACHEFLAG_WAITING) {
+    if ((scp->flags & CM_SCACHEFLAG_WAITING) ||
+        !osi_QIsEmpty(&scp->waitQueueH)) {
         osi_Log3(afsd_logp, "CM SyncOpDone 0x%x Waking scp 0x%p bufp 0x%p", flags, scp, bufp);
         osi_Wakeup((LONG_PTR) &scp->flags);
     }
@@ -1610,6 +1740,17 @@ dv_diff(afs_uint64 dv1, afs_uint64 dv2)
         return (afs_uint32)(dv1 - dv2);
 }
 
+long
+cm_IsStatusValid(AFSFetchStatus *statusp)
+{
+    if (statusp->InterfaceVersion != 0x1 ||
+        !(statusp->FileType > 0 && statusp->FileType <= SymbolicLink)) {
+        return 0;
+    }
+
+    return 1;
+}
+
 /* merge in a response from an RPC.  The scp must be locked, and the callback
  * is optional.
  *
@@ -1623,7 +1764,7 @@ dv_diff(afs_uint64 dv1, afs_uint64 dv2)
  * handled after the callback breaking is done, but only one of whose calls
  * started before that, can cause old info to be merged from the first call.
  */
-void cm_MergeStatus(cm_scache_t *dscp,
+long cm_MergeStatus(cm_scache_t *dscp,
                    cm_scache_t *scp, AFSFetchStatus *statusp,
                    AFSVolSync *volsyncp,
                     cm_user_t *userp, cm_req_t *reqp, afs_uint32 flags)
@@ -1674,10 +1815,10 @@ void cm_MergeStatus(cm_scache_t *dscp,
     }
 #endif /* AFS_FREELANCE_CLIENT */
 
-    if (statusp->InterfaceVersion != 0x1) {
-        osi_Log2(afsd_logp, "Merge, Failure scp 0x%p Invalid InterfaceVersion %u",
-                 scp, statusp->InterfaceVersion);
-        return;
+    if (!cm_IsStatusValid(statusp)) {
+        osi_Log3(afsd_logp, "Merge: Bad Status scp 0x%p Invalid InterfaceVersion %d FileType %d",
+                 scp, statusp->InterfaceVersion, statusp->FileType);
+        return CM_ERROR_INVAL;
     }
 
     if (statusp->errorCode != 0) {
@@ -1693,7 +1834,7 @@ void cm_MergeStatus(cm_scache_t *dscp,
         if (scp->fid.vnode & 0x1)
             scp->fileType = CM_SCACHETYPE_DIRECTORY;
         else
-            scp->fileType = 0; /* unknown */
+            scp->fileType = CM_SCACHETYPE_UNKNOWN;
 
        scp->serverModTime = 0;
        scp->clientModTime = 0;
@@ -1867,7 +2008,8 @@ void cm_MergeStatus(cm_scache_t *dscp,
              * so leave it in place.
              */
             if (cm_FidCmp(&scp->fid, &bp->fid) == 0 &&
-                 lock_TryMutex(&bp->mx)) {
+                bp->refCount == 0 &&
+                lock_TryMutex(&bp->mx)) {
                 if (bp->refCount == 0 &&
                     !(bp->flags & (CM_BUF_READING | CM_BUF_WRITING | CM_BUF_DIRTY)) &&
                     !(bp->qFlags & CM_BUF_QREDIR)) {
@@ -1923,8 +2065,10 @@ void cm_MergeStatus(cm_scache_t *dscp,
     if (((flags & (CM_MERGEFLAG_STOREDATA|CM_MERGEFLAG_DIROP)) && (dv_diff(dataVersion, scp->dataVersion) > activeRPCs)) ||
          (!(flags & (CM_MERGEFLAG_STOREDATA|CM_MERGEFLAG_DIROP)) && (scp->dataVersion != dataVersion)) ||
          scp->bufDataVersionLow == CM_SCACHE_VERSION_BAD ||
-         scp->fileType == CM_SCACHETYPE_DIRECTORY)
+         scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+         flags & CM_MERGEFLAG_CACHE_BYPASS) {
         scp->bufDataVersionLow = dataVersion;
+    }
 
     if (RDR_Initialized) {
         /*
@@ -2009,6 +2153,8 @@ void cm_MergeStatus(cm_scache_t *dscp,
                              scp->fileType, AFS_INVALIDATE_DATA_VERSION);
         lock_ObtainWrite(&scp->rw);
     }
+
+    return 0;
 }
 
 /* note that our stat cache info is incorrect, so force us eventually
@@ -2028,7 +2174,7 @@ void cm_DiscardSCache(cm_scache_t *scp)
     }
     scp->cbExpires = 0;
     scp->cbIssued = 0;
-    _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_CALLBACK | CM_SCACHEFLAG_LOCAL | CM_SCACHEFLAG_RDR_IN_USE));
+    _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_LOCAL | CM_SCACHEFLAG_RDR_IN_USE));
     cm_dnlcPurgedp(scp);
     cm_dnlcPurgevp(scp);
     cm_FreeAllACLEnts(scp);
@@ -2100,34 +2246,6 @@ void cm_ReleaseSCacheNoLock(cm_scache_t *scp)
     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
-
-    if (refCount == 0 && (scp->flags & CM_SCACHEFLAG_DELETED)) {
-        int deleted = 0;
-        long      lockstate;
-
-        lockstate = lock_GetRWLockState(&cm_scacheLock);
-        if (lockstate != OSI_RWLOCK_WRITEHELD)
-            lock_ReleaseRead(&cm_scacheLock);
-        else
-            lock_ReleaseWrite(&cm_scacheLock);
-
-        lock_ObtainWrite(&scp->rw);
-        if (scp->flags & CM_SCACHEFLAG_DELETED)
-            deleted = 1;
-
-        if (refCount == 0 && deleted) {
-            lock_ObtainWrite(&cm_scacheLock);
-            cm_RecycleSCache(scp, 0);
-            if (lockstate != OSI_RWLOCK_WRITEHELD)
-                lock_ConvertWToR(&cm_scacheLock);
-        } else {
-            if (lockstate != OSI_RWLOCK_WRITEHELD)
-                lock_ObtainRead(&cm_scacheLock);
-            else
-                lock_ObtainWrite(&cm_scacheLock);
-        }
-        lock_ReleaseWrite(&scp->rw);
-    }
 }
 
 #ifdef DEBUG_REFCOUNT
@@ -2151,19 +2269,6 @@ void cm_ReleaseSCache(cm_scache_t *scp)
     afsi_log("%s:%d cm_ReleaseSCache scp 0x%p ref %d", file, line, scp, refCount);
 #endif
     lock_ReleaseRead(&cm_scacheLock);
-
-    if (scp->flags & CM_SCACHEFLAG_DELETED) {
-        int deleted = 0;
-        lock_ObtainWrite(&scp->rw);
-        if (scp->flags & CM_SCACHEFLAG_DELETED)
-            deleted = 1;
-        if (deleted) {
-            lock_ObtainWrite(&cm_scacheLock);
-            cm_RecycleSCache(scp, 0);
-            lock_ReleaseWrite(&cm_scacheLock);
-        }
-        lock_ReleaseWrite(&scp->rw);
-    }
 }
 
 /* just look for the scp entry to get filetype */