Windows: AFSPrimaryVolumeWorkerThread reorg
authorJeffrey Altman <jaltman@your-file-system.com>
Tue, 2 Apr 2013 04:46:27 +0000 (00:46 -0400)
committerJeffrey Altman <jaltman@your-file-system.com>
Sat, 6 Apr 2013 02:27:48 +0000 (19:27 -0700)
Periodically there is a lost race which results in a valid DirectoryCB
with a non-NULL ObjectInformation pointer that refers to freed memory.
This major reorganization simplifies the logic and attempts to close
potential loopholes.

First, the AFSExamineDirectory() function is removed and replaced by
a call to AFSDeleteDirEntry().  The AFSExamineDirectory() function
examined all of the children AFSObjectInfoCB objects which in turn
duplicated much of the logic of AFSExamineObjInfo at the cost of
increased complexity due to the additional layer of locked objects.
Once the AFSDirectoryCB is removed a subsequent pass of the worker
thread will free the AFSObjectInfoCBs.

Second, the AFS_OBJECT_REFERENCE_DIRENTRY category had been used for
both DirectoryCB references and the Pioctl references.  A new
AFS_OBJECT_REFERENCE_PIOCTL category has been created to improve the
ability to track the allocations and releases.

Third, the AFSPrimaryVolumeWorker thread now attempts to hold onto the
VolumeCB TreeLock exclusively.  Previously the lock was held shared.
However, it is not safe for both the garbage collection and the find
routines to both be shared.  One has to be exclusive.  Although holding
the TreeLock exclusively in the garbage collection processing will result
in the lock being held for extended periods of time, it is more likely
that there will be benefits from parallel access during AFSFindObjectInfo()
calls.

Attempts to obtain most other locks are non-blocking.  If the lock cannot
be obtained, the object must be in use.  Therefore, it should not be
garbage collected.

Change-Id: I75e0302c1737aadfbd9afc0c8a03e28513e785f5
Reviewed-on: http://gerrit.openafs.org/9720
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/AFSGeneric.cpp
src/WINNT/afsrdr/kernel/lib/AFSVolume.cpp
src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp
src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h

index 060b3bb..3524907 100644 (file)
@@ -5348,7 +5348,7 @@ AFSInitPIOCtlDirectoryCB( IN AFSObjectInfoCB *ParentObjectInfo)
         }
 
         lCount = AFSObjectInfoIncrement( pObjectInfoCB,
-                                         AFS_OBJECT_REFERENCE_DIRENTRY);
+                                         AFS_OBJECT_REFERENCE_PIOCTL);
 
         AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
                       AFS_TRACE_LEVEL_VERBOSE,
@@ -5460,7 +5460,7 @@ try_exit:
             {
 
                 lCount = AFSObjectInfoDecrement( pObjectInfoCB,
-                                                 AFS_OBJECT_REFERENCE_DIRENTRY);
+                                                 AFS_OBJECT_REFERENCE_PIOCTL);
 
                 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
                               AFS_TRACE_LEVEL_VERBOSE,
@@ -6234,157 +6234,169 @@ AFSReleaseObjectInfo( IN AFSObjectInfoCB **ppObjectInfo)
 void
 AFSDeleteObjectInfo( IN AFSObjectInfoCB **ppObjectInfo)
 {
-
     BOOLEAN bAcquiredTreeLock = FALSE;
     AFSObjectInfoCB *pObjectInfo = NULL;
+    AFSVolumeCB * pVolume = NULL;
     BOOLEAN bHeldInService;
     AFSObjectInfoCB * pParentObjectInfo = NULL;
     AFSFileID FileId;
     LONG lCount;
 
-    if ( BooleanFlagOn( (*ppObjectInfo)->Flags, AFS_OBJECT_ROOT_VOLUME))
+    __Enter
     {
+        if ( BooleanFlagOn( (*ppObjectInfo)->Flags, AFS_OBJECT_ROOT_VOLUME))
+        {
 
-        //
-        // AFSDeleteObjectInfo should never be called on the ObjectInformationCB
-        // embedded in the VolumeCB.
-        //
-
-        ASSERT( FALSE);
-
-        return;
-    }
+            //
+            // AFSDeleteObjectInfo should never be called on the ObjectInformationCB
+            // embedded in the VolumeCB.
+            //
 
-    pObjectInfo = (AFSObjectInfoCB *) InterlockedCompareExchangePointer( (PVOID *)ppObjectInfo,
-                                                                         NULL,
-                                                                         *ppObjectInfo);
+            ASSERT( FALSE);
 
-    if ( pObjectInfo == NULL)
-    {
+            return;
+        }
 
-        return;
-    }
+        pVolume = (*ppObjectInfo)->VolumeCB;
 
-    ASSERT( *ppObjectInfo == NULL);
+        if( !ExIsResourceAcquiredExclusiveLite( pVolume->ObjectInfoTree.TreeLock))
+        {
 
-    if( !ExIsResourceAcquiredExclusiveLite( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock))
-    {
+            ASSERT( !ExIsResourceAcquiredLite( pVolume->ObjectInfoTree.TreeLock));
 
-        ASSERT( !ExIsResourceAcquiredLite( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock));
+            AFSAcquireExcl( pVolume->ObjectInfoTree.TreeLock,
+                            TRUE);
 
-        AFSAcquireExcl( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock,
-                        TRUE);
+            bAcquiredTreeLock = TRUE;
+        }
 
-        bAcquiredTreeLock = TRUE;
-    }
+        for ( lCount = 0; lCount < AFS_OBJECT_REFERENCE_MAX; lCount++)
+        {
 
-    ASSERT( pObjectInfo->ObjectReferenceCount == 0);
+            ASSERT( (*ppObjectInfo)->ObjectReferences[ lCount] >= 0);
+        }
 
-    bHeldInService = BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_HELD_IN_SERVICE);
+        ASSERT( (*ppObjectInfo)->ObjectReferenceCount == 0);
 
