Windows: improved idle dead time handling
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
index 709a611..51c0496 100644 (file)
@@ -118,6 +118,11 @@ RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRed
     MEMORYSTATUSEX memStatus;
     DWORD maxMemoryCacheSize;
 
+#if 0
+    /*
+     * For now disable the memory extent interface because there
+     * have been reports of data corruption.
+     */
     memStatus.dwLength = sizeof(memStatus);
     if (GlobalMemoryStatusEx(&memStatus)) {
         /*
@@ -136,6 +141,9 @@ RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRed
          */
         maxMemoryCacheSize = 65536;
     }
+#else
+    maxMemoryCacheSize = 0;
+#endif
 
     *pRedirInitInfoLen = (DWORD) (sizeof(AFSRedirectorInitInfo) + (cm_CachePathLen + TempPathLen) * sizeof(WCHAR));
     *ppRedirInitInfo = (AFSRedirectorInitInfo *)malloc(*pRedirInitInfoLen);
@@ -282,8 +290,12 @@ RDR_FlagScpInUse( IN cm_scache_t *scp, IN BOOL bLocked )
 }
 
 /*
- * Obtain the status information for the specified object and
- *
+ * Obtain the status information for the specified object using
+ * an inline bulk status rpc.  cm_BPlusDirEnumBulkStatOne() will
+ * obtain current status for the directory object, the object
+ * which is the focus of the inquiry and as many other objects
+ * in the directory for which there are not callbacks registered
+ * since we are likely to be asked for other objects in the directory.
  */
 static afs_uint32
 RDR_BulkStatLookup( cm_scache_t *dscp,
@@ -308,7 +320,6 @@ RDR_BulkStatLookup( cm_scache_t *dscp,
                   code);
     }
 
-
     if (enump)
     {
         code = cm_BPlusDirEnumBulkStatOne(enump, scp);
@@ -328,7 +339,7 @@ RDR_BulkStatLookup( cm_scache_t *dscp,
 #define RDR_POP_WOW64              0x04
 #define RDR_POP_NO_GETSTATUS       0x08
 
-afs_uint32
+static afs_uint32
 RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                           IN  DWORD             dwMaxEntryLength,
                           IN  cm_scache_t     * dscp,
@@ -338,6 +349,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                           IN  wchar_t         * name,
                           IN  wchar_t         * shortName,
                           IN  DWORD             dwFlags,
+                          IN  afs_uint32        cmError,
                           OUT AFSDirEnumEntry **ppNextEntry,
                           OUT DWORD           * pdwRemainingLength)
 {
@@ -403,7 +415,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                 lock_ReleaseWrite(&scp->rw);
                 code = RDR_BulkStatLookup(dscp, scp, userp, reqp);
                 if (code) {
-                    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry RXR_BulkStatLookup failed for scp=0x%p code=0x%x",
+                    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry RDR_BulkStatLookup failed for scp=0x%p code=0x%x",
                              scp, code);
                     return code;
                 }
@@ -417,9 +429,11 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                     bMustFake = TRUE;
             }
         }
-
     }
 
+    /* Populate the error code */
+    smb_MapNTError(cmError, &pCurrentEntry->NTStatus, TRUE);
+
     /* Populate the real or fake data */
     pCurrentEntry->FileId.Cell = scp->fid.cell;
     pCurrentEntry->FileId.Volume = scp->fid.volume;
@@ -498,8 +512,8 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
     wcsncpy(wname, name, len);
     pCurrentEntry->FileNameLength = (ULONG)(sizeof(WCHAR) * len);
 
-    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry scp=0x%p fileType=%d",
-              scp, scp->fileType);
+    osi_Log3(afsd_logp, "RDR_PopulateCurrentEntry scp=0x%p fileType=%d dv=%u",
+              scp, scp->fileType, (afs_uint32)scp->dataVersion);
 
     if (!(dwFlags & RDR_POP_NO_GETSTATUS))
         cm_SyncOpDone( scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
@@ -620,7 +634,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
     return code;
 }
 
-afs_uint32
+static afs_uint32
 RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
                                IN  DWORD             dwMaxEntryLength,
                                IN  cm_scache_t     * dscp,
