Windows: More RDR Garbage Collection
authorJeffrey Altman <jaltman@your-file-system.com>
Tue, 29 Jan 2013 02:12:10 +0000 (21:12 -0500)
committerJeffrey Altman <jaltman@your-file-system.com>
Sat, 2 Feb 2013 17:33:44 +0000 (09:33 -0800)
This patchset addresses the failure of AFSVolumeCB, AFSDirectoryCB,
and AFSObjectInformationCB objects to be garbage collected by the
AFSPrimaryVolumeWorker thread.  The AFSPrimaryVolumeWorker thread
is broken up into smaller pieces.

Change-Id: I54749960be8f22313ba7ee5f9f96438be6321f25
Reviewed-on: http://gerrit.openafs.org/8995
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Jeffrey Altman <jaltman@your-file-system.com>
Tested-by: Jeffrey Altman <jaltman@your-file-system.com>

src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp
src/WINNT/afsrdr/kernel/lib/AFSFcbSupport.cpp
src/WINNT/afsrdr/kernel/lib/AFSGeneric.cpp
src/WINNT/afsrdr/kernel/lib/AFSNameSupport.cpp
src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp
src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h

index 5eece7b..20f4e9e 100644 (file)
@@ -1449,23 +1449,13 @@ AFSOpenRoot( IN PIRP Irp,
         // init the volume fcb
         //
 
-        if( VolumeCB->RootFcb == NULL)
-        {
-
-            ntStatus = AFSInitRootFcb( (ULONGLONG)PsGetCurrentProcessId(),
-                                       VolumeCB);
-
-            if( !NT_SUCCESS( ntStatus))
-            {
+        ntStatus = AFSInitRootFcb( (ULONGLONG)PsGetCurrentProcessId(),
+                                   VolumeCB);
 
-                try_return( ntStatus);
-            }
-        }
-        else
+        if( !NT_SUCCESS( ntStatus))
         {
 
-            AFSAcquireExcl( VolumeCB->RootFcb->Header.Resource,
-                            TRUE);
+            try_return( ntStatus);
         }
 
         lCount = InterlockedIncrement( &VolumeCB->RootFcb->OpenReferenceCount);
index 5630ba5..eb1b25d 100644 (file)
@@ -152,10 +152,6 @@ AFSInitFcb( IN AFSDirectoryCB  *DirEntry)
 
         ExInitializeResourceLite( &pNPFcb->CcbListLock);
 
-        pFcb->Header.Resource = &pNPFcb->Resource;
-
-        pFcb->Header.PagingIoResource = &pNPFcb->PagingResource;
-
         //
         // Grab the Fcb for processing
         //
@@ -169,6 +165,10 @@ AFSInitFcb( IN AFSDirectoryCB  *DirEntry)
         AFSAcquireExcl( &pNPFcb->Resource,
                         TRUE);
 
+        pFcb->Header.Resource = &pNPFcb->Resource;
+
+        pFcb->Header.PagingIoResource = &pNPFcb->PagingResource;
+
         pFcb->NPFcb = pNPFcb;
 
         //
@@ -820,7 +820,7 @@ AFSRemoveVolume( IN AFSVolumeCB *VolumeCB)
                 AFSReleaseResource( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
             }
 
-            AFSDeleteObjectInfo( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
+            AFSDeleteObjectInfo( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
 
             ExDeleteResourceLite( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
 
@@ -946,6 +946,7 @@ AFSInitRootFcb( IN ULONGLONG ProcessID,
                        sizeof( AFSFcb));
 
         pFcb->Header.NodeByteSize = sizeof( AFSFcb);
+
         pFcb->Header.NodeTypeCode = AFS_ROOT_FCB;
 
         pNPFcb = (AFSNonPagedFcb *)AFSExAllocatePoolWithTag( NonPagedPool,
@@ -966,6 +967,7 @@ AFSInitRootFcb( IN ULONGLONG ProcessID,
                        sizeof( AFSNonPagedFcb));
 
         pNPFcb->Size = sizeof( AFSNonPagedFcb);
+
         pNPFcb->Type = AFS_NON_PAGED_FCB;
 
         //
@@ -978,6 +980,12 @@ AFSInitRootFcb( IN ULONGLONG ProcessID,
 
         ExInitializeResourceLite( &pNPFcb->Resource);
 
+        ExInitializeResourceLite( &pNPFcb->PagingResource);
+
+        ExInitializeResourceLite( &pNPFcb->SectionObjectResource);
+
+        ExInitializeResourceLite( &pNPFcb->CcbListLock);
+
         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
                       AFS_TRACE_LEVEL_VERBOSE,
                       "AFSInitRootFcb Acquiring Fcb lock %p EXCL %08lX\n",
@@ -987,10 +995,6 @@ AFSInitRootFcb( IN ULONGLONG ProcessID,
         AFSAcquireExcl( &pNPFcb->Resource,
                         TRUE);
 
-        ExInitializeResourceLite( &pNPFcb->PagingResource);
-
-        ExInitializeResourceLite( &pNPFcb->CcbListLock);
-
         pFcb->Header.Resource = &pNPFcb->Resource;
 
         pFcb->Header.PagingIoResource = &pNPFcb->PagingResource;
@@ -1001,23 +1005,77 @@ AFSInitRootFcb( IN ULONGLONG ProcessID,
         // Save the root Fcb in the VolumeCB
         //
 
-        VolumeCB->ObjectInformation.Fcb = pFcb;
+        pFcb->ObjectInformation = &VolumeCB->ObjectInformation;
 
         VolumeCB->ObjectInformation.VolumeCB = VolumeCB;
 
-        VolumeCB->RootFcb = pFcb;
+        AFSAcquireShared( &VolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock,
+                          TRUE);
+        //
+        // Swap the allocated FCB into the ObjectInformation structure if it
+        // does not already have one.
+        //
 
-        pFcb->ObjectInformation = &VolumeCB->ObjectInformation;
+        if ( InterlockedCompareExchangePointer( (PVOID *)&VolumeCB->ObjectInformation.Fcb, pFcb, NULL) != NULL)
+        {
+
+            AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
+                          AFS_TRACE_LEVEL_WARNING,
+                          "AFSInitRootFcb Raced Fcb %p pFcb %p\n",
+                          VolumeCB->ObjectInformation.Fcb,
+                          pFcb);
+
+            AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
+                          AFS_TRACE_LEVEL_VERBOSE,
+                          "AFSInitRootFcb Acquiring Fcb lock %p EXCL %08lX\n",
+                          &VolumeCB->ObjectInformation.Fcb->NPFcb->Resource,
+                          PsGetCurrentThread());
+
+            AFSReleaseResource( &VolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
+
+            AFSAcquireExcl( &VolumeCB->ObjectInformation.Fcb->NPFcb->Resource,
+                            TRUE);
+
+            try_return( ntStatus = STATUS_REPARSE);
+        }
+
+        VolumeCB->RootFcb = VolumeCB->ObjectInformation.Fcb;
+
+        AFSReleaseResource( &VolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
+
+        AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
+                      AFS_TRACE_LEVEL_VERBOSE,
+                      "AFSInitRootFcb Initialized Fcb %p\n",
+                      &VolumeCB->ObjectInformation.Fcb);
 
 try_exit:
 
-        if( !NT_SUCCESS( ntStatus))
+        if( !NT_SUCCESS( ntStatus) ||
+            ntStatus == STATUS_REPARSE)
         {
 
             if( pFcb != NULL)
             {
 
-                AFSRemoveRootFcb( pFcb);
+                if( pNPFcb != NULL)
+                {
+
+                    AFSReleaseResource( &pNPFcb->Resource);
+
+                    FsRtlTeardownPerStreamContexts( &pFcb->Header);
+
+                    ExDeleteResourceLite( &pNPFcb->SectionObjectResource);
+
+                    ExDeleteResourceLite( &pNPFcb->PagingResource);
+
+                    ExDeleteResourceLite( &pNPFcb->CcbListLock);
+
+                    ExDeleteResourceLite( &pNPFcb->Resource);
+
+                    AFSExFreePoolWithTag( pNPFcb, AFS_FCB_NP_ALLOCATION_TAG);
+                }
+
+                AFSExFreePoolWithTag( pFcb, AFS_FCB_ALLOCATION_TAG);
             }
         }
     }
@@ -1030,42 +1088,67 @@ try_exit:
 //
 // Description:
 //
-//      This function performs root Fcb removal/deallocation
+//      This function performs root Fcb removal/deallocation from
+//      the provided VolumeCB object.
 //
 // Return:
 //
-//      A status is returned for the function
+//      None
 //
 
 void
-AFSRemoveRootFcb( IN AFSFcb *RootFcb)
+AFSRemoveRootFcb( IN AFSVolumeCB *VolumeCB)
 {
+    AFSFcb * pRootFcb;
+
+    pRootFcb = (AFSFcb *) InterlockedCompareExchangePointer( (PVOID *)&VolumeCB->ObjectInformation.Fcb,
+                                                             NULL,
+                                                             (PVOID *)&VolumeCB->ObjectInformation.Fcb);
+
+    if ( pRootFcb == NULL)
+    {
+
+        return;
+    }
+
+    //
+    // The Fcb has been disconnected from the ObjectInformation block.
+    // Clear it from the RootFcb convenience pointer.
+    //
 
-    if( RootFcb->NPFcb != NULL)
+    VolumeCB->RootFcb = NULL;
+
+    if( pRootFcb->NPFcb != NULL)
     {
 
         //
         // Now the resource
         //
 
-        ExDeleteResourceLite( &RootFcb->NPFcb->Resource);
+        ExDeleteResourceLite( &pRootFcb->NPFcb->Resource);
+
+        ExDeleteResourceLite( &pRootFcb->NPFcb->PagingResource);
+
+        ExDeleteResourceLite( &pRootFcb->NPFcb->SectionObjectResource);
 
-        ExDeleteResourceLite( &RootFcb->NPFcb->PagingResource);
+        ExDeleteResourceLite( &pRootFcb->NPFcb->CcbListLock);
 
-        ExDeleteResourceLite( &RootFcb->NPFcb->CcbListLock);
+        FsRtlTeardownPerStreamContexts( &pRootFcb->Header);
 
         //
         // The non paged region
         //
 
-        AFSExFreePoolWithTag( RootFcb->NPFcb, AFS_FCB_NP_ALLOCATION_TAG);
+        AFSExFreePoolWithTag( pRootFcb->NPFcb, AFS_FCB_NP_ALLOCATION_TAG);
+
+        pRootFcb->NPFcb = NULL;
     }
 
     //
     // And the Fcb itself
     //
 
-    AFSExFreePoolWithTag( RootFcb, AFS_FCB_ALLOCATION_TAG);
+    AFSExFreePoolWithTag( pRootFcb, AFS_FCB_ALLOCATION_TAG);
 
     return;
 }
@@ -1096,6 +1179,8 @@ AFSRemoveFcb( IN AFSFcb **ppFcb)
         return;
     }
 
+    ASSERT( pFcb->Header.NodeTypeCode != AFS_ROOT_FCB);
+
     //
     // Uninitialize the file lock if it is a file
     //
index 89ad4f2..e653397 100644 (file)
@@ -691,7 +691,7 @@ AFSInitializeGlobalDirectoryEntries()
         if( pDirNode == NULL)
         {
 
-            AFSDeleteObjectInfo( pObjectInfoCB);
+            AFSDeleteObjectInfo( &pObjectInfoCB);
 
             AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING | AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
                           AFS_TRACE_LEVEL_ERROR,
@@ -714,7 +714,7 @@ AFSInitializeGlobalDirectoryEntries()
 
             ExFreePool( pDirNode);
 
-            AFSDeleteObjectInfo( pObjectInfoCB);
+            AFSDeleteObjectInfo( &pObjectInfoCB);
 
             AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING,
                           AFS_TRACE_LEVEL_ERROR,
@@ -808,7 +808,7 @@ AFSInitializeGlobalDirectoryEntries()
                           AFS_TRACE_LEVEL_ERROR,
                           "AFSInitializeGlobalDirectoryEntries AFS_DIR_ENTRY_TAG allocation failure\n");
 
-            AFSDeleteObjectInfo( pObjectInfoCB);
+            AFSDeleteObjectInfo( &pObjectInfoCB);
 
             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
         }
@@ -827,7 +827,7 @@ AFSInitializeGlobalDirectoryEntries()
 
             ExFreePool( pDirNode);
 
-            AFSDeleteObjectInfo( pObjectInfoCB);
+            AFSDeleteObjectInfo( &pObjectInfoCB);
 
             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
         }
@@ -884,7 +884,7 @@ try_exit:
             if( AFSGlobalDotDirEntry != NULL)
             {
 
-                AFSDeleteObjectInfo( AFSGlobalDotDirEntry->ObjectInformation);
+                AFSDeleteObjectInfo( &AFSGlobalDotDirEntry->ObjectInformation);
 
                 ExDeleteResourceLite( &AFSGlobalDotDirEntry->NonPaged->Lock);
 
@@ -898,7 +898,7 @@ try_exit:
             if( AFSGlobalDotDotDirEntry != NULL)
             {
 
-                AFSDeleteObjectInfo( AFSGlobalDotDotDirEntry->ObjectInformation);
+                AFSDeleteObjectInfo( &AFSGlobalDotDotDirEntry->ObjectInformation);
 
                 ExDeleteResourceLite( &AFSGlobalDotDotDirEntry->NonPaged->Lock);
 
@@ -1237,7 +1237,7 @@ try_exit:
 
                     ASSERT( pObjectInfoCB->ObjectReferenceCount == 0);
 
-                    AFSDeleteObjectInfo( pObjectInfoCB);
+                    AFSDeleteObjectInfo( &pObjectInfoCB);
                 }
             }
         }
@@ -4396,7 +4396,7 @@ AFSInitializeSpecialShareNameList()
         if( pDirNode == NULL)
         {
 
-            AFSDeleteObjectInfo( pObjectInfoCB);
+            AFSDeleteObjectInfo( &pObjectInfoCB);
 
             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
         }
@@ -4415,7 +4415,7 @@ AFSInitializeSpecialShareNameList()
 
             ExFreePool( pDirNode);
 
-            AFSDeleteObjectInfo( pObjectInfoCB);
+            AFSDeleteObjectInfo( &pObjectInfoCB);
 
             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
         }
@@ -4489,7 +4489,7 @@ AFSInitializeSpecialShareNameList()
         if( pDirNode == NULL)
         {
 
-            AFSDeleteObjectInfo( pObjectInfoCB);
+            AFSDeleteObjectInfo( &pObjectInfoCB);
 
             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
         }
@@ -4508,7 +4508,7 @@ AFSInitializeSpecialShareNameList()
 
             ExFreePool( pDirNode);
 
-            AFSDeleteObjectInfo( pObjectInfoCB);
+            AFSDeleteObjectInfo( &pObjectInfoCB);
 
             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
         }