-    if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
-    {
+        pObjectInfo = (AFSObjectInfoCB *) InterlockedCompareExchangePointer( (PVOID *)ppObjectInfo,
+                                                                             NULL,
+                                                                             *ppObjectInfo);
 
-        pParentObjectInfo = AFSFindObjectInfo( pObjectInfo->VolumeCB,
-                                               &pObjectInfo->ParentFileId);
-    }
+        if ( pObjectInfo == NULL)
+        {
 
-    //
-    // Remove it from the tree and list if it was inserted
-    //
+            try_return( NOTHING);
+        }
 
-    if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE))
-    {
+        ASSERT( *ppObjectInfo == NULL);
 
-        AFSRemoveHashEntry( &pObjectInfo->VolumeCB->ObjectInfoTree.TreeHead,
-                            &pObjectInfo->TreeEntry);
-    }
+        if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
+        {
 
-    if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_VOLUME_LIST))
-    {
+            pParentObjectInfo = AFSFindObjectInfo( pVolume,
+                                                   &pObjectInfo->ParentFileId);
+            if( pParentObjectInfo != NULL)
+            {
 
-        if( pObjectInfo->ListEntry.fLink == NULL)
-        {
+                ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID);
 
-            pObjectInfo->VolumeCB->ObjectInfoListTail = (AFSObjectInfoCB *)pObjectInfo->ListEntry.bLink;
+                lCount = AFSObjectInfoDecrement( pParentObjectInfo,
+                                                 AFS_OBJECT_REFERENCE_CHILD);
 
-            if( pObjectInfo->VolumeCB->ObjectInfoListTail != NULL)
-            {
+                AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                              AFS_TRACE_LEVEL_VERBOSE,
+                              "AFSDeleteObjectInfo Decrement count on parent object %p Cnt %d\n",
+                              pParentObjectInfo,
+                              lCount));
 
-                pObjectInfo->VolumeCB->ObjectInfoListTail->ListEntry.fLink = NULL;
+                AFSReleaseObjectInfo( &pParentObjectInfo);
             }
         }
-        else
+
+        //
+        // Remove it from the tree and list if it was inserted
+        //
+
+        if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE))
         {
 
-            ((AFSObjectInfoCB *)(pObjectInfo->ListEntry.fLink))->ListEntry.bLink = pObjectInfo->ListEntry.bLink;
+            AFSRemoveHashEntry( &pVolume->ObjectInfoTree.TreeHead,
+                                &pObjectInfo->TreeEntry);
         }
 
-        if( pObjectInfo->ListEntry.bLink == NULL)
+        if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_VOLUME_LIST))
         {
 
-            pObjectInfo->VolumeCB->ObjectInfoListHead = (AFSObjectInfoCB *)pObjectInfo->ListEntry.fLink;
+            if( pObjectInfo->ListEntry.fLink == NULL)
+            {
+
+                pVolume->ObjectInfoListTail = (AFSObjectInfoCB *)pObjectInfo->ListEntry.bLink;
 
-            if( pObjectInfo->VolumeCB->ObjectInfoListHead != NULL)
+                if( pVolume->ObjectInfoListTail != NULL)
+                {
+
+                    pVolume->ObjectInfoListTail->ListEntry.fLink = NULL;
+                }
+            }
+            else
             {
 
-                pObjectInfo->VolumeCB->ObjectInfoListHead->ListEntry.bLink = NULL;
+                ((AFSObjectInfoCB *)(pObjectInfo->ListEntry.fLink))->ListEntry.bLink = pObjectInfo->ListEntry.bLink;
             }
-        }
-        else
-        {
 
-            ((AFSObjectInfoCB *)(pObjectInfo->ListEntry.bLink))->ListEntry.fLink = pObjectInfo->ListEntry.fLink;
-        }
-    }
+            if( pObjectInfo->ListEntry.bLink == NULL)
+            {
 
-    if( pParentObjectInfo != NULL)
-    {
+                pVolume->ObjectInfoListHead = (AFSObjectInfoCB *)pObjectInfo->ListEntry.fLink;
 
-        ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID);
+                if( pVolume->ObjectInfoListHead != NULL)
+                {
 
-        lCount = AFSObjectInfoDecrement( pParentObjectInfo,
-                                         AFS_OBJECT_REFERENCE_CHILD);
+                    pVolume->ObjectInfoListHead->ListEntry.bLink = NULL;
+                }
+            }
+            else
+            {
 
-        AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
-                      AFS_TRACE_LEVEL_VERBOSE,
-                      "AFSDeleteObjectInfo Decrement count on parent object %p Cnt %d\n",
-                      pParentObjectInfo,
-                      lCount));
+                ((AFSObjectInfoCB *)(pObjectInfo->ListEntry.bLink))->ListEntry.fLink = pObjectInfo->ListEntry.fLink;
+            }
+        }
 
