}
lCount = AFSObjectInfoIncrement( pObjectInfoCB,
- AFS_OBJECT_REFERENCE_DIRENTRY);
+ AFS_OBJECT_REFERENCE_PIOCTL);
AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
AFS_TRACE_LEVEL_VERBOSE,
{
lCount = AFSObjectInfoDecrement( pObjectInfoCB,
- AFS_OBJECT_REFERENCE_DIRENTRY);
+ AFS_OBJECT_REFERENCE_PIOCTL);
AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
AFS_TRACE_LEVEL_VERBOSE,
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;
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)
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 ||
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)
pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0)
{
- break;
+ AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
+
+ try_return( ntStatus);
}
if ( liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart ||
pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart)
{
- break;
+ AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock);
+
+ try_return( ntStatus);
}
if ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY)
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);
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)
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;
}
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)
// 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,
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)
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
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)
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
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)
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
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)
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
LONG TimeOut;
KTIMER Timer;
AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
- BOOLEAN bFcbBusy = FALSE;
LONG lCount;
AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
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
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