@@ -4563,7 +4563,7 @@ try_exit:
 
                     pLastDirNode = (AFSDirectoryCB *)pDirNode->ListEntry.fLink;
 
-                    AFSDeleteObjectInfo( pDirNode->ObjectInformation);
+                    AFSDeleteObjectInfo( &pDirNode->ObjectInformation);
 
                     ExDeleteResourceLite( &pDirNode->NonPaged->Lock);
 
@@ -6021,7 +6021,7 @@ try_exit:
                               pObjectInfoCB,
                               lCount);
 
-                AFSDeleteObjectInfo( pObjectInfoCB);
+                AFSDeleteObjectInfo( &pObjectInfoCB);
             }
         }
     }
@@ -6744,14 +6744,17 @@ AFSReleaseObjectInfo( IN AFSObjectInfoCB **ppObjectInfo)
 }
 
 void
-AFSDeleteObjectInfo( IN AFSObjectInfoCB *ObjectInfo)
+AFSDeleteObjectInfo( IN AFSObjectInfoCB **ppObjectInfo)
 {
 
     BOOLEAN bAcquiredTreeLock = FALSE;
+    AFSObjectInfoCB *pObjectInfo = (*ppObjectInfo);
+    BOOLEAN bHeldInService = BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_HELD_IN_SERVICE);
     AFSObjectInfoCB * pParentObjectInfo = NULL;
+    AFSFileID FileId;
     LONG lCount;
 
-    if ( BooleanFlagOn( ObjectInfo->Flags, AFS_OBJECT_ROOT_VOLUME))
+    if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_ROOT_VOLUME))
     {
 
         //
@@ -6764,78 +6767,82 @@ AFSDeleteObjectInfo( IN AFSObjectInfoCB *ObjectInfo)
         return;
     }
 