-        AFSReleaseObjectInfo( &pParentObjectInfo);
-    }
+        bHeldInService = BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_HELD_IN_SERVICE);
 
-    if( bAcquiredTreeLock)
-    {
+        if( bHeldInService)
+        {
 
-        AFSReleaseResource( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock);
-    }
+            FileId = pObjectInfo->FileId;
+        }
 
-    if( bHeldInService)
-    {
+        ASSERT( pObjectInfo->ObjectReferenceCount == 0);
 
-        FileId = pObjectInfo->FileId;
-    }
+        ExDeleteResourceLite( &pObjectInfo->NonPagedInfo->ObjectInfoLock);
 
-    ASSERT( pObjectInfo->ObjectReferenceCount == 0);
+        ExDeleteResourceLite( &pObjectInfo->NonPagedInfo->DirectoryNodeHdrLock);
 
-    ExDeleteResourceLite( &pObjectInfo->NonPagedInfo->ObjectInfoLock);
+        AFSExFreePoolWithTag( pObjectInfo->NonPagedInfo, AFS_NP_OBJECT_INFO_TAG);
 
-    ExDeleteResourceLite( &pObjectInfo->NonPagedInfo->DirectoryNodeHdrLock);
+        AFSExFreePoolWithTag( pObjectInfo, AFS_OBJECT_INFO_TAG);
 
-    AFSExFreePoolWithTag( pObjectInfo->NonPagedInfo, AFS_NP_OBJECT_INFO_TAG);
+try_exit:
 
-    AFSExFreePoolWithTag( pObjectInfo, AFS_OBJECT_INFO_TAG);
+        if( bAcquiredTreeLock)
+        {
 
-    //
-    // Release the fid in the service
-    //
+            AFSReleaseResource( pVolume->ObjectInfoTree.TreeLock);
+        }
 
-    if( bHeldInService)
-    {
+        //
+        // Release the fid in the service
+        //
 
-        AFSReleaseFid( &FileId);
+        if( bHeldInService)
+        {
+
+            AFSReleaseFid( &FileId);
+        }
     }
 
     return;
index 77a1b8a..c99734c 100644 (file)
@@ -432,6 +432,7 @@ AFSRemoveVolume( IN AFSVolumeCB *VolumeCB)
 
     NTSTATUS ntStatus = STATUS_SUCCESS;
     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
+    LONG lCount;
 
     __Enter
     {
@@ -506,7 +507,22 @@ AFSRemoveVolume( IN AFSVolumeCB *VolumeCB)
                 AFSReleaseResource( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
             }
 
-            AFSDeleteObjectInfo( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
+            lCount = AFSObjectInfoDecrement( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation,
+                                             AFS_OBJECT_REFERENCE_PIOCTL);
+
+            AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                          AFS_TRACE_LEVEL_VERBOSE,
+                          "AFSRemoveVolume Decrement count on object %p Cnt %d\n",
+                          VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation,
+                          lCount));
+
+            ASSERT( lCount == 0);
+
+            if ( lCount == 0)
+            {
+
+                AFSDeleteObjectInfo( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
+            }
 
             ExDeleteResourceLite( &VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
 
index ee5d1d4..2310268 100644 (file)
@@ -943,149 +943,18 @@ AFSIOWorkerThread( IN PVOID Context)
     return;
 }
 
-static BOOLEAN
-AFSExamineDirectory( IN AFSObjectInfoCB * pCurrentObject,
-                     IN AFSDirectoryCB  * pCurrentDirEntry)
-{
-    NTSTATUS ntStatus;
-    AFSFcb *pFcb = NULL;
-    AFSObjectInfoCB *pCurrentChildObject = NULL;
-    AFSVolumeCB * pVolumeCB = pCurrentObject->VolumeCB;
-    BOOLEAN bFcbBusy = FALSE;
-    LONG lCount;
-
-    pCurrentChildObject = pCurrentDirEntry->ObjectInformation;
-
-    AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING | AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
-                  AFS_TRACE_LEVEL_VERBOSE,
-                  "AFSExamineDirectory Deleting DE %wZ Object %p\n",
-                  &pCurrentDirEntry->NameInformation.FileName,
-                  pCurrentChildObject));
-
-    AFSDeleteDirEntry( pCurrentObject,
-                       pCurrentDirEntry);
-
-    if ( pCurrentChildObject != NULL)
-    {
-
-        //
-        // Acquire ObjectInfoLock shared here so as not to deadlock
-        // with an invalidation call from the service during AFSCleanupFcb
-        //
-
-        lCount = AFSObjectInfoIncrement( pCurrentChildObject,
-                                         AFS_OBJECT_REFERENCE_WORKER);
-
-        AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
-                      AFS_TRACE_LEVEL_VERBOSE,
-                      "AFSExamineDirectory Increment count on object %p Cnt %d\n",
-                      pCurrentChildObject,
-                      lCount));
-
-        if( lCount == 1 &&
-            pCurrentChildObject->Fcb != NULL &&
-            pCurrentChildObject->FileType == AFS_FILE_TYPE_FILE)
-        {
-
-            //
-            // We must not hold pVolumeCB->ObjectInfoTree.TreeLock exclusive
-            // across an AFSCleanupFcb call since it can deadlock with an
-            // invalidation call from the service.
-            //
-
-            AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
-
-            //
-            // 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
-            //
-
-            ntStatus = AFSCleanupFcb( pCurrentChildObject->Fcb,
-                                      TRUE);
-
-            if ( ntStatus == STATUS_RETRY)
-            {
-
-                bFcbBusy = TRUE;
-            }
-
-            AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                            TRUE);
-        }
-
-        AFSAcquireExcl( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock,
-                        TRUE);
-
-        lCount = AFSObjectInfoDecrement( pCurrentChildObject,
-                                         AFS_OBJECT_REFERENCE_WORKER);
-
-        AFSDbgTrace(( 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)
-        {
-
-            AFSRemoveFcb( &pCurrentChildObject->Fcb);
-
-            if( pCurrentChildObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
-                pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
-            {
-
-                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);
-
-                AFSDbgTrace(( 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);
-            }
-
-            AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
-
-            AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING | AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
-                          AFS_TRACE_LEVEL_VERBOSE,
-                          "AFSExamineDirectory Deleting object %p\n",
-                          pCurrentChildObject));
-
-            AFSDeleteObjectInfo( &pCurrentChildObject);
-        }
-        else
-        {
-
-            AFSReleaseResource( &pCurrentChildObject->NonPagedInfo->ObjectInfoLock);
-        }
-    }
-
-    return bFcbBusy;
-}
-
 //
