Windows: cm_GetNewSCache init mpDV to BAD
[openafs.git] / src / WINNT / afsd / cm_scache.c
index 31afbb0..1c07b12 100644 (file)
@@ -66,11 +66,8 @@ 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);
     }
 }
@@ -173,17 +170,19 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
          !cm_accessPerFileCheck) {
         cm_volume_t *volp = cm_GetVolumeByFID(&scp->fid);
 
-        if (!(volp && (volp->flags & CM_VOLUMEFLAG_DFS_VOLUME)))
-            cm_EAccesClearParentEntries(&fid);
-        cm_PutVolume(volp);
+        if (volp) {
+            if (!(volp->flags & CM_VOLUMEFLAG_DFS_VOLUME))
+                cm_EAccesClearParentEntries(&fid);
+
+            cm_PutVolume(volp);
+        }
     }
 
     /* invalidate so next merge works fine;
      * 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
@@ -218,6 +217,7 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
     scp->mask = 0;
 
     /* discard symlink info */
+    scp->mpDataVersion = CM_SCACHE_VERSION_BAD;
     scp->mountPointStringp[0] = '\0';
     memset(&scp->mountRootFid, 0, sizeof(cm_fid_t));
     memset(&scp->dotdotFid, 0, sizeof(cm_fid_t));
@@ -387,7 +387,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));
@@ -403,10 +403,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;
@@ -635,7 +635,6 @@ cm_ShutdownSCache(void)
         }
         scp->cbExpires = 0;
         scp->cbIssued = 0;
-        _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_CALLBACK);
         lock_ReleaseWrite(&scp->rw);
 
 #ifdef USE_BPLUS
@@ -698,7 +697,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;
@@ -1168,6 +1167,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);
 
@@ -1411,15 +1412,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);
@@ -1435,10 +1436,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;
@@ -1591,7 +1592,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);
     }
@@ -1606,6 +1608,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.
  *
@@ -1619,7 +1632,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)
@@ -1670,6 +1683,12 @@ void cm_MergeStatus(cm_scache_t *dscp,
     }
 #endif /* AFS_FREELANCE_CLIENT */
 
+    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) {
         switch (statusp->errorCode) {
         case EACCES:
@@ -1683,7 +1702,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;
@@ -1762,8 +1781,19 @@ void cm_MergeStatus(cm_scache_t *dscp,
             goto done;
     }
 
-    if (cm_readonlyVolumeVersioning)
+    /*
+     * The first field of the volsync parameter is supposed to be the
+     * volume creation date.  Unfortunately, pre-OpenAFS 1.4.11 and 1.6.0
+     * file servers do not populate the VolSync structure for BulkStat and
+     * InlineBulkStat RPCs.  As a result, the volume creation date is not
+     * trustworthy when status is obtained via [Inline]BulkStatus RPCs.
+     * If cm_readonlyVolumeVersioning is set, it is assumed that all file
+     * servers populate the VolSync structure at all times.
+     */
+    if (cm_readonlyVolumeVersioning || !(flags & CM_MERGEFLAG_BULKSTAT))
         scp->volumeCreationDate = volsyncp->spare1;       /* volume creation date */
+    else
+        scp->volumeCreationDate = 0;
 
     scp->serverModTime = statusp->ServerModTime;
 
@@ -1880,15 +1910,7 @@ void cm_MergeStatus(cm_scache_t *dscp,
         lock_ReleaseWrite(&buf_globalLock);
     }
 
-    /*
-     * If the dataVersion has changed, the mountPointStringp must be cleared
-     * in order to force a re-evaluation by cm_HandleLink().  The Windows CM
-     * does not update a mountpoint or symlink by altering the contents of
-     * the file data; but the Unix CM does.
-     */
     if (scp->dataVersion != dataVersion && !(flags & CM_MERGEFLAG_FETCHDATA)) {
-        scp->mountPointStringp[0] = '\0';
-
         osi_Log5(afsd_logp, "cm_MergeStatus data version change scp 0x%p cell %u vol %u vn %u uniq %u",
                  scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
 
@@ -1996,6 +2018,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
@@ -2015,17 +2039,13 @@ void cm_DiscardSCache(cm_scache_t *scp)
     }
     scp->cbExpires = 0;
     scp->cbIssued = 0;
-    scp->volumeCreationDate = 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);
 
     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';
 }
 
 void cm_AFSFidFromFid(AFSFid *afsFidp, cm_fid_t *fidp)
@@ -2232,10 +2252,10 @@ int cm_DumpSCache(FILE *outputFile, char *cookie, int lock)
         }
         sprintf(output,
                 "%s scp=0x%p, fid (cell=%d, volume=%d, vnode=%d, unique=%d) type=%d dv=%I64d len=0x%I64x "
-                "mp='%s' Locks (server=0x%x shared=%d excl=%d clnt=%d) fsLockCount=%d linkCount=%d anyAccess=0x%x "
+                "mpDV=%I64d mp='%s' Locks (server=0x%x shared=%d excl=%d clnt=%d) fsLockCount=%d linkCount=%d anyAccess=0x%x "
                 "flags=0x%x cbServer='%s' cbExpires='%s' volumeCreationDate='%s' refCount=%u\r\n",
                 cookie, scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
-                scp->fileType, scp->dataVersion, scp->length.QuadPart, scp->mountPointStringp,
+                scp->fileType, scp->dataVersion, scp->length.QuadPart, scp->mpDataVersion, scp->mountPointStringp,
                 scp->serverLock, scp->sharedLocks, scp->exclusiveLocks, scp->clientLocks, scp->fsLockCount,
                 scp->linkCount, scp->anyAccess, scp->flags, srvStr ? srvStr : "<none>", cbt ? cbt : "<none>",
                 cdrot ? cdrot : "<none>", scp->refCount);