-    ASSERT( ObjectInfo->ObjectReferenceCount == 0);
+    ASSERT( pObjectInfo->ObjectReferenceCount == 0);
 
-    if( !ExIsResourceAcquiredExclusiveLite( ObjectInfo->VolumeCB->ObjectInfoTree.TreeLock))
+    (*ppObjectInfo) = NULL;
+
+    if( !ExIsResourceAcquiredExclusiveLite( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock))
     {
 
-        ASSERT( !ExIsResourceAcquiredLite( ObjectInfo->VolumeCB->ObjectInfoTree.TreeLock));
+        ASSERT( !ExIsResourceAcquiredLite( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock));
 
-        AFSAcquireExcl( ObjectInfo->VolumeCB->ObjectInfoTree.TreeLock,
+        AFSAcquireExcl( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock,
                         TRUE);
 
         bAcquiredTreeLock = TRUE;
     }
 
-    if ( BooleanFlagOn( ObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
+    if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
     {
 
-        pParentObjectInfo = AFSFindObjectInfo( ObjectInfo->VolumeCB,
-                                               &ObjectInfo->ParentFileId);
+        pParentObjectInfo = AFSFindObjectInfo( pObjectInfo->VolumeCB,
+                                               &pObjectInfo->ParentFileId);
     }
 
     //
     // Remove it from the tree and list if it was inserted
     //
 
-    if( BooleanFlagOn( ObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE))
+    if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE))
     {
 
-        AFSRemoveHashEntry( &ObjectInfo->VolumeCB->ObjectInfoTree.TreeHead,
-                            &ObjectInfo->TreeEntry);
+        AFSRemoveHashEntry( &pObjectInfo->VolumeCB->ObjectInfoTree.TreeHead,
+                            &pObjectInfo->TreeEntry);
     }
 
-    if( BooleanFlagOn( ObjectInfo->Flags, AFS_OBJECT_INSERTED_VOLUME_LIST))
+    if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_VOLUME_LIST))
     {
 
-        if( ObjectInfo->ListEntry.fLink == NULL)
+        if( pObjectInfo->ListEntry.fLink == NULL)
         {
 
-            ObjectInfo->VolumeCB->ObjectInfoListTail = (AFSObjectInfoCB *)ObjectInfo->ListEntry.bLink;
+            pObjectInfo->VolumeCB->ObjectInfoListTail = (AFSObjectInfoCB *)pObjectInfo->ListEntry.bLink;
 
-            if( ObjectInfo->VolumeCB->ObjectInfoListTail != NULL)
+            if( pObjectInfo->VolumeCB->ObjectInfoListTail != NULL)
             {
 
-                ObjectInfo->VolumeCB->ObjectInfoListTail->ListEntry.fLink = NULL;
+                pObjectInfo->VolumeCB->ObjectInfoListTail->ListEntry.fLink = NULL;
             }
         }
         else
         {
 
-            ((AFSObjectInfoCB *)(ObjectInfo->ListEntry.fLink))->ListEntry.bLink = ObjectInfo->ListEntry.bLink;
+            ((AFSObjectInfoCB *)(pObjectInfo->ListEntry.fLink))->ListEntry.bLink = pObjectInfo->ListEntry.bLink;
         }
 
-        if( ObjectInfo->ListEntry.bLink == NULL)
+        if( pObjectInfo->ListEntry.bLink == NULL)
         {
 
-            ObjectInfo->VolumeCB->ObjectInfoListHead = (AFSObjectInfoCB *)ObjectInfo->ListEntry.fLink;
+            pObjectInfo->VolumeCB->ObjectInfoListHead = (AFSObjectInfoCB *)pObjectInfo->ListEntry.fLink;
 
-            if( ObjectInfo->VolumeCB->ObjectInfoListHead != NULL)
+            if( pObjectInfo->VolumeCB->ObjectInfoListHead != NULL)
             {
 
-                ObjectInfo->VolumeCB->ObjectInfoListHead->ListEntry.bLink = NULL;
+                pObjectInfo->VolumeCB->ObjectInfoListHead->ListEntry.bLink = NULL;
             }
         }
         else
         {
 
-            ((AFSObjectInfoCB *)(ObjectInfo->ListEntry.bLink))->ListEntry.fLink = ObjectInfo->ListEntry.fLink;
+            ((AFSObjectInfoCB *)(pObjectInfo->ListEntry.bLink))->ListEntry.fLink = pObjectInfo->ListEntry.fLink;
         }
     }
 
     if( pParentObjectInfo != NULL)
     {
 
+        ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID);
+
         lCount = AFSObjectInfoDecrement( pParentObjectInfo,
                                          AFS_OBJECT_REFERENCE_CHILD);
 
@@ -6844,31 +6851,39 @@ AFSDeleteObjectInfo( IN AFSObjectInfoCB *ObjectInfo)
                       "AFSDeleteObjectInfo Decrement count on parent object %p Cnt %d\n",
                       pParentObjectInfo,
                       lCount);
+
+        AFSReleaseObjectInfo( &pParentObjectInfo);
     }
 
     if( bAcquiredTreeLock)
     {
 
-        AFSReleaseResource( ObjectInfo->VolumeCB->ObjectInfoTree.TreeLock);
+        AFSReleaseResource( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock);
     }
 
-    //
-    // Release the fid in the service
-    //
-
-    if( BooleanFlagOn( ObjectInfo->Flags, AFS_OBJECT_HELD_IN_SERVICE))
+    if( bHeldInService)
     {
 
-        AFSReleaseFid( &ObjectInfo->FileId);
+        FileId = pObjectInfo->FileId;
     }
 
-    ExDeleteResourceLite( &ObjectInfo->NonPagedInfo->ObjectInfoLock);
+    ExDeleteResourceLite( &pObjectInfo->NonPagedInfo->ObjectInfoLock);
 
-    ExDeleteResourceLite( &ObjectInfo->NonPagedInfo->DirectoryNodeHdrLock);
+    ExDeleteResourceLite( &pObjectInfo->NonPagedInfo->DirectoryNodeHdrLock);
 
-    AFSExFreePoolWithTag( ObjectInfo->NonPagedInfo, AFS_NP_OBJECT_INFO_TAG);
+    AFSExFreePoolWithTag( pObjectInfo->NonPagedInfo, AFS_NP_OBJECT_INFO_TAG);
 
-    AFSExFreePoolWithTag( ObjectInfo, AFS_OBJECT_INFO_TAG);
+    AFSExFreePoolWithTag( pObjectInfo, AFS_OBJECT_INFO_TAG);
+
+    //
+    // Release the fid in the service
+    //
+
+    if( bHeldInService)
+    {
+
+        AFSReleaseFid( &FileId);
+    }
 
     return;
 }
@@ -8216,7 +8231,7 @@ AFSCloseLibrary()
             lCount = AFSObjectInfoDecrement( AFSGlobalDotDirEntry->ObjectInformation,
                                              AFS_OBJECT_REFERENCE_GLOBAL);
 
-            AFSDeleteObjectInfo( AFSGlobalDotDirEntry->ObjectInformation);
+            AFSDeleteObjectInfo( &AFSGlobalDotDirEntry->ObjectInformation);
 
             ExDeleteResourceLite( &AFSGlobalDotDirEntry->NonPaged->Lock);
 
@@ -8233,7 +8248,7 @@ AFSCloseLibrary()
             lCount = AFSObjectInfoDecrement( AFSGlobalDotDotDirEntry->ObjectInformation,
                                              AFS_OBJECT_REFERENCE_GLOBAL);
 
-            AFSDeleteObjectInfo( AFSGlobalDotDotDirEntry->ObjectInformation);
+            AFSDeleteObjectInfo( &AFSGlobalDotDotDirEntry->ObjectInformation);
 
             ExDeleteResourceLite( &AFSGlobalDotDotDirEntry->NonPaged->Lock);
 
@@ -8257,7 +8272,7 @@ AFSCloseLibrary()
                 lCount = AFSObjectInfoDecrement( pDirNode->ObjectInformation,
                                                  AFS_OBJECT_REFERENCE_GLOBAL);
 
-                AFSDeleteObjectInfo( pDirNode->ObjectInformation);
+                AFSDeleteObjectInfo( &pDirNode->ObjectInformation);
 
                 ExDeleteResourceLite( &pDirNode->NonPaged->Lock);
 
index 19a0301..4642a8f 100644 (file)
@@ -2514,12 +2514,11 @@ AFSInsertDirectoryNode( IN AFSObjectInfoCB *ParentObjectInfo,
     return;
 }
 