-// Called with VolumeCB->ObjectInfoTree.TreeLock held shared.
-// The TreeLock will be released unless *pbReleaseVolumeLock is set to FALSE.
+// Called with VolumeCB->ObjectInfoTree.TreeLock held exclusive.
+// pCurrentObject->ObjectReferenceCount is incremented by the caller.
+//
+// The *pbReleaseVolumeLock is set to FALSE if the TreeLock is dropped
+// before returning.
+//
+// pCurrentObject must either be destroyed or the reference count
+// decremented before returning.
 //
 
-static BOOLEAN
+static void
 AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
                       IN BOOLEAN           bVolumeObject,
                       IN OUT BOOLEAN     * pbReleaseVolumeLock)
@@ -1097,125 +966,130 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
     AFSObjectInfoCB *pCurrentChildObject = NULL;
     AFSVolumeCB * pVolumeCB = pCurrentObject->VolumeCB;
     LARGE_INTEGER liCurrentTime;
-    BOOLEAN bFcbBusy = FALSE;
     LONG lCount;
     BOOLEAN bTemp;
 
-    switch ( pCurrentObject->FileType) {
+    __Enter
+    {
+
+        ASSERT( ExIsResourceAcquiredExclusiveLite( pVolumeCB->ObjectInfoTree.TreeLock));
+
+        switch ( pCurrentObject->FileType)
+        {
 
-    case AFS_FILE_TYPE_DIRECTORY:
+        case AFS_FILE_TYPE_DIRECTORY:
         {
 
             if ( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
             {
 
-                return FALSE;
+                try_return( ntStatus);
             }
 
             //
             // 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)
+            if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED))
             {
 
-                AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
-
-                //
-                // Dropping the TreeLock permits the
-                // pCurrentObject->ObjectReferenceCount to change
-                //
-
-                if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                    FALSE))
+                if ( pCurrentObject->ObjectReferenceCount == 1 &&
+                     ( pCurrentObject->Fcb == NULL ||
+                       pCurrentObject->Fcb->OpenReferenceCount == 0) &&
+                     pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL &&
+                     pCurrentObject->Specific.Directory.ChildOpenReferenceCount == 0)
                 {
 
                     AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
                                     TRUE);
 
-                    if ( pCurrentObject->ObjectReferenceCount == 0)
+                    if ( pCurrentObject->Fcb != NULL)
                     {
 
                         AFSRemoveFcb( &pCurrentObject->Fcb);
+                    }
 
-                        if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
-                        {
+                    if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
+                    {
 
-                            AFSAcquireExcl( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
-                                            TRUE);
+                        AFSAcquireExcl( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock,
+                                        TRUE);
 
-                            AFSRemoveFcb( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
+                        AFSRemoveFcb( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
 
-                            AFSReleaseResource( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
+                        AFSReleaseResource( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->NonPagedInfo->ObjectInfoLock);
 
-                            AFSDeleteObjectInfo( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
+                        lCount = AFSObjectInfoDecrement( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation,
+                                                         AFS_OBJECT_REFERENCE_PIOCTL);
 
-                            ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
+                        AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                                      AFS_TRACE_LEVEL_VERBOSE,
+                                      "AFSExamineObjectInfo Decrement count on object %p Cnt %d\n",
+                                      pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation,
+                                      lCount));
 
-                            AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
+                        ASSERT( lCount == 0);
 
-                            AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
-                                          AFS_TRACE_LEVEL_VERBOSE,
-                                          "AFSExamineObjectInfo (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
-                                          pCurrentObject->Specific.Directory.PIOCtlDirectoryCB));
+                        if ( lCount == 0)
+                        {
 
-                            AFSExFreePoolWithTag( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
+                            AFSDeleteObjectInfo( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
                         }
 
-                        AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
+                        ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock);
+
+                        AFSExFreePoolWithTag( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged, AFS_DIR_ENTRY_NP_TAG);
 
-                        AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
+                        AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_ALLOCATION,
                                       AFS_TRACE_LEVEL_VERBOSE,
-                                      "AFSExamineObjectInfo Deleting deleted object %p\n",
-                                      pCurrentObject));
+                                      "AFSExamineObjectInfo (pioctl) AFS_DIR_ENTRY_TAG deallocating %p\n",
+                                      pCurrentObject->Specific.Directory.PIOCtlDirectoryCB));
 
-                        AFSDeleteObjectInfo( &pCurrentObject);
-                    }
-                    else
-                    {
+                        AFSExFreePoolWithTag( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB, AFS_DIR_ENTRY_TAG);
 
-                        AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
+                        pCurrentObject->Specific.Directory.PIOCtlDirectoryCB = NULL;
                     }
 