@@ -630,6 +644,7 @@ RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
                                IN  wchar_t         * name,
                                IN  wchar_t         * shortName,
                                IN  DWORD             dwFlags,
+                               IN  afs_uint32        cmError,
                                OUT AFSDirEnumEntry **ppNextEntry,
                                OUT DWORD           * pdwRemainingLength)
 {
@@ -661,6 +676,10 @@ RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
 
     dwEntryLength = sizeof(AFSDirEnumEntry);
 
+    /* Populate the error code */
+    smb_MapNTError(cmError, &pCurrentEntry->NTStatus, TRUE);
+
+    /* Populate the fake data */
     pCurrentEntry->FileId.Cell = fidp->cell;
     pCurrentEntry->FileId.Volume = fidp->volume;
     pCurrentEntry->FileId.Vnode = fidp->vnode;
@@ -809,16 +828,20 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
         return;
     }
 
+    osi_Log1(afsd_logp, "RDR_EnumerateDirectory dv=%u", (afs_uint32)dscp->dataVersion);
+
     /*
      * If there is no enumeration handle, then this is a new query
-     * and we must perform an enumeration for the specified object
+     * and we must perform an enumeration for the specified object.
      */
     if (QueryCB->EnumHandle == (ULONG_PTR)NULL) {
         cm_dirOp_t    dirop;
 
         code = cm_BeginDirOp(dscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
         if (code == 0) {
-            code = cm_BPlusDirEnumerate(dscp, userp, &req, TRUE, NULL, !bSkipStatus, &enump);
+            code = cm_BPlusDirEnumerate(dscp, userp, &req,
+                                        TRUE /* dir locked */, NULL /* no mask */,
+                                        TRUE /* fetch status? */, &enump);
             if (code) {
                 osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumerate failure code=0x%x",
                           code);
@@ -832,43 +855,56 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
         enump = (cm_direnum_t *)QueryCB->EnumHandle;
     }
 
-    if (enump && ResultBufferLength) {
-        cm_direnum_entry_t * entryp = NULL;
+    if (enump) {
+        if (ResultBufferLength == 0) {
+            code = cm_BPlusDirEnumBulkStat(enump);
+            if (code) {
+                osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumBulkStat failure code=0x%x",
+                          code);
+            }
+        } else {
+            cm_direnum_entry_t * entryp = NULL;
+
+            pDirEnumResp->SnapshotDataVersion.QuadPart = enump->dataVersion;
 
-      getnextentry:
-        if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
-            osi_Log0(afsd_logp, "RDR_EnumerateDirectory out of space, returning");
-            goto outofspace;
-        }
+          getnextentry:
+            if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
+                osi_Log0(afsd_logp, "RDR_EnumerateDirectory out of space, returning");
+                goto outofspace;
+            }
 
-        code = cm_BPlusDirNextEnumEntry(enump, &entryp);
+            code = cm_BPlusDirNextEnumEntry(enump, &entryp);
 
-        if ((code == 0 || code == CM_ERROR_STOPNOW) && entryp) {
-            cm_scache_t *scp;
-            int stopnow = (code == CM_ERROR_STOPNOW);
+            if ((code == 0 || code == CM_ERROR_STOPNOW) && entryp) {
+                cm_scache_t *scp = NULL;
+                int stopnow = (code == CM_ERROR_STOPNOW);
 
-            if ( !wcscmp(L".", entryp->name) || !wcscmp(L"..", entryp->name) ) {
-                osi_Log0(afsd_logp, "RDR_EnumerateDirectory skipping . or ..");
-                if (stopnow)
-                    goto outofspace;
-                goto getnextentry;
-            }
+                if ( !wcscmp(L".", entryp->name) || !wcscmp(L"..", entryp->name) ) {
+                    osi_Log0(afsd_logp, "RDR_EnumerateDirectory skipping . or ..");
+                    if (stopnow)
+                        goto outofspace;
+                    goto getnextentry;
+                }
 
-            if ( FALSE /* bSkipStatus */) {
-                scp = cm_FindSCache(&entryp->fid);
-                code = 0;
-            } else {
-                code = cm_GetSCache(&entryp->fid, &scp, userp, &req);
-            }
+                if (bSkipStatus) {
+                    code = cm_GetSCache(&entryp->fid, &scp, userp, &req);
+                    if (code) {
+                        osi_Log5(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure cell %u vol %u vnode %u uniq %u code=0x%x",
+                                 entryp->fid.cell, entryp->fid.volume, entryp->fid.vnode, entryp->fid.unique, code);
+                    }
+                } else {
+                    code = entryp->errorCode;
+                    scp = code ? NULL : cm_FindSCache(&entryp->fid);
+                }
 
-            if (!code) {
                 if (scp) {
-                    code = RDR_PopulateCurrentEntry(pCurrentEntry, dwMaxEntryLength,
+                    code = RDR_PopulateCurrentEntry( pCurrentEntry, dwMaxEntryLength,
                                                      dscp, scp, userp, &req,
                                                      entryp->name,
                                                      cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
                                                      (bWow64 ? RDR_POP_WOW64 : 0) |
                                                      (bSkipStatus ? RDR_POP_NO_GETSTATUS : 0),
+                                                     code,
                                                      &pCurrentEntry, &dwMaxEntryLength);
                     cm_ReleaseSCache(scp);
                 } else {
@@ -877,28 +913,16 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
                                                           entryp->name,
                                                           cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
                                                           (bWow64 ? RDR_POP_WOW64 : 0),
+                                                          code,
                                                           &pCurrentEntry, &dwMaxEntryLength);
                 }
                 if (stopnow)
                     goto outofspace;
                 goto getnextentry;
-            } else {
-                osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure scp=0x%p code=0x%x",
-                          scp, code);
-                if (stopnow)
-                    goto outofspace;
-                goto getnextentry;
             }
         }
     }
 
-    if (enump && ResultBufferLength == 0) {
-        code = cm_BPlusDirEnumBulkStat(enump);
-        if (code) {
-            osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumBulkStat failure code=0x%x",
-                      code);
-        }
-    }
   outofspace:
 
     if (code || enump->next == enump->count || ResultBufferLength == 0) {
@@ -920,6 +944,7 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwMaxEntryLength;
 
         pDirEnumResp->EnumHandle = (ULONG_PTR) enump;
+        pDirEnumResp->CurrentDataVersion.QuadPart = dscp->dataVersion;
     }
 
     if (dscp)