-NTSTATUS
+void
 AFSDeleteDirEntry( IN AFSObjectInfoCB *ParentObjectInfo,
                    IN AFSDirectoryCB *DirEntry)
 {
 
-    NTSTATUS ntStatus = STATUS_SUCCESS;
     LONG lCount;
 
     __Enter
@@ -2594,8 +2593,6 @@ AFSDeleteDirEntry( IN AFSObjectInfoCB *ParentObjectInfo,
 
         AFSExFreePoolWithTag( DirEntry, AFS_DIR_ENTRY_TAG);
     }
-
-    return ntStatus;
 }
 
 NTSTATUS
index 4eee3a0..5596c89 100644 (file)
@@ -949,733 +949,974 @@ AFSIOWorkerThread( IN PVOID Context)
     return;
 }
 
-void
-AFSPrimaryVolumeWorkerThread( IN PVOID Context)
+static BOOLEAN
+AFSExamineDirectory( IN AFSObjectInfoCB * pCurrentObject,
+                     IN AFSDirectoryCB  * pCurrentDirEntry)
 {
-
-    UNREFERENCED_PARAMETER(Context);
-    NTSTATUS ntStatus = STATUS_SUCCESS;
-    AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&AFSGlobalRoot->NonPagedVcb->VolumeWorkerContext;
-    AFSDeviceExt *pControlDeviceExt = NULL;
-    AFSDeviceExt *pRDRDeviceExt = NULL;
-    LARGE_INTEGER DueTime;
-    LONG TimeOut;
-    KTIMER Timer;
-    AFSObjectInfoCB *pCurrentObject = NULL, *pNextObject = NULL, *pCurrentChildObject = NULL;
-    AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL;
-    BOOLEAN bReleaseVolumeLock = FALSE;
-    AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
+    NTSTATUS ntStatus;
     AFSFcb *pFcb = NULL;
-    LARGE_INTEGER liCurrentTime;
-    BOOLEAN bVolumeObject = FALSE;
+    AFSObjectInfoCB *pCurrentChildObject = NULL;
+    AFSVolumeCB * pVolumeCB = pCurrentObject->VolumeCB;
     BOOLEAN bFcbBusy = FALSE;
     LONG lCount;
 
-    pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
-
-    pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
+    pCurrentChildObject = pCurrentDirEntry->ObjectInformation;
 
-    AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
+    AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING | AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
                   AFS_TRACE_LEVEL_VERBOSE,
-                  "AFSPrimaryVolumeWorkerThread Initialized\n");
+                  "AFSExamineDirectory Deleting DE %wZ Object %p\n",
+                  &pCurrentDirEntry->NameInformation.FileName,
+                  pCurrentChildObject);
+
+    AFSDeleteDirEntry( pCurrentObject,
+                       pCurrentDirEntry);
 
     //
-    // Initialize the timer for the worker thread
+    // Acquire ObjectInfoLock shared here so as not to deadlock
+    // with an invalidation call from the service during AFSCleanupFcb
     //
 
-    DueTime.QuadPart = -(5000);
+    lCount = AFSObjectInfoIncrement( pCurrentChildObject,
+                                     AFS_OBJECT_REFERENCE_WORKER);
 
-    TimeOut = 5000;
+    AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                  AFS_TRACE_LEVEL_VERBOSE,
+                  "AFSExamineDirectory Increment count on object %p Cnt %d\n",
+                  pCurrentChildObject,
+                  lCount);
 