-                    AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
-                }
-                else
-                {
+                    AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
 
-                    *pbReleaseVolumeLock = FALSE;
+                    lCount = AFSObjectInfoDecrement( pCurrentObject,
+                                                     AFS_OBJECT_REFERENCE_WORKER);
+
+                    AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                                  AFS_TRACE_LEVEL_VERBOSE,
+                                  "AFSExamineObjectInfo Decrement1 count on object %p Cnt %d\n",
+                                  pCurrentObject,
+                                  lCount));
+
+                    AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
+                                  AFS_TRACE_LEVEL_VERBOSE,
+                                  "AFSExamineObjectInfo Deleting deleted object %p\n",
+                                  pCurrentObject));
+
+                    //
+                    // The CurrentReferenceCount must be zero or we would not
+                    // have gotten this far.   It is safe to delete the ObjectInfoCB.
+                    //
+
+                    AFSDeleteObjectInfo( &pCurrentObject);
                 }
 
-                return bFcbBusy;
+                //
+                // Finished processing the AFS_OBJECT_FLAGS_DELETED case.
+                //
+
+                try_return( ntStatus);
             }
 
+            //
+            // pCurrentObject not marked Deleted.
+            //
+
             if ( pCurrentObject->Fcb != NULL &&
                  pCurrentObject->Fcb->CcbListHead != NULL)
             {
 
-                AFSCcb *pCcb;
-
-                for ( pCcb = pCurrentObject->Fcb->CcbListHead;
-                      pCcb;
-                      pCcb = (AFSCcb *)pCcb->ListEntry.fLink)
-                {
-
-                    if ( pCcb->NameArray) {
-
-                        AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
-                                      AFS_TRACE_LEVEL_VERBOSE,
-                                      "AFSExamineObjectInfo Found Object %p Fcb %p Ccb %p\n",
-                                      pCurrentObject,
-                                      pCurrentObject->Fcb,
-                                      pCcb));
-                    }
-                }
-
-                return bFcbBusy;
+                try_return( ntStatus);
             }
 
             if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0 ||
@@ -1223,41 +1097,44 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
                   pCurrentObject->Fcb->OpenReferenceCount > 0))
             {
 
-                return bFcbBusy;
+                try_return( ntStatus);
             }
 
-            if ( pCurrentObject->FileType != AFS_FILE_TYPE_DIRECTORY ||
+            if ( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
                  pCurrentObject->Specific.Directory.DirectoryNodeListHead != NULL)
             {
 
+                //
+                // Directory Entry Processing
+                //
+                // First pass is performed with the TreeLock held shared.
+                // If we detect any objects in use, we give up quickly without
+                // making any changes and without blocking other threads.
+                // The second pass is performed with the TreeLock held exclusive
+                // so deletions can take place.
+                //
+
                 if( !AFSAcquireShared( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
                                        FALSE))
                 {
 
-                    return bFcbBusy;
+                    try_return( ntStatus);
                 }
 
-                pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
-
-                //
-                // Directory Entry Processing
-                //
-
                 KeQueryTickCount( &liCurrentTime);
 
+                pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
+
                 while( pCurrentDirEntry != NULL)
                 {
 
-                    if( pCurrentDirEntry->DirOpenReferenceCount > 0)
+                    if( pCurrentDirEntry->DirOpenReferenceCount > 0 ||
+                        pCurrentDirEntry->NameArrayReferenceCount > 0)
                     {
 
-                        break;
-                    }
-
-                    if ( pCurrentDirEntry->NameArrayReferenceCount > 0)
-                    {
+                        AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
 
-                        break;
+                        try_return( ntStatus);
                     }
 
                     if ( pCurrentDirEntry->ObjectInformation != NULL)
@@ -1267,7 +1144,9 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
                              pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0)
                         {
 
-                            break;
+                            AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
+
+                            try_return( ntStatus);
                         }
 
                         if ( liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
@@ -1275,7 +1154,9 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
                              pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
                         {
 
-                            break;
+                            AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
+
+                            try_return( ntStatus);
                         }
 
                         if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY)
@@ -1309,45 +1190,30 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
                     pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
                 }
 
+                AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
+
                 if( pCurrentDirEntry != NULL)
                 {
 
-                    AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
-
-                    return bFcbBusy;
+                    try_return( ntStatus);
                 }
 
-                AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
-
-                AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
-
                 //
-                // Now acquire the locks excl without deadlocking
+                // Attempt the second pass with the TreeLock held exclusive.
+                // The the TreeLock cannot be obtained without blocking it means that
+                // the directory is in active use, so do nothing.
                 //
 
                 if( AFSAcquireExcl( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock,
                                     FALSE))
                 {
 
-                    if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                         FALSE))
-                    {
-
-                        AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
-
-                        *pbReleaseVolumeLock = FALSE;
-
-                        return bFcbBusy;
-                    }
-
                     if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0)
                     {
 
                         AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
 
-                        AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
-
-                        return bFcbBusy;
+                        try_return( ntStatus);
                     }
 
                     KeQueryTickCount( &liCurrentTime);
