VOID FatFspClose ( IN PVCB Vcb OPTIONAL ) /*++ Routine Description: This routine implements the FSP part of Close. Arguments: Vcb - If present, tells us to only close file objects opened on the specified volume. Return Value: None. --*/ { PCLOSE_CONTEXT CloseContext; PVCB CurrentVcb = NULL; PVCB LastVcb = NULL; BOOLEAN FreeContext = FALSE; BOOLEAN TopLevel = FALSE; ULONG LoopsWithVcbHeld = 0; PAGED_CODE(); DebugTrace(+1, Dbg, "FatFspClose\n", 0); // // Set the top level IRP for the true FSP operation. // if (!ARGUMENT_PRESENT( Vcb )) { IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP ); TopLevel = TRUE; } while ((CloseContext = FatRemoveClose(Vcb, LastVcb)) != NULL) { // // If we are in the FSP (i.e. Vcb == NULL), then try to keep ahead of // creates by doing several closes with one acquisition of the Vcb. // // Note that we cannot be holding the Vcb on entry to FatCommonClose // if this is last close as we will try to acquire FatData, and // worse the volume (and therefore the Vcb) may go away. // if (!ARGUMENT_PRESENT(Vcb)) { if (!FatData.ShutdownStarted) { if (CloseContext->Vcb != CurrentVcb) { LoopsWithVcbHeld = 0; // // Release a previously held Vcb, if any. // if (CurrentVcb != NULL) { ExReleaseResourceLite( &CurrentVcb->Resource); } // // Get the new Vcb. // CurrentVcb = CloseContext->Vcb; (VOID)ExAcquireResourceExclusiveLite( &CurrentVcb->Resource, TRUE ); } else { // // Share the resource occasionally if we seem to be finding a lot // of closes for a single volume. // if (++LoopsWithVcbHeld >= 20) { if (ExGetSharedWaiterCount( &CurrentVcb->Resource ) + ExGetExclusiveWaiterCount( &CurrentVcb->Resource )) { ExReleaseResourceLite( &CurrentVcb->Resource); (VOID)ExAcquireResourceExclusiveLite( &CurrentVcb->Resource, TRUE ); } LoopsWithVcbHeld = 0; } } // // Now check the Open count. We may be about to delete this volume! // // The test below must be <= 1 because there could still be outstanding // stream references on this VCB that are not counted in the OpenFileCount. // For example if there are no open files OpenFileCount could be zero and we would // not release the resource here. The call to FatCommonClose() below may cause // the VCB to be torn down and we will try to release memory we don't // own later. // if (CurrentVcb->OpenFileCount <= 1) { ExReleaseResourceLite( &CurrentVcb->Resource); CurrentVcb = NULL; } // // If shutdown has started while processing our list, drop the // current Vcb resource. // } else if (CurrentVcb != NULL) { ExReleaseResourceLite( &CurrentVcb->Resource); CurrentVcb = NULL; } } LastVcb = CurrentVcb; // // Call the common Close routine. Protected in a try {} except {} // try { // // The close context either is in the CCB, automatically freed, // or was from pool for a metadata fileobject, CCB is NULL, and // we'll need to free it. // FreeContext = CloseContext->Free; (VOID)FatCommonClose( CloseContext->Vcb, CloseContext->Fcb, (FreeContext ? NULL : CONTAINING_RECORD( CloseContext, CCB, CloseContext)), CloseContext->TypeOfOpen, TRUE, TopLevel, NULL ); } except(FatExceptionFilter( NULL, GetExceptionInformation() )) { // // Ignore anything we expect. // NOTHING; } // // Drop the context if it came from pool. // if (FreeContext) { ExFreePool( CloseContext ); } } // // Release a previously held Vcb, if any. // if (CurrentVcb != NULL) { ExReleaseResourceLite( &CurrentVcb->Resource); } // // Clean up the top level IRP hint if we owned it. // if (!ARGUMENT_PRESENT( Vcb )) { IoSetTopLevelIrp( NULL ); } // // And return to our caller // DebugTrace(-1, Dbg, "FatFspClose -> NULL\n", 0); }
VOID FatFspClose ( IN PVCB Vcb OPTIONAL ) /*++ Routine Description: This routine implements the FSP part of Close. Arguments: Vcb - If present, tells us to only close file objects opened on the specified volume. Return Value: None. --*/ { PCLOSE_CONTEXT CloseContext; PVCB CurrentVcb = NULL; PVCB LastVcb = NULL; BOOLEAN FreeContext; ULONG LoopsWithVcbHeld; DebugTrace(+1, Dbg, "FatFspClose\n", 0); // // Set the top level IRP for the true FSP operation. // if (!ARGUMENT_PRESENT( Vcb )) { IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP ); } while (CloseContext = FatRemoveClose(Vcb, LastVcb)) { #ifdef __ND_FAT_SECONDARY__ NTSTATUS Status; #endif // // If we are in the FSP (i.e. Vcb == NULL), then try to keep ahead of // creates by doing several closes with one acquisition of the Vcb. // // Note that we cannot be holding the Vcb on entry to FatCommonClose // if this is last close as we will try to acquire FatData, and // worse the volume (and therefore the Vcb) may go away. // if (!ARGUMENT_PRESENT(Vcb)) { if (!FatData.ShutdownStarted) { if (CloseContext->Vcb != CurrentVcb) { LoopsWithVcbHeld = 0; // // Release a previously held Vcb, if any. // if (CurrentVcb != NULL) { ExReleaseResourceLite( &CurrentVcb->Resource); } // // Get the new Vcb. // CurrentVcb = CloseContext->Vcb; (VOID)ExAcquireResourceExclusiveLite( &CurrentVcb->Resource, TRUE ); } else { // // Share the resource occasionally if we seem to be finding a lot // of closes for a single volume. // if (++LoopsWithVcbHeld >= 20) { if (ExGetSharedWaiterCount( &CurrentVcb->Resource ) + ExGetExclusiveWaiterCount( &CurrentVcb->Resource )) { ExReleaseResourceLite( &CurrentVcb->Resource); (VOID)ExAcquireResourceExclusiveLite( &CurrentVcb->Resource, TRUE ); } LoopsWithVcbHeld = 0; } } // // Now check the Open count. We may be about to delete this volume! // // The test below must be <= 1 because there could still be outstanding // stream references on this VCB that are not counted in the OpenFileCount. // For example if there are no open files OpenFileCount could be zero and we would // not release the resource here. The call to FatCommonClose() below may cause // the VCB to be torn down and we will try to release memory we don't // own later. // if (CurrentVcb->OpenFileCount <= 1) { ExReleaseResourceLite( &CurrentVcb->Resource); CurrentVcb = NULL; } // // If shutdown has started while processing our list, drop the // current Vcb resource. // } else if (CurrentVcb != NULL) { ExReleaseResourceLite( &CurrentVcb->Resource); CurrentVcb = NULL; } } LastVcb = CurrentVcb; // // Call the common Close routine. Protected in a try {} except {} // try { // // The close context either is in the CCB, automatically freed, // or was from pool for a metadata fileobject, CCB is NULL, and // we'll need to free it. // FreeContext = CloseContext->Free; #ifdef __ND_FAT_SECONDARY__ if (CloseContext->Fcb && FlagOn(CloseContext->Fcb->NdFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { PVOLUME_DEVICE_OBJECT VolumeDeviceObject = (CONTAINING_RECORD(CloseContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb)); BOOLEAN secondaryResourceAcquired = FALSE; BOOLEAN secondaryRecoveryResourceAcquired = FALSE; ASSERT( FreeContext == FALSE ); Status = STATUS_SUCCESS; while (TRUE) { ASSERT( secondaryRecoveryResourceAcquired == FALSE ); ASSERT( secondaryResourceAcquired == FALSE ); if (FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { if (FlagOn(VolumeDeviceObject->Vcb.NdFatFlags, ND_FAT_VCB_FLAG_TRY_CLOSE_FILES)) { Status = STATUS_CANT_WAIT; break; } secondaryRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( NULL, &VolumeDeviceObject->Secondary->RecoveryResource, TRUE ); if (!FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Secondary->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; continue; } secondaryResourceAcquired = SecondaryAcquireResourceExclusiveLite( NULL, &VolumeDeviceObject->Secondary->Resource, TRUE ); try { SessionRecovery( VolumeDeviceObject->Secondary, NULL ); } finally { SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Secondary->Resource ); secondaryResourceAcquired = FALSE; SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Secondary->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; } continue; } secondaryResourceAcquired = SecondaryAcquireResourceSharedLite( NULL, &VolumeDeviceObject->Secondary->Resource, TRUE ); if (secondaryResourceAcquired == FALSE) { ASSERT( FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) || FlagOn(VolumeDeviceObject->Secondary->Flags, SECONDARY_FLAG_RECONNECTING) ); continue; } break; } if (Status == STATUS_SUCCESS) { try { Status = FatCommonClose( CloseContext->Vcb, CloseContext->Fcb, (FreeContext ? NULL : CONTAINING_RECORD( CloseContext, CCB, CloseContext)), CloseContext->TypeOfOpen, TRUE, NULL ); } finally { ASSERT( ExIsResourceAcquiredSharedLite(&VolumeDeviceObject->Secondary->Resource) ); SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Secondary->Resource ); } } } else Status = FatCommonClose( CloseContext->Vcb, CloseContext->Fcb, (FreeContext ? NULL : CONTAINING_RECORD( CloseContext, CCB, CloseContext)), CloseContext->TypeOfOpen, TRUE, NULL ); #else (VOID)FatCommonClose( CloseContext->Vcb, CloseContext->Fcb, (FreeContext ? NULL : CONTAINING_RECORD( CloseContext, CCB, CloseContext)), CloseContext->TypeOfOpen, TRUE, NULL ); #endif } except(FatExceptionFilter( NULL, GetExceptionInformation() )) { // // Ignore anything we expect. // NOTHING; } // // Drop the context if it came from pool. // #ifdef __ND_FAT_SECONDARY__ if (Status == STATUS_CANT_WAIT) { ASSERT( FreeContext == FALSE ); ASSERT( CloseContext->Fcb && FlagOn(CloseContext->Fcb->FcbState, FCB_STATE_DELAY_CLOSE) ); FatQueueClose( CloseContext, (BOOLEAN)(CloseContext->Fcb && FlagOn(CloseContext->Fcb->FcbState, FCB_STATE_DELAY_CLOSE)) ); break; } if (FreeContext) { ExFreePool( CloseContext ); } #else if (FreeContext) { ExFreePool( CloseContext ); } #endif }