-    KeInitializeTimerEx( &Timer,
-                         SynchronizationTimer);
+    if( lCount == 1 &&
+        pCurrentChildObject->Fcb != NULL &&
+        pCurrentChildObject->FileType == AFS_FILE_TYPE_FILE)
+    {
 
-    KeSetTimerEx( &Timer,
-                  DueTime,
-                  TimeOut,
-                  NULL);
+        //
+        // We must not hold pVolumeCB->ObjectInfoTree.TreeLock exclusive
+        // across an AFSCleanupFcb call since it can deadlock with an
+        // invalidation call from the service.
+        //
 
-    //
-    // Indicate that we are initialized and ready
-    //
+        AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
 
-    KeSetEvent( &pPoolContext->WorkerThreadReady,
-                0,
-                FALSE);
+        //
+        // Cannot hold a TreeLock across an AFSCleanupFcb call
+        // as it can deadlock with an invalidation ioctl initiated
+        // from the service.
+        //
+        // Dropping the TreeLock permits the
+        // pCurrentObject->ObjectReferenceCount to change
+        //
 
-    //
-    // Indicate we are initialized
-    //
+        ntStatus = AFSCleanupFcb( pCurrentChildObject->Fcb,
+                                  TRUE);
 
-    SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
+        if ( ntStatus == STATUS_RETRY)
+        {
 
-    while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
+            bFcbBusy = TRUE;
+        }
+
+        AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
+                        TRUE);
+    }
+
+    AFSAcquireExcl( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock,
+                    TRUE);
+
+    lCount = AFSObjectInfoDecrement( pCurrentChildObject,
+                                     AFS_OBJECT_REFERENCE_WORKER);
+
+    AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                  AFS_TRACE_LEVEL_VERBOSE,
+                  "AFSExamineDirectory Decrement1 count on object %p Cnt %d\n",
+                  pCurrentChildObject,
+                  lCount);
+
+    if( lCount == 0 &&
+        pCurrentChildObject->Fcb != NULL &&
+        pCurrentChildObject->Fcb->OpenReferenceCount == 0)
     {
 
-        if ( bFcbBusy == FALSE)
-        {
+        AFSRemoveFcb( &pCurrentChildObject->Fcb);
 
-            KeWaitForSingleObject( &Timer,
-                                   Executive,
-                                   KernelMode,
-                                   FALSE,
-                                   NULL);
-        }
-        else
+        if( pCurrentChildObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
+            pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
         {
 
-            bFcbBusy = FALSE;
+            AFSAcquireExcl( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
+                            TRUE);
+
+            AFSRemoveFcb( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
+
+            AFSReleaseResource( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
+
+            AFSDeleteObjectInfo( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
+
+            ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
+
+            AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
+
+            AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
+                          AFS_TRACE_LEVEL_VERBOSE,
+                          "AFSExamineDirectory (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
+                          pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB);
+
+            AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
         }
 
-        //
-        // This is the primary volume worker so it will traverse the volume list
-        // looking for cleanup or volumes requiring private workers
-        //
+        AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
 
-        AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
-                          TRUE);
+        AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
+                      AFS_TRACE_LEVEL_VERBOSE,
+                      "AFSExamineDirectory Deleting object %p\n",
+                      pCurrentChildObject);
 
-        pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
+        AFSDeleteObjectInfo( &pCurrentChildObject);
+    }
+    else
+    {
 
-        while( pVolumeCB != NULL)
+        AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
+    }
+
+    return bFcbBusy;
+}
+
+//
+// Called with VolumeCB->ObjectInfoTree.TreeLock held shared.
+// The TreeLock will be released unless *pbReleaseVolumeLock is set to FALSE.
+//
+
+static BOOLEAN
+AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
+                      IN BOOLEAN           bVolumeObject,
+                      IN OUT BOOLEAN     * pbReleaseVolumeLock)
+{
+    NTSTATUS ntStatus = STATUS_SUCCESS;
+    AFSDeviceExt *pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
+    AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
+    AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL;
+    AFSObjectInfoCB *pCurrentChildObject = NULL;
+    AFSVolumeCB * pVolumeCB = pCurrentObject->VolumeCB;
+    LARGE_INTEGER liCurrentTime;
+    BOOLEAN bFcbBusy = FALSE;
+    LONG lCount;
+    BOOLEAN bTemp;
+
+    switch ( pCurrentObject->FileType) {
+
+    case AFS_FILE_TYPE_DIRECTORY:
         {
 
-            if( pVolumeCB == AFSGlobalRoot ||
-                !AFSAcquireExcl( pVolumeCB->VolumeLock,
-                                 FALSE))
+            if ( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
             {
 
-                pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
-
-                continue;
+                return FALSE;
             }
 
-            if( pVolumeCB->ObjectInfoListHead == NULL)
+            //
+            // If this object is deleted then remove it from the parent, if we can
+            //
+
+            if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) &&
+                pCurrentObject->ObjectReferenceCount <= 0 &&
+                ( pCurrentObject->Fcb == NULL ||
+                  pCurrentObject->Fcb->OpenReferenceCount == 0) &&
+                pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL &&
+                pCurrentObject->Specific.Directory.ChildOpenReferenceCount == 0)
             {
 
-                AFSReleaseResource( pVolumeCB->VolumeLock);
+                AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
 
-                AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
+                //
+                // Dropping the TreeLock permits the
+                // pCurrentObject->ObjectReferenceCount to change
+                //
 
-                AFSAcquireExcl( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock,
-                                TRUE);
+                if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
+                                    FALSE))
+                {
 
-                AFSAcquireExcl( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
-                                TRUE);
+                    AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
+                                    TRUE);
 
-                if( !AFSAcquireExcl( pVolumeCB->VolumeLock,
-                                     FALSE))
-                {
+                    if ( pCurrentObject->ObjectReferenceCount <= 0)
+                    {
 
-                    AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
+                        AFSRemoveFcb( &pCurrentObject->Fcb);
 
-                    AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
+                        if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
+                        {
 
-                    pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
+                            AFSAcquireExcl( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
+                                            TRUE);
 
-                    continue;
-                }
+                            AFSRemoveFcb( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
 
-                KeQueryTickCount( &liCurrentTime);
+                            AFSReleaseResource( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
 
-                pNextVolume = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
+                            AFSDeleteObjectInfo( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
 
-                AFSAcquireShared( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock,
-                                  TRUE);
+                            ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
 
-                if( pVolumeCB->ObjectInfoListHead == NULL &&
-                    pVolumeCB->DirectoryCB->DirOpenReferenceCount <= 0 &&
-                    pVolumeCB->DirectoryCB->NameArrayReferenceCount <= 0 &&
-                    pVolumeCB->VolumeReferenceCount == 1 &&
-                    ( pVolumeCB->RootFcb == NULL ||
-                      pVolumeCB->RootFcb->OpenReferenceCount == 0) &&
-                    pVolumeCB->ObjectInformation.ObjectReferenceCount <= 0)
-                {
+                            AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
 
-                    if( pVolumeCB->RootFcb != NULL)
-                    {
+                            AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
+                                          AFS_TRACE_LEVEL_VERBOSE,
+                                          "AFSExamineObjectInfo (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
+                                          pCurrentObject->Specific.Directory.PIOCtlDirectoryCB);
+
+                            AFSExFreePoolWithTag( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
+                        }
 
-                        AFSRemoveRootFcb( pVolumeCB->RootFcb);
+                        AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
+
+                        AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
+                                      AFS_TRACE_LEVEL_VERBOSE,
+                                      "AFSExamineObjectInfo Deleting deleted object %p\n",
+                                      pCurrentObject);
+
+                        AFSDeleteObjectInfo( &pCurrentObject);
                     }
+                    else
+                    {
 
-                    AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
+                        AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
+                    }
 
-                    AFSRemoveVolume( pVolumeCB);
+                    AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
                 }
                 else
                 {
 
-                    AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
-
-                    AFSReleaseResource( pVolumeCB->VolumeLock);
+                    *pbReleaseVolumeLock = FALSE;
                 }
 
-                AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
+                return bFcbBusy;
+            }
 
-                AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
+            if ( pCurrentObject->Fcb != NULL &&
+                 pCurrentObject->Fcb->CcbListHead != NULL)
+            {
 
-                pVolumeCB = pNextVolume;
+                AFSCcb *pCcb;
 
-                continue;
-            }
+                for ( pCcb = pCurrentObject->Fcb->CcbListHead;
+                      pCcb;
+                      pCcb = (AFSCcb *)pCcb->ListEntry.fLink)
+                {
 
-            //
-            // Don't need this lock anymore now that we have a volume cb to work with
-            //
+                    if ( pCcb->NameArray) {
 
-            AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
+                        AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
+                                      AFS_TRACE_LEVEL_VERBOSE,
+                                      "AFSExamineObjectInfo Found Object %p Fcb %p Ccb %p\n",
+                                      pCurrentObject,
+                                      pCurrentObject->Fcb,
+                                      pCcb);
+                    }
+                }
 
-            //
-            // For now we only need the volume lock shared
-            //
+                return bFcbBusy;
+            }
 
-            AFSConvertToShared( pVolumeCB->VolumeLock);
+            if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0 ||
+                ( pCurrentObject->Fcb != NULL &&
+                  pCurrentObject->Fcb->OpenReferenceCount > 0))
+            {
 
-            if( AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
-                                  FALSE))
+                return bFcbBusy;
+            }
+
+            if ( pCurrentObject->FileType != AFS_FILE_TYPE_DIRECTORY ||
+                 pCurrentObject->Specific.Directory.DirectoryNodeListHead != NULL)
             {
 
-                pCurrentObject = pVolumeCB->ObjectInfoListHead;
+                if( !AFSAcquireShared( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
+                                       FALSE))
+                {
 
-                pNextObject = NULL;
+                    return bFcbBusy;
+                }
+
+                pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
+
+                //
+                // Directory Entry Processing
+                //
 
-                bReleaseVolumeLock = TRUE;
+                KeQueryTickCount( &liCurrentTime);
 
-                while( pCurrentObject != NULL)
+                while( pCurrentDirEntry != NULL)
                 {
 
-                    if( pCurrentObject != &pVolumeCB->ObjectInformation)
+                    if( pCurrentDirEntry->DirOpenReferenceCount > 0)
                     {
 
-                        pNextObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
-
-                        if( pNextObject == NULL &&
-                            pVolumeCB != AFSGlobalRoot)  // Don't free up the root of the global
-                        {
+                        break;
+                    }
 
-                            pNextObject = &pVolumeCB->ObjectInformation;
-                        }
+                    if ( pCurrentDirEntry->NameArrayReferenceCount > 0)
+                    {
 
-                        bVolumeObject = FALSE;
+                        break;
                     }
-                    else
+
+                    if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
+                         pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0)
                     {
 
-                        pNextObject = NULL;
+                        break;
+                    }
+
+                    if ( liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
+                         liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
+                         pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
+                    {
 
-                        bVolumeObject = TRUE;
+                        break;
                     }
 
-                    if( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
-                        !BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))  // If we are in shutdown mode skip directories
+                    if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY)
                     {
 
-                        //
-                        // If this object is deleted then remove it from the parent, if we can
-                        //
+                        if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL)
+                        {
 
-                        if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) &&
-                            pCurrentObject->ObjectReferenceCount <= 0 &&
-                            ( pCurrentObject->Fcb == NULL ||
-                              pCurrentObject->Fcb->OpenReferenceCount == 0) &&
-                            pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL &&
-                            pCurrentObject->Specific.Directory.ChildOpenReferenceCount == 0)
+                            break;
+                        }
+
+                        if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
                         {
 
-                            AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
+                            break;
+                        }
+                    }
 
-                            //
-                            // Dropping the TreeLock permits the
-                            // pCurrentObject->ObjectReferenceCount to change
-                            //
+                    if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE)
+                    {
 
-                            if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                                FALSE))
-                            {
+                        if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
+                             pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0)
+                        {
 
-                                AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
-                                                TRUE);
+                            break;
+                        }
+                    }
 
-                                if ( pCurrentObject->ObjectReferenceCount <= 0)
-                                {
+                    pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
+                }
 
-                                    AFSRemoveFcb( &pCurrentObject->Fcb);
+                if( pCurrentDirEntry != NULL)
+                {
 
-                                    if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
-                                    {
+                    AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
 
-                                        AFSAcquireExcl( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
-                                                        TRUE);
+                    return bFcbBusy;
+                }
 
-                                        AFSRemoveFcb( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
+                AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
 
-                                        AFSReleaseResource( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
+                AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
 
-                                        AFSDeleteObjectInfo( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
+                //
+                // Now acquire the locks excl without deadlocking
+                //
 
-                                        ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
+                if( AFSAcquireExcl( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
+                                    FALSE))
+                {
 
-                                        AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
+                    if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
+                                         FALSE))
+                    {
 
-                                        AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
-                                                      AFS_TRACE_LEVEL_VERBOSE,
-                                                      "AFSPrimaryVolumeWorkerThread (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
-                                                      pCurrentObject->Specific.Directory.PIOCtlDirectoryCB);
+                        AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
 
-                                        AFSExFreePoolWithTag( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
-                                    }
+                        *pbReleaseVolumeLock = FALSE;
 
-                                    AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
+                        return bFcbBusy;
+                    }
 
-                                    AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
-                                                  AFS_TRACE_LEVEL_VERBOSE,
-                                                  "AFSPrimaryVolumeWorkerThread Deleting deleted object %p\n",
-                                                  pCurrentObject);
+                    if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0)
+                    {
 
-                                    AFSDeleteObjectInfo( pCurrentObject);
-                                }
-                                else
-                                {
+                        AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
 
-                                    AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
-                                }
+                        AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
 