@@ -1421,13 +1287,21 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
                     if( pCurrentDirEntry != NULL)
                     {
 
-                        AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
+                        //
+                        // At least one entry in the directory is actively in use.
+                        // Drop the lock and exit without removing anything.
+                        //
 
-                        AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+                        AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
 
-                        return bFcbBusy;
+                        try_return( ntStatus);
                     }
 
+                    //
+                    // Third pass, process each directory entry and remove what we can.
+                    // The VolumeCB TreeLock and the ObjectInfo TreeLock are still held exclusive.
+                    //
+
                     pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead;
 
                     while( pCurrentDirEntry != NULL)
@@ -1435,8 +1309,20 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
 
                         pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink;
 
-                        AFSExamineDirectory( pCurrentObject,
-                                             pCurrentDirEntry);
+                        //
+                        // Delete the DirectoryCB which in turn removes the DIRENTRY reference
+                        // count from the associated ObjectInfoCB.  The reference count held above
+                        // may now be the only one left.
+                        //
+
+                        AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING | AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
+                                      AFS_TRACE_LEVEL_VERBOSE,
+                                      "AFSExamineObjectInfo Deleting DE %wZ Object %p\n",
+                                      &pCurrentDirEntry->NameInformation.FileName,
+                                      pCurrentDirEntry->ObjectInformation));
+
+                        AFSDeleteDirEntry( pCurrentObject,
+                                           pCurrentDirEntry);
 
                         pCurrentDirEntry = pNextDirEntry;
                     }
@@ -1448,24 +1334,6 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
                     ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED);
 
                     AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
-
-                    AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
-                }
-                else
-                {
-
-                    //
-                    // Try to grab the volume lock again ... no problem if we don't
-                    //
-
-                    if( !AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
-                                           FALSE))
-                    {
-
-                        *pbReleaseVolumeLock = FALSE;
-
-                        return bFcbBusy;
-                    }
                 }
             }
             else if ( bVolumeObject == FALSE)
@@ -1474,15 +1342,12 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
                 // No children
                 //
 
-                AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
-
-                if ( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                      FALSE))
+                if( pCurrentObject->ObjectReferenceCount > 1 ||
+                    pCurrentObject->Fcb != NULL &&
+                    pCurrentObject->Fcb->OpenReferenceCount > 0)
                 {
 
-                    *pbReleaseVolumeLock = FALSE;
-
-                    return bFcbBusy;
+                    try_return( ntStatus);
                 }
 
                 AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
@@ -1490,9 +1355,9 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
 
                 KeQueryTickCount( &liCurrentTime);
 
-                if( pCurrentObject->ObjectReferenceCount <= 0 &&
+                if( pCurrentObject->ObjectReferenceCount == 1 &&
                     ( pCurrentObject->Fcb == NULL ||
-                      pCurrentObject->Fcb->OpenReferenceCount <= 0) &&
+                      pCurrentObject->Fcb->OpenReferenceCount == 0) &&
                     liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
                     liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
                     pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
@@ -1502,6 +1367,20 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
 
                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
 
+                    lCount = AFSObjectInfoDecrement( pCurrentObject,
+                                                     AFS_OBJECT_REFERENCE_WORKER);
+
+                    AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                                  AFS_TRACE_LEVEL_VERBOSE,
+                                  "AFSExamineObjectInfo Decrement4 count on object %p Cnt %d\n",
+                                  pCurrentObject,
+                                  lCount));
+
+                    //
+                    // The Volume TreeLock is held exclusive.  Therefore, the ObjectReferenceCount
+                    // cannot change.  It is therefore safe to delete the ObjectInfoCB
+                    //
+
                     AFSDeleteObjectInfo( &pCurrentObject);
                 }
                 else
@@ -1509,73 +1388,69 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
 
                     AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
                 }
-
-                AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
             }
+
+            break;
         }
-        break;
 
-    case AFS_FILE_TYPE_FILE:
+        case AFS_FILE_TYPE_FILE:
         {
 
-            lCount = AFSObjectInfoIncrement( pCurrentObject,
-                                             AFS_OBJECT_REFERENCE_WORKER);
-
-            AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
-                          AFS_TRACE_LEVEL_VERBOSE,
-                          "AFSExamineObjectInfo Increment3 count on object %p Cnt %d\n",
-                          pCurrentObject,
-                          lCount));
+            if( pCurrentObject->ObjectReferenceCount > 1 ||
+                pCurrentObject->Fcb != NULL &&
+                pCurrentObject->Fcb->OpenReferenceCount > 0)
+            {
 
-            AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
+                try_return( ntStatus);
+            }
 
             if( pCurrentObject->Fcb != NULL)
             {
 
+                AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
+
                 //
-                // Dropping the TreeLock permits the
-                // pCurrentObject->ObjectReferenceCount to change
+                // Dropping the VolumeCB TreeLock permits the
+                // pCurrentObject->ObjectReferenceCount to change.
+                // But it cannot be held across the AFSCleanupFcb
+                // call.
                 //
 
                 ntStatus = AFSCleanupFcb( pCurrentObject->Fcb,
                                           FALSE);
 
-                if ( ntStatus == STATUS_RETRY)
+                if (!AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
+                                     FALSE))
                 {
 
-                    bFcbBusy = TRUE;
+                    *pbReleaseVolumeLock = FALSE;
                 }