@@ -940,8 +965,9 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
                         IN DWORD    ResultBufferLength,
                         IN OUT AFSCommResult **ResultCB)
 {
+    AFSFileEvalResultCB *pEvalResultCB = NULL;
     AFSDirEnumEntry * pCurrentEntry;
-    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
     afs_uint32  code = 0;
     cm_scache_t * scp = NULL;
     cm_scache_t * dscp = NULL;
@@ -981,9 +1007,13 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
     }
 
     memset(*ResultCB, 0, size);
-    (*ResultCB)->ResultBufferLength = ResultBufferLength;
-    if (ResultBufferLength)
-        pCurrentEntry = (AFSDirEnumEntry *)&(*ResultCB)->ResultData;
+    (*ResultCB)->ResultBufferLength = 0;
+    dwRemaining = ResultBufferLength;
+    if (ResultBufferLength >= sizeof( AFSFileEvalResultCB)) {
+        pEvalResultCB = (AFSFileEvalResultCB *)&(*ResultCB)->ResultData;
+        pCurrentEntry = &pEvalResultCB->DirEnum;
+        dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
+    }
 
     if (ParentID.Cell != 0) {
         parentFid.cell   = ParentID.Cell;
@@ -996,6 +1026,8 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
         if (code) {
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
             (*ResultCB)->ResultStatus = status;
+            if ( status == STATUS_INVALID_HANDLE)
+                status = STATUS_OBJECT_PATH_INVALID;
             osi_Log2(afsd_logp, "RDR_EvaluateNodeByName cm_GetSCache parentFID failure code=0x%x status=0x%x",
                       code, status);
             free(wszName);
@@ -1064,12 +1096,12 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
             shortName[0] = '\0';
         }
 
-        code = RDR_PopulateCurrentEntry(pCurrentEntry, ResultBufferLength,
+        code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
                                         dscp, scp, userp, &req,
                                         FileName, shortName,
                                         (bWow64 ? RDR_POP_WOW64 : 0) |
                                         (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
-                                        NULL, &dwRemaining);
+                                        0, NULL, &dwRemaining);
         if (bHoldFid)
             RDR_FlagScpInUse( scp, FALSE );
         cm_ReleaseSCache(scp);
@@ -1080,6 +1112,7 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
             osi_Log2(afsd_logp, "RDR_EvaluateNodeByName FAILURE code=0x%x status=0x%x",
                       code, status);
         } else {
+            pEvalResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
             (*ResultCB)->ResultStatus = STATUS_SUCCESS;
             (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
             osi_Log0(afsd_logp, "RDR_EvaluateNodeByName SUCCESS");
@@ -1109,8 +1142,9 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
                       IN DWORD     ResultBufferLength,
                       IN OUT AFSCommResult **ResultCB)
 {
-    AFSDirEnumEntry * pCurrentEntry;
-    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    AFSFileEvalResultCB *pEvalResultCB = NULL;
+    AFSDirEnumEntry * pCurrentEntry = NULL;
+    size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
     afs_uint32  code = 0;
     cm_scache_t * scp = NULL;
     cm_scache_t * dscp = NULL;
@@ -1132,10 +1166,13 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
     }
 
     memset(*ResultCB, 0, size);
-    (*ResultCB)->ResultBufferLength = ResultBufferLength;
+    (*ResultCB)->ResultBufferLength = 0;
     dwRemaining = ResultBufferLength;
-    if (ResultBufferLength)
-        pCurrentEntry = (AFSDirEnumEntry *)&(*ResultCB)->ResultData;
+    if (ResultBufferLength >= sizeof( AFSFileEvalResultCB)) {
+        pEvalResultCB = (AFSFileEvalResultCB *)&(*ResultCB)->ResultData;
+        pCurrentEntry = &pEvalResultCB->DirEnum;
+        dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
+    }
 
     RDR_InitReq(&req);
     if ( bWow64 )
@@ -1168,6 +1205,8 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
         if (code) {
             cm_ReleaseSCache(scp);
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            if ( status == STATUS_INVALID_HANDLE)
+                status = STATUS_OBJECT_PATH_INVALID;
             (*ResultCB)->ResultStatus = status;
             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
                       code, status);
@@ -1182,6 +1221,8 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
         if (code) {
             cm_ReleaseSCache(scp);
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            if ( status == STATUS_INVALID_HANDLE)
+                status = STATUS_OBJECT_PATH_INVALID;
             (*ResultCB)->ResultStatus = status;
             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
                       code, status);
@@ -1219,11 +1260,11 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
         return;
     }
 