-                                AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+                        return bFcbBusy;
+                    }
 
-                                pCurrentObject = pNextObject;
+                    KeQueryTickCount( &liCurrentTime);
 
-                                continue;
-                            }
-                            else
-                            {
+                    pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
 
-                                bReleaseVolumeLock = FALSE;
+                    while( pCurrentDirEntry != NULL)
+                    {
 
-                                break;
-                            }
+                        if( pCurrentDirEntry->DirOpenReferenceCount > 0)
+                        {
+
+                            break;
                         }
 
-                        if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0 ||
-                            ( pCurrentObject->Fcb != NULL &&
-                              pCurrentObject->Fcb->OpenReferenceCount > 0) ||
-                            pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL)
+                        if ( pCurrentDirEntry->NameArrayReferenceCount > 0)
                         {
 
-                            pCurrentObject = pNextObject;
-
-                            continue;
+                            break;
                         }
 
-                        if( !AFSAcquireShared( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
-                                               FALSE))
+                        if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
+                             pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0)
                         {
 
-                            pCurrentObject = pNextObject;
-
-                            continue;
+                            break;
                         }
 
-                        KeQueryTickCount( &liCurrentTime);
+                        if ( liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
+                             liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
+                             pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
+                        {
 
-                        pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
+                            break;
+                        }
 
-                        while( pCurrentDirEntry != NULL)
+                        if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY)
                         {
 
-                            if( pCurrentDirEntry->DirOpenReferenceCount > 0 ||
-                                pCurrentDirEntry->NameArrayReferenceCount > 0 ||
-                                ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
-                                  pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0) ||
-                                liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
-                                liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
-                                                                        pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart ||
-                                ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY &&
-                                   ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL ||
-                                     pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)) ||
-                                ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE &&
-                                  pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
-                                  pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0))
+                            if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL)
                             {
 
                                 break;
                             }
 
-                            pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
+                            if ( pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
+                            {
+
+                                break;
+                            }
                         }
 
-                        if( pCurrentDirEntry != NULL)
+                        if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE)
                         {
 
-                            AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
-
-                            pCurrentObject = pNextObject;
+                            if ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
+                                 pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0)
+                            {
 
-                            continue;
+                                break;
+                            }
                         }
 
+                        pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
+                    }
+
+                    if( pCurrentDirEntry != NULL)
+                    {
+
                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
 
-                        AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
+                        AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
 
-                        //
-                        // Now acquire the locks excl
-                        //
+                        return bFcbBusy;
+                    }
 
-                        if( AFSAcquireExcl( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
-                                            FALSE))
-                        {
+                    pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
 
-                            if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                                FALSE))
-                            {
+                    while( pCurrentDirEntry != NULL)
+                    {
 
-                                if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0)
-                                {
+                        pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
 
-                                    AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
+                        AFSExamineDirectory( pCurrentObject,
+                                             pCurrentDirEntry);
 
-                                    AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+                        pCurrentDirEntry = pNextDirEntry;
+                    }
 
-                                    pCurrentObject = pNextObject;
+                    //
+                    // Clear our enumerated flag on this object so we retrieve info again on next access
+                    //
 
-                                    continue;
-                                }
+                    ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED);
 
-                                KeQueryTickCount( &liCurrentTime);
+                    AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
 
-                                pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
+                    AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+                }
+                else
+                {
 
-                                while( pCurrentDirEntry != NULL)
-                                {
+                    //
+                    // Try to grab the volume lock again ... no problem if we don't
+                    //
 
-                                    if( pCurrentDirEntry->DirOpenReferenceCount > 0 ||
-                                        pCurrentDirEntry->NameArrayReferenceCount > 0 ||
-                                        ( pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
-                                          pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0) ||
-                                        liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
-                                        liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart <
-                                                                                pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart ||
-                                        ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY &&
-                                          ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL ||
-                                            pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)) ||
-                                        ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE &&
-                                          pCurrentDirEntry->ObjectInformation->Fcb != NULL &&
-                                          pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0))
-                                    {
+                    if( !AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
+                                           FALSE))
+                    {
 
-                                        break;
-                                    }
+                        *pbReleaseVolumeLock = FALSE;
 
-                                    pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
-                                }
+                        return bFcbBusy;
+                    }
+                }
+            }
+            else if ( bVolumeObject == FALSE)
+            {
+                //
+                // No children
+                //
 
-                                if( pCurrentDirEntry != NULL)
-                                {
+                AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
 
-                                    AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
+                if ( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
+                                      FALSE))
+                {
 
-                                    AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+                    *pbReleaseVolumeLock = FALSE;
 
-                                    pCurrentObject = pNextObject;
+                    return bFcbBusy;
+                }
 
-                                    continue;
-                                }
+                AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
+                                TRUE);
 
-                                pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
+                KeQueryTickCount( &liCurrentTime);
 
-                                while( pCurrentDirEntry != NULL)
-                                {
+                if( pCurrentObject->ObjectReferenceCount <= 0 &&
+                    ( pCurrentObject->Fcb == NULL ||
+                      pCurrentObject->Fcb->OpenReferenceCount <= 0) &&
+                    liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
+                    liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
+                    pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
+                {
 
-                                    pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
+                    AFSRemoveFcb( &pCurrentObject->Fcb);
 
-                                    pCurrentChildObject = pCurrentDirEntry->ObjectInformation;
+                    AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
 
-                                    pFcb = NULL;
+                    AFSDeleteObjectInfo( &pCurrentObject);
+                }
+                else
+                {
 
-                                    AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING | AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
-                                                  AFS_TRACE_LEVEL_VERBOSE,
-                                                  "AFSPrimaryVolumeWorkerThread Deleting DE %wZ Object %p\n",
-                                                  &pCurrentDirEntry->NameInformation.FileName,
-                                                  pCurrentChildObject);
+                    AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
+                }
 
-                                    AFSDeleteDirEntry( pCurrentObject,
-                                                       pCurrentDirEntry);
+                AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+            }
+        }
+        break;
 
+    case AFS_FILE_TYPE_FILE:
+        {
 
-                                    //
-                                    // Acquire ObjectInfoLock shared here so as not to deadlock
-                                    // with an invalidation call from the service during AFSCleanupFcb
-                                    //
+            lCount = AFSObjectInfoIncrement( pCurrentObject,
+                                             AFS_OBJECT_REFERENCE_WORKER);
 
-                                    lCount = AFSObjectInfoIncrement( pCurrentChildObject,
-                                                                     AFS_OBJECT_REFERENCE_WORKER);
+            AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                          AFS_TRACE_LEVEL_VERBOSE,
+                          "AFSExamineObjectInfo Increment3 count on object %p Cnt %d\n",
+                          pCurrentObject,
+                          lCount);
 
-                                    AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
-                                                  AFS_TRACE_LEVEL_VERBOSE,
-                                                  "AFSPrimaryVolumeWorkerThread Increment count on object %p Cnt %d\n",
-                                                  pCurrentChildObject,
-                                                  lCount);
+            AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
 
-                                    if( lCount == 1 &&
-                                        pCurrentChildObject->Fcb != NULL &&
-                                        pCurrentChildObject->FileType == AFS_FILE_TYPE_FILE)
-                                    {
+            if( pCurrentObject->Fcb != NULL)
+            {
 
-                                        //
-                                        // We must not hold pVolumeCB->ObjectInfoTree.TreeLock exclusive
-                                        // across an AFSCleanupFcb call since it can deadlock with an
-                                        // invalidation call from the service.
-                                        //
+                //
+                // Dropping the TreeLock permits the
+                // pCurrentObject->ObjectReferenceCount to change
+                //
 
-                                        AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
+                ntStatus = AFSCleanupFcb( pCurrentObject->Fcb,
+                                          FALSE);
 
-                                        //
-                                        // Cannot hold a TreeLock across an AFSCleanupFcb call
-                                        // as it can deadlock with an invalidation ioctl initiated
-                                        // from the service.
-                                        //
-                                        // Dropping the TreeLock permits the
-                                        // pCurrentObject->ObjectReferenceCount to change
-                                        //
+                if ( ntStatus == STATUS_RETRY)
+                {
 
-                                        ntStatus = AFSCleanupFcb( pCurrentChildObject->Fcb,
-                                                                  TRUE);
+                    bFcbBusy = TRUE;
+                }
+            }
 
-                                        if ( ntStatus == STATUS_RETRY)
-                                        {
+            bTemp = AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
+                                    FALSE);
 
-                                            bFcbBusy = TRUE;
-                                        }
+            lCount = AFSObjectInfoDecrement( pCurrentObject,
+                                             AFS_OBJECT_REFERENCE_WORKER);
 