-            }
 
-            bTemp = AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                    FALSE);
-
-            lCount = AFSObjectInfoDecrement( pCurrentObject,
-                                             AFS_OBJECT_REFERENCE_WORKER);
-
-            AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
-                          AFS_TRACE_LEVEL_VERBOSE,
-                          "AFSExamineObjectInfo Decrement3 count on object %p Cnt %d\n",
-                          pCurrentObject,
-                          lCount));
-
-            if ( bTemp == FALSE)
-            {
+                if ( ntStatus == STATUS_RETRY ||
+                     *pbReleaseVolumeLock == FALSE)
+                {
 
-                *pbReleaseVolumeLock = FALSE;
+                    //
+                    // The Fcb is in use.
+                    //
 
-                return bFcbBusy;
+                    try_return( ntStatus);
+                }
             }
 
+            //
+            // VolumeCB is held exclusive
+            //
+
             AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
                             TRUE);
 
             KeQueryTickCount( &liCurrentTime);
 
-            if( pCurrentObject->ObjectReferenceCount <= 0 &&
+            if( pCurrentObject->ObjectReferenceCount == 1 &&
                 ( pCurrentObject->Fcb == NULL ||
-                  ( pCurrentObject->Fcb->OpenReferenceCount <= 0 &&
-                    pCurrentObject->Fcb->Specific.File.ExtentsDirtyCount <= 0)) &&
+                  ( 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)
@@ -1585,6 +1460,20 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
 
                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
 
+                lCount = AFSObjectInfoDecrement( pCurrentObject,
+                                                 AFS_OBJECT_REFERENCE_WORKER);
+
+                AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                              AFS_TRACE_LEVEL_VERBOSE,
+                              "AFSExamineObjectInfo Decrement5 count on object %p Cnt %d\n",
+                              pCurrentObject,
+                              lCount));
+
+                //
+                // The VolumeCB TreeLock is held exclusive so the
+                // ObjectReferenceCount cannot change.
+                //
+
                 AFSDeleteObjectInfo( &pCurrentObject);
             }
             else
@@ -1593,32 +1482,20 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
             }
 
-            AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+            break;
         }
-        break;
 
-    default:
+        default:
         {
 
-            AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
-
-            if ( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                  FALSE))
-            {
-
-                *pbReleaseVolumeLock = FALSE;
-
-                return bFcbBusy;
-            }
-
             AFSAcquireExcl( &pCurrentObject->NonPagedInfo->ObjectInfoLock,
                             TRUE);
 
             KeQueryTickCount( &liCurrentTime);
 
-            if( pCurrentObject->ObjectReferenceCount <= 0 &&
+            if( pCurrentObject->ObjectReferenceCount == 1 &&
                 ( pCurrentObject->Fcb == NULL ||
-                  pCurrentObject->Fcb->OpenReferenceCount <= 0) &&
+                  pCurrentObject->Fcb->OpenReferenceCount == 0) &&
                 liCurrentTime.QuadPart > pCurrentObject->LastAccessCount.QuadPart &&
                 liCurrentTime.QuadPart - pCurrentObject->LastAccessCount.QuadPart >
                 pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
@@ -1628,6 +1505,20 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
 
                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
 
+                lCount = AFSObjectInfoDecrement( pCurrentObject,
+                                                 AFS_OBJECT_REFERENCE_WORKER);
+
+                AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                              AFS_TRACE_LEVEL_VERBOSE,
+                              "AFSExamineObjectInfo Decrement6 count on object %p Cnt %d\n",
+                              pCurrentObject,
+                              lCount));
+
+                //
+                // The VolumeCB TreeLock is held exclusive so the
+                // ObjectReferenceCount cannot change.
+                //
+
                 AFSDeleteObjectInfo( &pCurrentObject);
             }
             else
@@ -1635,36 +1526,68 @@ AFSExamineObjectInfo( IN AFSObjectInfoCB * pCurrentObject,
 
                 AFSReleaseResource( &pCurrentObject->NonPagedInfo->ObjectInfoLock);
             }
+        }
+        }
+
+      try_exit:
+
+        if ( pCurrentObject != NULL)
+        {
 
-            AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
+            lCount = AFSObjectInfoDecrement( pCurrentObject,
+                                             AFS_OBJECT_REFERENCE_WORKER);
+
+            AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                          AFS_TRACE_LEVEL_VERBOSE,
+                          "AFSExamineObjectInfo Decrement count on object %p Cnt %d\n",
+                          pCurrentObject,
+                          lCount));
         }
     }
-
-    return bFcbBusy;
 }
 
+//
+// Called with VolumeCB->VolumeLock held shared.
+//
 