-    code = RDR_PopulateCurrentEntry(pCurrentEntry, ResultBufferLength,
+    code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
                                     dscp, scp, userp, &req, NULL, NULL,
                                     (bWow64 ? RDR_POP_WOW64 : 0) |
                                     (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
-                                    NULL, &dwRemaining);
+                                    0, NULL, &dwRemaining);
 
     if (bHoldFid)
         RDR_FlagScpInUse( scp, FALSE );
@@ -1236,6 +1277,8 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
         osi_Log2(afsd_logp, "RDR_EvaluateNodeByID FAILURE code=0x%x status=0x%x",
                  code, status);
     } else {
+        pEvalResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
+
         (*ResultCB)->ResultStatus = STATUS_SUCCESS;
         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID SUCCESS");
@@ -1297,6 +1340,8 @@ RDR_CreateFileEntry( IN cm_user_t *userp,
     if (code) {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
         (*ResultCB)->ResultStatus = status;
+        if ( status == STATUS_INVALID_HANDLE)
+            status = STATUS_OBJECT_PATH_INVALID;
         osi_Log2(afsd_logp, "RDR_CreateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
                   code, status);
         return;
@@ -1395,7 +1440,7 @@ RDR_CreateFileEntry( IN cm_user_t *userp,
         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
                                         dscp, scp, userp, &req, FileName, shortName,
                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
-                                        NULL, &dwRemaining);
+                                        0, NULL, &dwRemaining);
 
         if (bHoldFid)
             RDR_FlagScpInUse( scp, FALSE );
@@ -1470,6 +1515,8 @@ RDR_UpdateFileEntry( IN cm_user_t *userp,
     if (code) {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
         (*ResultCB)->ResultStatus = status;
+        if ( status == STATUS_INVALID_HANDLE)
+            status = STATUS_OBJECT_PATH_INVALID;
         osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
                   code, status);
         return;
@@ -1600,10 +1647,12 @@ RDR_UpdateFileEntry( IN cm_user_t *userp,
 
         pResultCB = (AFSFileUpdateResultCB *)(*ResultCB)->ResultData;
 
+        pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
+
         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
                                         dscp, scp, userp, &req, NULL, NULL,
                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
-                                        NULL, &dwRemaining);
+                                        0, NULL, &dwRemaining);
         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
         osi_Log0(afsd_logp, "RDR_UpdateFileEntry SUCCESS");
     } else {
@@ -1632,7 +1681,8 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
                       IN DWORD ResultBufferLength,
                       IN OUT AFSCommResult **ResultCB)
 {
-    size_t size = sizeof(AFSCommResult);
+    AFSFileCleanupResultCB *pResultCB = NULL;
+    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
     cm_fid_t            Fid;
     cm_fid_t            parentFid;
     afs_uint32          code = 0;
@@ -1681,6 +1731,8 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
         code = cm_GetSCache(&parentFid, &dscp, userp, &req);
         if (code) {
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            if ( status == STATUS_INVALID_HANDLE)
+                status = STATUS_OBJECT_PATH_INVALID;
             (*ResultCB)->ResultStatus = status;
             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
                      code, status);
@@ -1955,14 +2007,21 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
             code = cm_Unlink(dscp, NULL, FileName, userp, &req);
     }
 
+    if ( ResultBufferLength >=  sizeof( AFSFileCleanupResultCB))
+    {
+        (*ResultCB)->ResultBufferLength = sizeof( AFSFileCleanupResultCB);
+        pResultCB = (AFSFileCleanupResultCB *)&(*ResultCB)->ResultData;
+        pResultCB->ParentDataVersion.QuadPart = dscp ? dscp->dataVersion : 0;
+    } else {
+        (*ResultCB)->ResultBufferLength = 0;
+    }
+
     if (code == 0) {
         (*ResultCB)->ResultStatus = 0;
-        (*ResultCB)->ResultBufferLength = 0;
         osi_Log0(afsd_logp, "RDR_CleanupFileEntry SUCCESS");
     } else {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
         (*ResultCB)->ResultStatus = status;
-        (*ResultCB)->ResultBufferLength = 0;
         osi_Log2(afsd_logp, "RDR_CleanupFileEntry FAILURE code=0x%x status=0x%x",
                   code, status);
     }
@@ -2032,6 +2091,8 @@ RDR_DeleteFileEntry( IN cm_user_t *userp,
     code = cm_GetSCache(&parentFid, &dscp, userp, &req);
     if (code) {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        if ( status == STATUS_INVALID_HANDLE)
+            status = STATUS_OBJECT_PATH_INVALID;
         (*ResultCB)->ResultStatus = status;
         osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
                   code, status);
@@ -2165,8 +2226,12 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
     DWORD                  TargetFileNameLength = pRenameCB->TargetNameLength;
     cm_fid_t               SourceParentFid;
     cm_fid_t               TargetParentFid;
+    cm_fid_t              SourceFid;
+    cm_fid_t              OrigTargetFid = {0,0,0,0,0};
+    cm_fid_t              TargetFid;
     cm_scache_t *          oldDscp;
     cm_scache_t *          newDscp;
+    cm_dirOp_t dirop;
     wchar_t                shortName[13];
     wchar_t                SourceFileName[260];
     wchar_t                TargetFileName[260];
@@ -2225,6 +2290,8 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
     if (code) {
         osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache source parent failed code 0x%x", code);
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        if ( status == STATUS_INVALID_HANDLE)
+            status = STATUS_OBJECT_PATH_INVALID;
         (*ResultCB)->ResultStatus = status;
         return;
     }
@@ -2235,6 +2302,8 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
     if (code) {
         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp oldDscp 0x%p failed code 0x%x", oldDscp, code);
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        if ( status == STATUS_INVALID_HANDLE)
+            status = STATUS_OBJECT_PATH_INVALID;
         (*ResultCB)->ResultStatus = status;
         lock_ReleaseWrite(&oldDscp->rw);
         cm_ReleaseSCache(oldDscp);
@@ -2286,11 +2355,17 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
         return;
     }
 
+    /* Obtain the original FID just for debugging purposes */
+    code = cm_BeginDirOp( oldDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
+    if (code == 0) {
+        code = cm_BPlusDirLookup(&dirop, SourceFileName, &SourceFid);
+        code = cm_BPlusDirLookup(&dirop, TargetFileName, &OrigTargetFid);
+        cm_EndDirOp(&dirop);
+    }
+
     code = cm_Rename( oldDscp, NULL, SourceFileName,
                       newDscp, TargetFileName, userp, &req);
     if (code == 0) {
-        cm_dirOp_t dirop;
-        cm_fid_t   targetFid;
         cm_scache_t *scp = 0;
         DWORD dwRemaining;
 
@@ -2306,7 +2381,7 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
 
         code = cm_BeginDirOp( newDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
         if (code == 0) {
-            code = cm_BPlusDirLookup(&dirop, TargetFileName, &targetFid);
+            code = cm_BPlusDirLookup(&dirop, TargetFileName, &TargetFid);
             cm_EndDirOp(&dirop);
         }
 
@@ -2320,10 +2395,10 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
         }
 
         osi_Log4(afsd_logp, "RDR_RenameFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
-                  targetFid.cell,  targetFid.volume,
-                  targetFid.vnode, targetFid.unique);
+                  TargetFid.cell,  TargetFid.volume,
+                  TargetFid.vnode, TargetFid.unique);
 
-        code = cm_GetSCache(&targetFid, &scp, userp, &req);
+        code = cm_GetSCache(&TargetFid, &scp, userp, &req);
         if (code) {
             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target failed code 0x%x", code);
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
@@ -2362,7 +2437,7 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
         RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
                                  newDscp, scp, userp, &req, TargetFileName, shortName,
                                  RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
-                                 NULL, &dwRemaining);
+                                 0, NULL, &dwRemaining);
         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
         cm_ReleaseSCache(scp);
 
@@ -2962,7 +3037,7 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
              * we need to re-queue this extent fetch.
              */
             force_retry = 1;
-            continue;
+            break;
         }
 
         if (!rwheld) {
@@ -2972,9 +3047,6 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
 
         code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
         if (code == 0) {
-            if (bufp->flags & CM_BUF_DIRTY)
-                cm_BufWrite(scp, &bufp->offset, cm_chunkSize, CM_BUF_WRITE_SCP_LOCKED, userp, reqp);
-
             if (!(bufp->qFlags & CM_BUF_QREDIR)) {
 #ifdef VALIDATE_CHECK_SUM
 #ifdef ODS_DEBUG
@@ -2982,6 +3054,9 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
                 char dbgstr[1024];
 #endif
 #endif
+                if (bufp->flags & CM_BUF_DIRTY)
+                    cm_BufWrite(scp, &bufp->offset, cm_data.buf_blockSize, CM_BUF_WRITE_SCP_LOCKED, userp, reqp);
+
                 lock_ObtainWrite(&buf_globalLock);
                 if (!(bufp->flags & CM_BUF_DIRTY) &&
                     bufp->cmFlags == 0 &&
@@ -3063,6 +3138,7 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
                  * non-fatal errors.  re-queue the exent
                  */
                 code = CM_ERROR_RETRY;
+                force_retry = 1;
             }
         }
 
@@ -3373,6 +3449,7 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
     cm_req_t    req;
     int         dirty = 0;
     int         released = 0;
+    int         deleted = 0;
     DWORD       status;
 #ifdef ODS_DEBUG
 #ifdef VALIDATE_CHECK_SUM
@@ -3412,13 +3489,20 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
                   code, status);
     }
 
+    deleted = scp && (scp->flags & CM_SCACHEFLAG_DELETED);
+
     /*
      * We do not stop processing as a result of being unable to find the cm_scache object.
      * If this occurs something really bad has happened since the cm_scache object must have
      * been recycled while extents were held by the redirector.  However, we will be resilient
      * and carry on without it.
+     *
+     * If the file is known to be deleted, there is no point attempting to ask the
+     * file server about it or update the attributes.
      */
-    if (scp && ReleaseExtentsCB->AllocationSize.QuadPart != scp->length.QuadPart) {
+    if (scp && ReleaseExtentsCB->AllocationSize.QuadPart != scp->length.QuadPart &&
+        !deleted)
+    {
         cm_attr_t setAttr;
 
         memset(&setAttr, 0, sizeof(cm_attr_t));
@@ -3881,6 +3965,7 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
         cm_scache_t *    scp = NULL;
         int              dirty = 0;
         int              released = 0;
+        int              deleted = 0;
         char * p;
 
         userp = RDR_UserFromAuthGroup( &pFileCB->AuthGroup);
@@ -3913,6 +3998,8 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
              */
         }
 
+        deleted = scp && (scp->flags & CM_SCACHEFLAG_DELETED);
+
         /* if the scp was not found, do not perform the length check */
         if (scp && (pFileCB->AllocationSize.QuadPart != scp->length.QuadPart)) {
             cm_attr_t setAttr;
@@ -4050,8 +4137,8 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
 #endif
                             }
 
-                            if ( (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_DIRTY) ||
-                                 (pExtent->Flags & AFS_EXTENT_FLAG_DIRTY) )
+                            if ((ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_DIRTY) ||
+                                (pExtent->Flags & AFS_EXTENT_FLAG_DIRTY))
                             {
 #ifdef VALIDATE_CHECK_SUM
                                 if ( buf_ValidateCheckSum(bufp) ) {
@@ -4089,8 +4176,10 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
                                                       pExtent->CacheOffset.HighPart,
                                                       pExtent->CacheOffset.LowPart);
 
-                                            buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
-                                            dirty++;
+                                            if (!deleted) {
+                                                buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                                dirty++;
+                                            }
                                         } else {
 #ifdef ODS_DEBUG
                                             snprintf(dbgstr, 1024,
@@ -4116,8 +4205,10 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
                                     }
                                 }
 #else /* !VALIDATE_CHECK_SUM */
-                                buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
-                                dirty++;
+                                if (!deleted) {
+                                    buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                    dirty++;
+                                }
 #ifdef ODS_DEBUG
                                 snprintf(dbgstr, 1024,
                                           "RDR_ProcessReleaseFileExtentsResult dirty! vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
@@ -4135,7 +4226,7 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
 #ifdef ODS_DEBUG
                                 HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
 #endif
-                                if ( !buf_ValidateCheckSum(bufp) ) {
+                                if (!buf_ValidateCheckSum(bufp) ) {
                                     buf_ComputeCheckSum(bufp);
 #ifdef ODS_DEBUG
                                     HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
@@ -4159,8 +4250,10 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
 #ifdef DEBUG
                                     DebugBreak();
 #endif
-                                    buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
-                                    dirty++;
+                                    if (!deleted) {
+                                        buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                        dirty++;
+                                    }
                                 } else {
                                     buf_ComputeCheckSum(bufp);
 #ifdef ODS_DEBUG
@@ -4999,7 +5092,7 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
                                         &volStat, &Name, &OfflineMsg, &MOTD);
            rx_PutConnection(rxconnp);
 
-       } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
+       } while (cm_Analyze(connp, userp, &req, &scp->fid, 0, NULL, NULL, NULL, code));
        code = cm_MapRPCError(code, &req);
         if (code == 0) {
             pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;