-                                        AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                                        TRUE);
-                                    }
+            AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                          AFS_TRACE_LEVEL_VERBOSE,
+                          "AFSExamineObjectInfo Decrement3 count on object %p Cnt %d\n",
+                          pCurrentObject,
+                          lCount);
 
-                                    lCount = AFSObjectInfoDecrement( pCurrentChildObject,
-                                                                     AFS_OBJECT_REFERENCE_WORKER);
 
-                                    AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
-                                                  AFS_TRACE_LEVEL_VERBOSE,
-                                                  "AFSPrimaryVolumeWorkerThread Decrement1 count on object %p Cnt %d\n",
-                                                  pCurrentChildObject,
-                                                  lCount);
+            if ( bTemp == FALSE)
+            {
 
-                                    AFSAcquireExcl( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock,
-                                                    TRUE);
+                *pbReleaseVolumeLock = FALSE;
 
-                                    if( pCurrentChildObject->ObjectReferenceCount <= 0)
-                                    {
+                return bFcbBusy;
+            }
 
-                                        AFSRemoveFcb( &pCurrentChildObject->Fcb);
+            AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
+                            TRUE);
 
-                                        if( pCurrentChildObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
-                                            pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
-                                        {
+            KeQueryTickCount( &liCurrentTime);
 
-                                            AFSAcquireExcl( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
-                                                            TRUE);
+            if( pCurrentObject->ObjectReferenceCount <= 0 &&
+                ( pCurrentObject->Fcb == NULL ||
+                  ( pCurrentObject->Fcb->OpenReferenceCount <= 0 &&
+                    pCurrentObject->Fcb->Specific.File.ExtentsDirtyCount <= 0)) &&
+                liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
+                liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
+                pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
+            {
 
-                                            AFSRemoveFcb( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
+                AFSRemoveFcb( &pCurrentObject->Fcb);
 
-                                            AFSReleaseResource( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
+                AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
 
-                                            AFSDeleteObjectInfo( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
+                AFSDeleteObjectInfo( &pCurrentObject);
+            }
+            else
+            {
 
-                                            ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
+                AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
+            }
 
-                                            AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
+            AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+        }
+        break;
 
-                                            AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
-                                                          AFS_TRACE_LEVEL_VERBOSE,
-                                                          "AFSPrimaryVolumeWorkerThread (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
-                                                          pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB);
+    default:
+        {
 
-                                            AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
-                                        }
+            AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
 
-                                        AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
+            if ( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
+                                  FALSE))
+            {
 
-                                        AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
-                                                      AFS_TRACE_LEVEL_VERBOSE,
-                                                      "AFSPrimaryVolumeWorkerThread Deleting object %p\n",
-                                                      pCurrentChildObject);
+                *pbReleaseVolumeLock = FALSE;
 
-                                        AFSDeleteObjectInfo( pCurrentChildObject);
-                                    }
-                                    else
-                                    {
+                return bFcbBusy;
+            }
 
-                                        AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
-                                    }
+            AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
+                            TRUE);
 
-                                    pCurrentDirEntry = pNextDirEntry;
+            KeQueryTickCount( &liCurrentTime);
 
-                                }
+            if( pCurrentObject->ObjectReferenceCount <= 0 &&
+                ( pCurrentObject->Fcb == NULL ||
+                  pCurrentObject->Fcb->OpenReferenceCount <= 0) &&
+                liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
+                liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
+                pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
+            {
 
-                                pCurrentObject->Specific.Directory.DirectoryNodeListHead = NULL;
+                AFSRemoveFcb( &pCurrentObject->Fcb);
 
-                                pCurrentObject->Specific.Directory.DirectoryNodeListTail = NULL;
+                AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
 
-                                pCurrentObject->Specific.Directory.ShortNameTree = NULL;
+                AFSDeleteObjectInfo( &pCurrentObject);
+            }
+            else
+            {
 
-                                pCurrentObject->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead = NULL;
+                AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
+            }
 
-                                pCurrentObject->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead = NULL;
+            AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+        }
+    }
 
-                                pCurrentObject->Specific.Directory.DirectoryNodeCount = 0;
+    return bFcbBusy;
+}
 
-                                AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT,
-                                              AFS_TRACE_LEVEL_VERBOSE,
-                                              "AFSPrimaryVolumeWorkerThread Reset count to 0 on parent FID %08lX-%08lX-%08lX-%08lX\n",
-                                              pCurrentObject->FileId.Cell,
-                                              pCurrentObject->FileId.Volume,
-                                              pCurrentObject->FileId.Vnode,
-                                              pCurrentObject->FileId.Unique);
 
-                                //
-                                // Clear our enumerated flag on this object so we retrieve info again on next access
-                                //
+static BOOLEAN
+AFSExamineVolume( IN AFSVolumeCB *pVolumeCB)
+{
+    NTSTATUS ntStatus = STATUS_SUCCESS;
+    AFSObjectInfoCB *pCurrentObject = NULL, *pNextObject = NULL;
+    BOOLEAN bReleaseVolumeLock = FALSE;
+    BOOLEAN bVolumeObject = FALSE;
+    BOOLEAN bFcbBusy = FALSE;
+    LONG lCount;
 
-                                ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED);
+    if( AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
+                          FALSE))
+    {
 
-                                AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
+        bReleaseVolumeLock = TRUE;
 
-                                AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
-                            }
-                            else
-                            {
+        pCurrentObject = pVolumeCB->ObjectInfoListHead;
 
-                                AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
+        pNextObject = NULL;
 
-                                bReleaseVolumeLock = FALSE;
+        while( pCurrentObject != NULL)
+        {
 
-                                break;
-                            }
-                        }
-                        else
-                        {
+            if( pCurrentObject != &pVolumeCB->ObjectInformation)
+            {
 
-                            //
-                            // Try to grab the volume lock again ... no problem if we don't
-                            //
+                pNextObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
 
-                            if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                                 FALSE))
-                            {
+                //
+                // If the end of the VolumeCB ObjectInfo List is reached, then
+                // the next ObjectInformationCB to examine is the one embedded within
+                // the VolumeCB itself except when the VolumeCB is the AFSGlobalRoot.
+                //
+                // bVolumeObject is used to indicate whether the embedded ObjectInfoCB
+                // is being examined.
+                //
 
-                                bReleaseVolumeLock = FALSE;
+                if( pNextObject == NULL &&
+                    pVolumeCB != AFSGlobalRoot)  // Don't free up the root of the global
+                {
 
-                                break;
-                            }
-                        }
+                    pNextObject = &pVolumeCB->ObjectInformation;
+                }
 
-                        if( pCurrentObject != &pVolumeCB->ObjectInformation)
-                        {
+                bVolumeObject = FALSE;
 
-                            pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink;
+                if ( pNextObject)
+                {
 
-                            if( pCurrentObject == NULL &&
-                                pVolumeCB != AFSGlobalRoot)
-                            {
+                    lCount = AFSObjectInfoIncrement( pNextObject,
+                                                     AFS_OBJECT_REFERENCE_WORKER);
 
-                                pCurrentObject = &pVolumeCB->ObjectInformation;
-                            }
-                        }
-                        else
-                        {
+                    AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                                  AFS_TRACE_LEVEL_VERBOSE,
+                                  "AFSExamineVolume Increment count on object %p Cnt %d\n",
+                                  pNextObject,
+                                  lCount);
+                }
+            }
+            else
+            {
 
-                            pCurrentObject = NULL;
-                        }
+                pNextObject = NULL;
 
-                        continue;
-                    }
-                    else if( pCurrentObject->FileType == AFS_FILE_TYPE_FILE)
-                    {
+                bVolumeObject = TRUE;
+            }
 
