Windows: refactor afs status cloning and clone when fs fetchdata bug detected
authorJeffrey Altman <jaltman@secure-endpoints.com>
Tue, 13 Oct 2009 01:57:52 +0000 (21:57 -0400)
committerJeffrey Altman <jaltman|account-1000011@unknown>
Wed, 14 Oct 2009 18:04:32 +0000 (11:04 -0700)
When the file server fetchdata invalid length bug is detected the
cache manager must fake the AFS Status info for the file as well
as the AFSVolSync info.   Otherwise, the merge status is incorrect.

LICENSE MIT

Reviewed-on: http://gerrit.openafs.org/651
Tested-by: Jeffrey Altman <jaltman@openafs.org>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>

src/WINNT/afsd/cm_dcache.c

index 94010d9..d15ecde 100644 (file)
@@ -1383,6 +1383,60 @@ void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore, long code, int scp_locked)
     biop->bufListEndp = NULL;
 }   
 
+static int
+cm_CloneStatus(cm_scache_t *scp, cm_user_t *userp, int scp_locked,
+               AFSFetchStatus *afsStatusp, AFSVolSync *volSyncp)
+{
+    // setup the status based upon the scp data
+    afsStatusp->InterfaceVersion = 0x1;
+    switch (scp->fileType) {
+    case CM_SCACHETYPE_FILE:
+        afsStatusp->FileType = File;
+        break;
+    case CM_SCACHETYPE_DIRECTORY:
+        afsStatusp->FileType = Directory;
+        break;
+    case CM_SCACHETYPE_MOUNTPOINT:
+        afsStatusp->FileType = SymbolicLink;
+        break;
+    case CM_SCACHETYPE_SYMLINK:
+    case CM_SCACHETYPE_DFSLINK:
+        afsStatusp->FileType = SymbolicLink;
+        break;
+    default:
+        afsStatusp->FileType = -1;    /* an invalid value */
+    }
+    afsStatusp->LinkCount = scp->linkCount;
+    afsStatusp->Length = scp->length.LowPart;
+    afsStatusp->DataVersion = (afs_uint32)(scp->dataVersion & MAX_AFS_UINT32);
+    afsStatusp->Author = 0x1;
+    afsStatusp->Owner = scp->owner;
+    if (!scp_locked) {
+        lock_ObtainWrite(&scp->rw);
+        scp_locked = 1;
+    }
+    if (cm_FindACLCache(scp, userp, &afsStatusp->CallerAccess))
+        afsStatusp->CallerAccess = scp->anyAccess;
+    afsStatusp->AnonymousAccess = scp->anyAccess;
+    afsStatusp->UnixModeBits = scp->unixModeBits;
+    afsStatusp->ParentVnode = scp->parentVnode;
+    afsStatusp->ParentUnique = scp->parentUnique;
+    afsStatusp->ResidencyMask = 0;
+    afsStatusp->ClientModTime = scp->clientModTime;
+    afsStatusp->ServerModTime = scp->serverModTime;
+    afsStatusp->Group = scp->group;
+    afsStatusp->SyncCounter = 0;
+    afsStatusp->dataVersionHigh = (afs_uint32)(scp->dataVersion >> 32);
+    afsStatusp->lockCount = 0;
+    afsStatusp->Length_hi = scp->length.HighPart;
+    afsStatusp->errorCode = 0;
+
+    memset(volSyncp, 0, sizeof(AFSVolSync));
+    volSyncp->spare1 = scp->lastUpdateRO;
+
+    return scp_locked;
+}
+
 /* Fetch a buffer.  Called with scp locked.
  * The scp is locked on return.
  */
@@ -1515,7 +1569,8 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp
         afsStatus.lockCount = 0;
         afsStatus.Length_hi = 0;
         afsStatus.errorCode = 0;
-       
+       memset(&volSync, 0, sizeof(volSync));
+
         // once we're done setting up the status info,
         // we just fill the buffer pages with fakedata
         // from cm_FakeRootDir. Extra pages are set to
@@ -1564,47 +1619,8 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp
                  scp, biod.offset.HighPart, biod.offset.LowPart,
                  scp->length.HighPart, scp->length.LowPart);
 
-        // setup the status based upon the scp data
-        afsStatus.InterfaceVersion = 0x1;
-        switch (scp->fileType) {
-        case CM_SCACHETYPE_FILE:
-            afsStatus.FileType = File;
-            break;
-        case CM_SCACHETYPE_DIRECTORY:
-            afsStatus.FileType = Directory;
-            break;
-        case CM_SCACHETYPE_MOUNTPOINT:
-            afsStatus.FileType = SymbolicLink;
-            break;
-        case CM_SCACHETYPE_SYMLINK:
-        case CM_SCACHETYPE_DFSLINK:
-            afsStatus.FileType = SymbolicLink;
-            break;
-        default:
-            afsStatus.FileType = -1;    /* an invalid value */
-        }
-        afsStatus.LinkCount = scp->linkCount;
-        afsStatus.Length = scp->length.LowPart;
-        afsStatus.DataVersion = (afs_uint32)(scp->dataVersion & MAX_AFS_UINT32);
-        afsStatus.Author = 0x1;
-        afsStatus.Owner = scp->owner;
-        lock_ObtainWrite(&scp->rw);
-        scp_locked = 1;
-        if (cm_FindACLCache(scp, userp, &afsStatus.CallerAccess))
-             afsStatus.CallerAccess = scp->anyAccess;
-        afsStatus.AnonymousAccess = scp->anyAccess;
-        afsStatus.UnixModeBits = scp->unixModeBits;
-        afsStatus.ParentVnode = scp->parentVnode;
-        afsStatus.ParentUnique = scp->parentUnique;
-        afsStatus.ResidencyMask = 0;
-        afsStatus.ClientModTime = scp->clientModTime;
-        afsStatus.ServerModTime = scp->serverModTime;
-        afsStatus.Group = scp->group;
-        afsStatus.SyncCounter = 0;
-        afsStatus.dataVersionHigh = (afs_uint32)(scp->dataVersion >> 32);
-        afsStatus.lockCount = 0;
-        afsStatus.Length_hi = scp->length.HighPart;
-        afsStatus.errorCode = 0;
+        /* Clone the current status info */
+        scp_locked = cm_CloneStatus(scp, userp, scp_locked, &afsStatus, &volSync);
 
         /* status info complete, fill pages with zeros */
         for (qdp = biod.bufListEndp;
@@ -1619,6 +1635,11 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp
         goto fetchingcompleted;
     }
 
+    if (scp_locked) {
+        lock_ReleaseWrite(&scp->rw);
+        scp_locked = 0;
+    }
+
     /* now make the call */
     do {
         code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
@@ -1851,10 +1872,16 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp
             osi_Log0(afsd_logp, "CALL EndCall returns RXKADUNKNOWNKEY");
 
         /* If we are avoiding a file server bug, ignore the error state */
-        if (fs_fetchdata_offset_bug && first_read && length_found == 0 && code == -451)
+        if (fs_fetchdata_offset_bug && first_read && length_found == 0 && code == -451) {
+            /* Clone the current status info and clear the error state */
+            scp_locked = cm_CloneStatus(scp, userp, scp_locked, &afsStatus, &volSync);
+            if (scp_locked) {
+                lock_ReleaseWrite(&scp->rw);
+                scp_locked = 0;
+            }
             code = 0;
         /* Prefer the error value from FetchData over rx_EndCall */
-        else if (code == 0 && code1 != 0)
+        } else if (code == 0 && code1 != 0)
             code = code1;
         osi_Log0(afsd_logp, "CALL FetchData DONE");