NTSTATUS FatFsdClose ( _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of Close. Arguments: VolumeDeviceObject - Supplies the volume device object where the file exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; PVCB Vcb; PFCB Fcb; PCCB Ccb; TYPE_OF_OPEN TypeOfOpen; BOOLEAN TopLevel; BOOLEAN VcbDeleted = FALSE; PAGED_CODE(); // // If we were called with our file system device object instead of a // volume device object, just complete this request with STATUS_SUCCESS // if (FatDeviceIsFatFsdo( VolumeDeviceObject)) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return STATUS_SUCCESS; } DebugTrace(+1, Dbg, "FatFsdClose\n", 0); // // Call the common Close routine // FsRtlEnterFileSystem(); TopLevel = FatIsIrpTopLevel( Irp ); // // Get a pointer to the current stack location and the file object // IrpSp = IoGetCurrentIrpStackLocation( Irp ); FileObject = IrpSp->FileObject; // // Decode the file object and set the read-only bit in the Ccb. // TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ); if (Ccb && IsFileObjectReadOnly(FileObject)) { SetFlag( Ccb->Flags, CCB_FLAG_READ_ONLY ); } try { PCLOSE_CONTEXT CloseContext = NULL; // // If we are top level, WAIT can be TRUE, otherwise make it FALSE // to avoid deadlocks, unless this is a top // level request not originating from the system process. // BOOLEAN Wait = TopLevel && (PsGetCurrentProcess() != FatData.OurProcess); #if (NTDDI_VERSION >= NTDDI_WIN8) // // To catch the odd case where a close comes in without a preceding cleanup, // call the oplock package to get rid of any oplock state. This can only // be safely done in the FSD path. // if ((Fcb != NULL) && !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) && FatIsFileOplockable( Fcb )) { // // This is equivalent to handling cleanup, and it always cleans up any // oplock immediately. Also, we don't need any locking of the FCB here; // the oplock's own lock will be sufficient for this purpose. // FsRtlCheckOplockEx( FatGetFcbOplock(Fcb), Irp, 0, NULL, NULL, NULL ); } #endif // // Call the common Close routine if we are not delaying this close. // if ((((TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen)) && FlagOn(Fcb->FcbState, FCB_STATE_DELAY_CLOSE) && !FatData.ShutdownStarted) || (FatCommonClose( Vcb, Fcb, Ccb, TypeOfOpen, Wait, TopLevel, &VcbDeleted ) == STATUS_PENDING)) { // // Metadata streams have had close contexts preallocated. // if (TypeOfOpen == VirtualVolumeFile) { NT_ASSERT( Vcb->CloseContext != NULL ); CloseContext = Vcb->CloseContext; Vcb->CloseContext = NULL; CloseContext->Free = TRUE; } else if ((TypeOfOpen == DirectoryFile) || (TypeOfOpen == EaFile)) { CloseContext = FatAllocateCloseContext( Vcb); NT_ASSERT( CloseContext != NULL ); CloseContext->Free = TRUE; } else { // // Free up any query template strings before using the close context fields, // which overlap (union) // FatDeallocateCcbStrings( Ccb ); CloseContext = &Ccb->CloseContext; CloseContext->Free = FALSE; SetFlag( Ccb->Flags, CCB_FLAG_CLOSE_CONTEXT ); } // // If the status is pending, then let's get the information we // need into the close context we already have bagged, complete // the request, and post it. It is important we allocate nothing // in the close path. // CloseContext->Vcb = Vcb; CloseContext->Fcb = Fcb; CloseContext->TypeOfOpen = TypeOfOpen; // // Send it off, either to an ExWorkerThread or to the async // close list. // FatQueueClose( CloseContext, (BOOLEAN)(Fcb && FlagOn(Fcb->FcbState, FCB_STATE_DELAY_CLOSE))); } else { // // The close proceeded synchronously, so for the metadata objects we // can now drop the close context we preallocated. // if ((TypeOfOpen == VirtualVolumeFile) || (TypeOfOpen == DirectoryFile) || (TypeOfOpen == EaFile)) { if (TypeOfOpen == VirtualVolumeFile) { // // If the VCB was deleted during the close, the close context for this // open has already been freed. // if (!VcbDeleted) { CloseContext = Vcb->CloseContext; Vcb->CloseContext = NULL; NT_ASSERT( CloseContext != NULL ); } else { CloseContext = NULL; } } else { CloseContext = FatAllocateCloseContext( (VcbDeleted ? NULL : Vcb) ); NT_ASSERT( CloseContext != NULL ); } if (CloseContext != NULL) { ExFreePool( CloseContext ); } } } FatCompleteRequest( FatNull, Irp, Status ); } except(FatExceptionFilter( NULL, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with the // error status that we get back from the execption code. // Status = FatProcessException( NULL, Irp, GetExceptionCode() ); } if (TopLevel) { IoSetTopLevelIrp( NULL ); } FsRtlExitFileSystem(); // // And return to our caller // DebugTrace(-1, Dbg, "FatFsdClose -> %08lx\n", Status); UNREFERENCED_PARAMETER( VolumeDeviceObject ); return Status; }
NTSTATUS FatFsdRead ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the driver entry to the common read routine for NtReadFile calls. For synchronous requests, the CommonRead is called with Wait == TRUE, which means the request will always be completed in the current thread, and never passed to the Fsp. If it is not a synchronous request, CommonRead is called with Wait == FALSE, which means the request will be passed to the Fsp only if there is a need to block. Arguments: VolumeDeviceObject - Supplies the volume device object where the file being Read exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { PFCB Fcb = NULL; NTSTATUS Status; PIRP_CONTEXT IrpContext = NULL; BOOLEAN TopLevel; DebugTrace(+1, Dbg, "FatFsdRead\n", 0); // // Call the common Read routine, with blocking allowed if synchronous // FsRtlEnterFileSystem(); // // We are first going to do a quick check for paging file IO. Since this // is a fast path, we must replicate the check for the fsdo. // if (!FatDeviceIsFatFsdo( IoGetCurrentIrpStackLocation(Irp)->DeviceObject)) { Fcb = (PFCB)(IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext); if ((NodeType(Fcb) == FAT_NTC_FCB) && FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) { // // Do the usual STATUS_PENDING things. // IoMarkIrpPending( Irp ); // // If there is not enough stack to do this read, then post this // read to the overflow queue. // if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) { KEVENT Event; PAGING_FILE_OVERFLOW_PACKET Packet; Packet.Irp = Irp; Packet.Fcb = Fcb; KeInitializeEvent( &Event, NotificationEvent, FALSE ); FsRtlPostPagingFileStackOverflow( &Packet, &Event, FatOverflowPagingFileRead ); // // And wait for the worker thread to complete the item // (VOID) KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL ); } else { // // Perform the actual IO, it will be completed when the io finishes. // FatPagingFileIo( Irp, Fcb ); } FsRtlExitFileSystem(); return STATUS_PENDING; } } try { TopLevel = FatIsIrpTopLevel( Irp ); IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) ); // // If this is an Mdl complete request, don't go through // common read. // if ( FlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE) ) { DebugTrace(0, Dbg, "Calling FatCompleteMdl\n", 0 ); try_return( Status = FatCompleteMdl( IrpContext, Irp )); } // // Check if we have enough stack space to process this request. If there // isn't enough then we will pass the request off to the stack overflow thread. // if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) { DebugTrace(0, Dbg, "Passing StackOverflowRead off\n", 0 ); try_return( Status = FatPostStackOverflowRead( IrpContext, Irp, Fcb ) ); } Status = FatCommonRead( IrpContext, Irp ); try_exit: NOTHING; } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = FatProcessException( IrpContext, Irp, GetExceptionCode() ); } if (TopLevel) { IoSetTopLevelIrp( NULL ); } FsRtlExitFileSystem(); // // And return to our caller // DebugTrace(-1, Dbg, "FatFsdRead -> %08lx\n", Status); UNREFERENCED_PARAMETER( VolumeDeviceObject ); return Status; }
NTSTATUS FatProcessException ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN NTSTATUS ExceptionCode ) /*++ Routine Description: This routine process an exception. It either completes the request with the saved exception status or it sends it off to IoRaiseHardError() Arguments: Irp - Supplies the Irp being processed ExceptionCode - Supplies the normalized exception status being handled Return Value: NTSTATUS - Returns the results of either posting the Irp or the saved completion status. --*/ { PVCB Vcb; PIO_STACK_LOCATION IrpSp; FAT_VOLUME_STATE TransitionState = VolumeDirty; ULONG SavedFlags; DebugTrace(0, Dbg, "FatProcessException\n", 0); // // If there is not an irp context, we must have had insufficient resources. // if ( !ARGUMENT_PRESENT( IrpContext ) ) { FatCompleteRequest( FatNull, Irp, ExceptionCode ); return ExceptionCode; } // // Get the real exception status from IrpContext->ExceptionStatus, and // reset it. // ExceptionCode = IrpContext->ExceptionStatus; FatResetExceptionState( IrpContext ); // // If this is an Mdl write request, then take care of the Mdl // here so that things get cleaned up properly. Cc now leaves // the MDL in place so a filesystem can retry after clearing an // internal condition (FAT does not). // #if __NDAS_FAT_WIN2K_SUPPORT__ if (NdFatCcMdlWriteAbort && (IrpContext->MajorFunction == IRP_MJ_WRITE) && (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE_MDL ) == IRP_MN_COMPLETE_MDL) && (Irp->MdlAddress != NULL)) { PIO_STACK_LOCATION LocalIrpSp = IoGetCurrentIrpStackLocation(Irp); NdFatCcMdlWriteAbort( LocalIrpSp->FileObject, Irp->MdlAddress ); Irp->MdlAddress = NULL; } #else if ((IrpContext->MajorFunction == IRP_MJ_WRITE) && (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE_MDL ) == IRP_MN_COMPLETE_MDL) && (Irp->MdlAddress != NULL)) { PIO_STACK_LOCATION LocalIrpSp = IoGetCurrentIrpStackLocation(Irp); CcMdlWriteAbort( LocalIrpSp->FileObject, Irp->MdlAddress ); Irp->MdlAddress = NULL; } #endif // // If we are going to post the request, we may have to lock down the // user's buffer, so do it here in a try except so that we failed the // request if the LockPages fails. // // Also unpin any repinned Bcbs, protected by the try {} except {} filter. // try { SavedFlags = IrpContext->Flags; // // Make sure we don't try to write through Bcbs // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH); FatUnpinRepinnedBcbs( IrpContext ); IrpContext->Flags = SavedFlags; // // If we will have to post the request, do it here. Note // that the last thing FatPrePostIrp() does is mark the Irp pending, // so it is critical that we actually return PENDING. Nothing // from this point to return can fail, so we are OK. // // We cannot do a verify operations at APC level because we // have to wait for Io operations to complete. // #if __NDAS_FAT__ if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) && (((ExceptionCode == STATUS_VERIFY_REQUIRED) && (KeGetCurrentIrql() >= APC_LEVEL)) || (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) && ExceptionCode == STATUS_CANT_WAIT))) { ExceptionCode = FatFsdPostRequest( IrpContext, Irp ); } #else if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) && (((ExceptionCode == STATUS_VERIFY_REQUIRED) && (KeGetCurrentIrql() >= APC_LEVEL)) || (ExceptionCode == STATUS_CANT_WAIT))) { ExceptionCode = FatFsdPostRequest( IrpContext, Irp ); } #endif } except( FatExceptionFilter( IrpContext, GetExceptionInformation() ) ) { ExceptionCode = IrpContext->ExceptionStatus; IrpContext->ExceptionStatus = 0; IrpContext->Flags = SavedFlags; } // // If we posted the request, just return here. // if (ExceptionCode == STATUS_PENDING) { return ExceptionCode; } Irp->IoStatus.Status = ExceptionCode; // // If this request is not a "top-level" irp, just complete it. // if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL)) { // // If there is a cache operation above us, commute verify // to a lock conflict. This will cause retries so that // we have a chance of getting through without needing // to return an unaesthetic error for the operation. // if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP && ExceptionCode == STATUS_VERIFY_REQUIRED) { ExceptionCode = STATUS_FILE_LOCK_CONFLICT; } FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } if (IoIsErrorUserInduced(ExceptionCode)) { // // Check for the various error conditions that can be caused by, // and possibly resolved by the user. // if (ExceptionCode == STATUS_VERIFY_REQUIRED) { PDEVICE_OBJECT Device; DebugTrace(0, Dbg, "Perform Verify Operation\n", 0); // // Now we are at the top level file system entry point. // // Grab the device to verify from the thread local storage // and stick it in the information field for transportation // to the fsp. We also clear the field at this time. // Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread ); IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL ); if ( Device == NULL ) { Device = IoGetDeviceToVerify( PsGetCurrentThread() ); IoSetDeviceToVerify( PsGetCurrentThread(), NULL ); ASSERT( Device != NULL ); } // // Let's not BugCheck just because the driver messed up. // if (Device == NULL) { ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR; FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } // // FatPerformVerify() will do the right thing with the Irp. return FatPerformVerify( IrpContext, Irp, Device ); } // // The other user induced conditions generate an error unless // they have been disabled for this request. // if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS)) { FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } else { // // Generate a pop-up // PDEVICE_OBJECT RealDevice; PVPB Vpb; PETHREAD Thread; if (IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL) { Vpb = IoGetCurrentIrpStackLocation(Irp)->FileObject->Vpb; } else { Vpb = NULL; } // // The device to verify is either in my thread local storage // or that of the thread that owns the Irp. // Thread = Irp->Tail.Overlay.Thread; RealDevice = IoGetDeviceToVerify( Thread ); if ( RealDevice == NULL ) { Thread = PsGetCurrentThread(); RealDevice = IoGetDeviceToVerify( Thread ); ASSERT( RealDevice != NULL ); } // // Let's not BugCheck just because the driver messed up. // if (RealDevice == NULL) { FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } // // This routine actually causes the pop-up. It usually // does this by queuing an APC to the callers thread, // but in some cases it will complete the request immediately, // so it is very important to IoMarkIrpPending() first. // IoMarkIrpPending( Irp ); IoRaiseHardError( Irp, Vpb, RealDevice ); // // We will be handing control back to the caller here, so // reset the saved device object. // IoSetDeviceToVerify( Thread, NULL ); // // The Irp will be completed by Io or resubmitted. In either // case we must clean up the IrpContext here. // FatDeleteIrpContext( IrpContext ); return STATUS_PENDING; } } // // This is just a run of the mill error. If is a STATUS that we // raised ourselves, and the information would be use for the // user, raise an informational pop-up. // IrpSp = IoGetCurrentIrpStackLocation( Irp ); Vcb = IrpContext->Vcb; // // Now, if the Vcb is unknown to us this means that the error was raised // in the process of a mount and before we even had a chance to build // a full Vcb - and was really handled there. // if (Vcb != NULL) { if ( !FatDeviceIsFatFsdo( IrpSp->DeviceObject) && !NT_SUCCESS(ExceptionCode) && !FsRtlIsTotalDeviceFailure(ExceptionCode) ) { TransitionState = VolumeDirtyWithSurfaceTest; } // // If this was a STATUS_FILE_CORRUPT or similar error indicating some // nastiness out on the media, then mark the volume permanently dirty. // if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS) && ( TransitionState == VolumeDirtyWithSurfaceTest || (ExceptionCode == STATUS_FILE_CORRUPT_ERROR) || (ExceptionCode == STATUS_DISK_CORRUPT_ERROR) || (ExceptionCode == STATUS_EA_CORRUPT_ERROR) || (ExceptionCode == STATUS_INVALID_EA_NAME) || (ExceptionCode == STATUS_EA_LIST_INCONSISTENT) || (ExceptionCode == STATUS_NO_EAS_ON_FILE) )) { ASSERT( NodeType(Vcb) == FAT_NTC_VCB ); SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ); // // Do the "dirty" work, ignoring any error. // try { FatMarkVolume( IrpContext, Vcb, TransitionState ); } except( FatExceptionFilter( IrpContext, GetExceptionInformation() ) ) { NOTHING; } } }
NTSTATUS FatFsdCleanup ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of closing down a handle to a file object. Arguments: VolumeDeviceObject - Supplies the volume device object where the file being Cleanup exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { NTSTATUS Status; PIRP_CONTEXT IrpContext = NULL; BOOLEAN TopLevel; PAGED_CODE(); #if __NDAS_FAT__ if ((PVOID)FatControlDeviceObject == VolumeDeviceObject) { Status = Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return Status; } #endif // // If we were called with our file system device object instead of a // volume device object, just complete this request with STATUS_SUCCESS // if ( FatDeviceIsFatFsdo( VolumeDeviceObject)) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return STATUS_SUCCESS; } DebugTrace(+1, Dbg, "FatFsdCleanup\n", 0); // // Call the common Cleanup routine, with blocking allowed. // FsRtlEnterFileSystem(); TopLevel = FatIsIrpTopLevel( Irp ); #if (__NDAS_FAT_PRIMARY__ || __NDAS_FAT_SECONDARY__) do { try { if (IrpContext == NULL) { IrpContext = FatCreateIrpContext( Irp, TRUE ); IrpContext->TopLevel = TopLevel; #if __NDAS_FAT_PRIMARY__ { ULONG_PTR stackBottom; ULONG_PTR stackTop; BOOLEAN validPrimaryRequest = FALSE; PPRIMARY_REQUEST_INFO primaryRequestInfo; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); primaryRequestInfo = (PPRIMARY_REQUEST_INFO)IoGetTopLevelIrp(); IoGetStackLimits( &stackTop, &stackBottom ); if ( (ULONG_PTR)primaryRequestInfo <= stackBottom - sizeof(PRIMARY_REQUEST_INFO) && (ULONG_PTR) primaryRequestInfo >= stackTop && (!FlagOn( (ULONG_PTR) primaryRequestInfo, 0x3 )) && primaryRequestInfo->PrimaryTag == 0xe2027482) { validPrimaryRequest = TRUE; } if (validPrimaryRequest) { //ASSERT( FatIsTopLevelRequest(IrpContext) ); IoSetTopLevelIrp( NULL ); TopLevel = FatIsIrpTopLevel( Irp ); ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL ); if (IsListEmpty(&VolumeDeviceObject->PrimarySessionQueue)) { NDAS_ASSERT( FALSE ); } IrpContext->PrimaryRequestInfo = *primaryRequestInfo; DebugTrace2( 0, Dbg, ("primaryRequestInfo = %p\n", primaryRequestInfo) ); } } #endif } #if __NDAS_FAT_SECONDARY__ if (IS_SECONDARY_FILEOBJECT(IoGetCurrentIrpStackLocation(Irp)->FileObject)) { BOOLEAN secondaryResourceAcquired = FALSE; BOOLEAN secondaryRecoveryResourceAcquired = FALSE; ASSERT( FatIsTopLevelRequest(IrpContext) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); Status = STATUS_SUCCESS; while (TRUE) { ASSERT( secondaryRecoveryResourceAcquired == FALSE ); ASSERT( secondaryResourceAcquired == FALSE ); if (FlagOn(VolumeDeviceObject->Secondary->Flags, SECONDARY_FLAG_RECONNECTING)) { if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { Status = FatFsdPostRequest( IrpContext, Irp ); break; } } if (FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { Status = FatFsdPostRequest( IrpContext, Irp ); break; } secondaryRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->RecoveryResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (!FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; continue; } secondaryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); try { SecondaryRecoverySessionStart( VolumeDeviceObject->Secondary, IrpContext ); } finally { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->Resource ); secondaryResourceAcquired = FALSE; SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; } continue; } secondaryResourceAcquired = SecondaryAcquireResourceSharedLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); 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 = FatCommonCleanup( IrpContext, Irp ); } finally { ASSERT( ExIsResourceAcquiredSharedLite(&VolumeDeviceObject->Resource) ); SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Resource ); } } } else Status = FatCommonCleanup( IrpContext, Irp ); #else Status = FatCommonCleanup( IrpContext, Irp ); #endif } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = FatProcessException( IrpContext, Irp, GetExceptionCode() ); } } while (Status == STATUS_CANT_WAIT);
NTSTATUS FatFsdClose ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of Close. Arguments: VolumeDeviceObject - Supplies the volume device object where the file exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; PVCB Vcb; PFCB Fcb; PCCB Ccb; TYPE_OF_OPEN TypeOfOpen; BOOLEAN TopLevel; BOOLEAN VcbDeleted; #ifdef __ND_FAT__ if ((PVOID)FatControlDeviceObject == VolumeDeviceObject) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return STATUS_SUCCESS; } #endif // // If we were called with our file system device object instead of a // volume device object, just complete this request with STATUS_SUCCESS // if (FatDeviceIsFatFsdo( VolumeDeviceObject)) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return STATUS_SUCCESS; } DebugTrace(+1, Dbg, "FatFsdClose\n", 0); // // Call the common Close routine // FsRtlEnterFileSystem(); TopLevel = FatIsIrpTopLevel( Irp ); // // Get a pointer to the current stack location and the file object // IrpSp = IoGetCurrentIrpStackLocation( Irp ); FileObject = IrpSp->FileObject; // // Decode the file object and set the read-only bit in the Ccb. // TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ); if (Ccb && IsFileObjectReadOnly(FileObject)) { SetFlag( Ccb->Flags, CCB_FLAG_READ_ONLY ); } try { PCLOSE_CONTEXT CloseContext; // // If we are top level, WAIT can be TRUE, otherwise make it FALSE // to avoid deadlocks, unless this is a top // level request not originating from the system process. // BOOLEAN Wait = TopLevel && (PsGetCurrentProcess() != FatData.OurProcess); #ifdef __ND_FAT__ if (Ccb) { SetFlag( Ccb->NdFatFlags, ND_FAT_CCB_FLAG_CLOSE ); ((PCCB)(FileObject->FsContext2))->FileObject = NULL; FileObject->FsContext = NULL; FileObject->FsContext2 = NULL; } #endif // // Call the common Close routine if we are not delaying this close. // if ((((TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen)) && FlagOn(Fcb->FcbState, FCB_STATE_DELAY_CLOSE) && !FatData.ShutdownStarted) || (FatCommonClose( Vcb, Fcb, Ccb, TypeOfOpen, Wait, &VcbDeleted ) == STATUS_PENDING)) { // // Metadata streams have had close contexts preallocated. // if (TypeOfOpen == VirtualVolumeFile || TypeOfOpen == DirectoryFile || TypeOfOpen == EaFile) { CloseContext = FatAllocateCloseContext(); ASSERT( CloseContext != NULL ); CloseContext->Free = TRUE; } else { // // Free up any query template strings before using the close context fields, // which overlap (union) // FatDeallocateCcbStrings( Ccb); CloseContext = &Ccb->CloseContext; CloseContext->Free = FALSE; SetFlag( Ccb->Flags, CCB_FLAG_CLOSE_CONTEXT ); } // // If the status is pending, then let's get the information we // need into the close context we already have bagged, complete // the request, and post it. It is important we allocate nothing // in the close path. // CloseContext->Vcb = Vcb; CloseContext->Fcb = Fcb; CloseContext->TypeOfOpen = TypeOfOpen; // // Send it off, either to an ExWorkerThread or to the async // close list. // FatQueueClose( CloseContext, (BOOLEAN)(Fcb && FlagOn(Fcb->FcbState, FCB_STATE_DELAY_CLOSE))); } else { // // The close proceeded synchronously, so for the metadata objects we // can now drop the close context we preallocated. // if (TypeOfOpen == VirtualVolumeFile || TypeOfOpen == DirectoryFile || TypeOfOpen == EaFile) { CloseContext = FatAllocateCloseContext(); ASSERT( CloseContext != NULL ); ExFreePool( CloseContext ); } } FatCompleteRequest( FatNull, Irp, Status ); } except(FatExceptionFilter( NULL, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with the // error status that we get back from the execption code. // Status = FatProcessException( NULL, Irp, GetExceptionCode() ); } if (TopLevel) { IoSetTopLevelIrp( NULL ); } FsRtlExitFileSystem(); // // And return to our caller // DebugTrace(-1, Dbg, "FatFsdClose -> %08lx\n", Status); UNREFERENCED_PARAMETER( VolumeDeviceObject ); return Status; }