-static BOOLEAN
+static void
 AFSExamineVolume( IN AFSVolumeCB *pVolumeCB)
 {
     NTSTATUS ntStatus = STATUS_SUCCESS;
     AFSObjectInfoCB *pCurrentObject = NULL, *pNextObject = NULL;
-    BOOLEAN bReleaseVolumeLock = FALSE;
+    BOOLEAN bReleaseVolumeTreeLock = FALSE;
     BOOLEAN bVolumeObject = FALSE;
-    BOOLEAN bFcbBusy = FALSE;
     LONG lCount;
 
-    if( AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock,
-                          FALSE))
+    //
+    // The Volume ObjectInfoTree TreeLock must be held exclusive to
+    // prevent other threads from obtaining a reference to an ObjectInfoCB
+    // via AFSFindObjectInfo() while it is being deleted.  This is
+    // annoying but the alternative is to hold the TreeLock shared during
+    // garbage collection and exclusive during find operations.
+    //
+
+    if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
+                        TRUE))
     {
 
-        bReleaseVolumeLock = TRUE;
+        bReleaseVolumeTreeLock = TRUE;
 
         pCurrentObject = pVolumeCB->ObjectInfoListHead;
 
+        lCount = AFSObjectInfoIncrement( pCurrentObject,
+                                         AFS_OBJECT_REFERENCE_WORKER);
+
+        AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                      AFS_TRACE_LEVEL_VERBOSE,
+                      "AFSExamineVolume Increment count on object %p Cnt %d\n",
+                      pCurrentObject,
+                      lCount));
+
         pNextObject = NULL;
 
-        while( pCurrentObject != NULL)
+        while( pCurrentObject != NULL &&
+               bReleaseVolumeTreeLock == TRUE)
         {
 
             if( pCurrentObject != &pVolumeCB->ObjectInformation)
@@ -1711,43 +1634,49 @@ AFSExamineVolume( IN AFSVolumeCB *pVolumeCB)
                 bVolumeObject = TRUE;
             }
 
-            bFcbBusy = AFSExamineObjectInfo( pCurrentObject, bVolumeObject, &bReleaseVolumeLock);
-
-            if ( pNextObject)
-            {
-
-                lCount = AFSObjectInfoDecrement( pNextObject,
-                                                 AFS_OBJECT_REFERENCE_WORKER);
-
-                AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
-                              AFS_TRACE_LEVEL_VERBOSE,
-                              "AFSExamineVolume Decrement count on object %p Cnt %d\n",
-                              pNextObject,
-                              lCount));
-            }
+            AFSExamineObjectInfo( pCurrentObject, bVolumeObject, &bReleaseVolumeTreeLock);
 
             //
-            // If AFSExamineObjectInfo drops the VolumeLock before returning
-            // we must halt processing of the Volume's ObjectInfo list.
+            // The CurrentObject is either destroyed or the reference count has been
+            // dropped by AFSExamineObjectInfo().
             //
 
-            if ( bReleaseVolumeLock == FALSE)
+            if ( bReleaseVolumeTreeLock == FALSE)
             {
 
-                break;
+                //
+                // Try to obtain the Volume's ObjectInfoTree.TreeLock after dropping
+                // other locks and continue.
+                //
+
+                bReleaseVolumeTreeLock = AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
+                                                         FALSE);
             }
 
             pCurrentObject = pNextObject;
+
+            pNextObject = NULL;
         }
 
-        if( bReleaseVolumeLock)
+        if ( pCurrentObject != NULL)
+        {
+
+            lCount = AFSObjectInfoDecrement( pCurrentObject,
+                                             AFS_OBJECT_REFERENCE_WORKER);
+
+            AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+                          AFS_TRACE_LEVEL_VERBOSE,
+                          "AFSExamineVolume Decrement count on object %p Cnt %d\n",
+                          pCurrentObject,
+                          lCount));
+        }
+
+        if( bReleaseVolumeTreeLock)
         {
 
             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
         }
     }
-
-    return bFcbBusy;
 }
 
 void
@@ -1762,7 +1691,6 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
     LONG TimeOut;
     KTIMER Timer;
     AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
-    BOOLEAN bFcbBusy = FALSE;
     LONG lCount;
 
     AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
@@ -1802,20 +1730,11 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
     {
 
-        if ( bFcbBusy == FALSE)
-        {
-
-            KeWaitForSingleObject( &Timer,
-                                   Executive,
-                                   KernelMode,
-                                   FALSE,
-                                   NULL);
-        }
-        else
-        {
-
-            bFcbBusy = FALSE;
-        }
+        KeWaitForSingleObject( &Timer,
+                               Executive,
+                               KernelMode,
+                               FALSE,
+                               NULL);
 
         //
         // This is the primary volume worker so it will traverse the volume list
@@ -1868,8 +1787,8 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
 
                 pNextVolume = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink;
 
-                AFSAcquireShared( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock,
-                                  TRUE);
+                AFSAcquireExcl( &pVolumeCB->ObjectInformation.NonPagedInfo->ObjectInfoLock,
+                                TRUE);
 
                 //
                 // If VolumeCB is idle, the Volume can be garbage collected
index 566c41c..cff9450 100644 (file)
@@ -168,7 +168,8 @@ NTSTATUS
 #define AFS_OBJECT_REFERENCE_STATUS                     6
 #define AFS_OBJECT_REFERENCE_FIND                       7
 #define AFS_OBJECT_REFERENCE_FS_REQ                     8
-#define AFS_OBJECT_REFERENCE_MAX                        9
+#define AFS_OBJECT_REFERENCE_PIOCTL                     9
+#define AFS_OBJECT_REFERENCE_MAX                       10
 
 //
 // Volume reference count reasons