-                        lCount = AFSObjectInfoIncrement( pCurrentObject,
-                                                         AFS_OBJECT_REFERENCE_WORKER);
+            bFcbBusy = AFSExamineObjectInfo( pCurrentObject, bVolumeObject, &bReleaseVolumeLock);
 
-                        AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
-                                      AFS_TRACE_LEVEL_VERBOSE,
-                                      "AFSPrimaryVolumeWorkerThread Increment2 count on object %p Cnt %d\n",
-                                      pCurrentObject,
-                                      lCount);
+            if ( pNextObject)
+            {
 
-                        AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
+                lCount = AFSObjectInfoDecrement( pNextObject,
+                                                 AFS_OBJECT_REFERENCE_WORKER);
 
-                        if( pCurrentObject->Fcb != NULL)
-                        {
+                AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                              AFS_TRACE_LEVEL_VERBOSE,
+                              "AFSExamineVolume Decrement count on object %p Cnt %d\n",
+                              pNextObject,
+                              lCount);
+            }
 
-                            //
-                            // Dropping the TreeLock permits the
-                            // pCurrentObject->ObjectReferenceCount to change
-                            //
+            //
+            // If AFSExamineObjectInfo drops the VolumeLock before returning
+            // we must halt processing of the Volume's ObjectInfo list.
+            //
 
-                            ntStatus = AFSCleanupFcb( pCurrentObject->Fcb,
-                                                      FALSE);
+            if ( bReleaseVolumeLock == FALSE)
+            {
 
-                            if ( ntStatus == STATUS_RETRY)
-                            {
+                break;
+            }
 
-                                bFcbBusy = TRUE;
-                            }
-                        }
+            pCurrentObject = pNextObject;
+        }
 
-                        lCount = AFSObjectInfoDecrement( pCurrentObject,
-                                                         AFS_OBJECT_REFERENCE_WORKER);
+        if( bReleaseVolumeLock)
+        {
 
-                        AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
-                                      AFS_TRACE_LEVEL_VERBOSE,
-                                      "AFSPrimaryVolumeWorkerThread Decrement2 count on object %p Cnt %d\n",
-                                      pCurrentObject,
-                                      lCount);
+            AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
+        }
+    }
 
-                        if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                             FALSE))
-                        {
+    return bFcbBusy;
+}
 
-                            bReleaseVolumeLock = FALSE;
+void
+AFSPrimaryVolumeWorkerThread( IN PVOID Context)
+{
 
-                            break;
-                        }
+    UNREFERENCED_PARAMETER(Context);
+    AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&AFSGlobalRoot->NonPagedVcb->VolumeWorkerContext;
+    AFSDeviceExt *pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
+    AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
+    LARGE_INTEGER DueTime;
+    LONG TimeOut;
+    KTIMER Timer;
+    AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
+    BOOLEAN bFcbBusy = FALSE;
+    LONG lCount;
+
+    AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
+                  AFS_TRACE_LEVEL_VERBOSE,
+                  "AFSPrimaryVolumeWorkerThread Initialized\n");
 
-                        AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
-                                        TRUE);
+    //
+    // Initialize the timer for the worker thread
+    //
 
-                        if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) &&
-                            pCurrentObject->ObjectReferenceCount <= 0)
-                        {
+    DueTime.QuadPart = -(5000);
 
-                            AFSRemoveFcb( &pCurrentObject->Fcb);
+    TimeOut = 5000;
 
-                            AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
+    KeInitializeTimerEx( &Timer,
+                         SynchronizationTimer);
 
-                            AFSDeleteObjectInfo( pCurrentObject);
-                        }
-                        else
-                        {
+    KeSetTimerEx( &Timer,
+                  DueTime,
+                  TimeOut,
+                  NULL);
 
-                            AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
-                        }
+    //
+    // Indicate that we are initialized and ready
+    //
 
-                        AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+    KeSetEvent( &pPoolContext->WorkerThreadReady,
+                0,
+                FALSE);
 
-                        pCurrentObject = pNextObject;
+    //
+    // Indicate we are initialized
+    //
 
-                        continue;
-                    }
+    SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
+
+    while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
+    {
+
+        if ( bFcbBusy == FALSE)
+        {
+
+            KeWaitForSingleObject( &Timer,
+                                   Executive,
+                                   KernelMode,
+                                   FALSE,
+                                   NULL);
+        }
+        else
+        {
+
+            bFcbBusy = FALSE;
+        }
+
+        //
+        // This is the primary volume worker so it will traverse the volume list
+        // looking for cleanup or volumes requiring private workers
+        //
+
+        AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
+                          TRUE);
+
+        pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead;
+
+        while( pVolumeCB != NULL)
+        {
+
+            if( pVolumeCB == AFSGlobalRoot ||
+                !AFSAcquireExcl( pVolumeCB->VolumeLock,
+                                 FALSE))
+            {
+
+                pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
+
+                continue;
+            }
+
+            if( pVolumeCB->ObjectInfoListHead == NULL)
+            {
+
+                AFSReleaseResource( pVolumeCB->VolumeLock);
+
+                AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
+
+                AFSAcquireExcl( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock,
+                                TRUE);
+
+                AFSAcquireExcl( &pRDRDeviceExt->Specific.RDR.VolumeListLock,
+                                TRUE);
+
+                if( !AFSAcquireExcl( pVolumeCB->VolumeLock,
+                                     FALSE))
+                {
+
+                    AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
+
+                    AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
 
-                    pCurrentObject = pNextObject;
+                    pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
+
+                    continue;
                 }
 
-                if( bReleaseVolumeLock)
+                pNextVolume = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
+
+                AFSAcquireShared( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock,
+                                  TRUE);
+
+                //
+                // If VolumeCB is idle, the Volume can be garbage collected
+                //
+
+                if( pVolumeCB->ObjectInfoListHead == NULL &&
+                    pVolumeCB->DirectoryCB->DirOpenReferenceCount <= 0 &&
+                    pVolumeCB->DirectoryCB->NameArrayReferenceCount <= 0 &&
+                    pVolumeCB->VolumeReferenceCount == 1 &&
+                    ( pVolumeCB->RootFcb == NULL ||
+                      pVolumeCB->RootFcb->OpenReferenceCount == 0) &&
+                    pVolumeCB->ObjectInformation.ObjectReferenceCount <= 0)
                 {
 
-                    AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
+                    AFSRemoveRootFcb( pVolumeCB);
+
+                    AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
+
+                    AFSRemoveVolume( pVolumeCB);
                 }
+                else
+                {
+
+                    AFSReleaseResource( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock);
+
+                    AFSReleaseResource( pVolumeCB->VolumeLock);
+                }
+
+                AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
+
+                AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock);
+
+                pVolumeCB = pNextVolume;
+
+                continue;
             }
 
             //
+            // Don't need this lock anymore now that we have a volume cb to work with
+            //
+
+            AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock);
+
+            //
+            // For now we only need the volume lock shared
+            //
+
+            AFSConvertToShared( pVolumeCB->VolumeLock);
+
+            AFSExamineVolume( pVolumeCB);
+
+            //
             // Next volume cb
             //
 
index 030b1bd..0f11fdf 100644 (file)
@@ -537,7 +537,7 @@ AFSInitRootFcb( IN ULONGLONG ProcessID,
                 IN AFSVolumeCB *VolumeCB);
 
 void
-AFSRemoveRootFcb( IN AFSFcb *RootFcb);
+AFSRemoveRootFcb( IN AFSVolumeCB *VolumeCB);
 
 NTSTATUS
 AFSInitCcb( IN OUT AFSCcb **Ccb,
@@ -586,7 +586,7 @@ AFSInsertDirectoryNode( IN AFSObjectInfoCB *ParentObjectInfo,
                         IN AFSDirectoryCB *DirEntry,
                         IN BOOLEAN InsertInEnumList);
 
-NTSTATUS
+void
 AFSDeleteDirEntry( IN AFSObjectInfoCB *ParentObjectInfo,
                    IN AFSDirectoryCB *DirEntry);
 
@@ -1331,7 +1331,7 @@ AFSObjectInfoDecrement( IN AFSObjectInfoCB *ObjectInfo,
                         IN LONG             Reason);
 
 void
-AFSDeleteObjectInfo( IN AFSObjectInfoCB *ObjectInfo);
+AFSDeleteObjectInfo( IN AFSObjectInfoCB **ppObjectInfo);
 
 AFSObjectInfoCB *
 AFSFindObjectInfo( IN AFSVolumeCB * VolumeCB,