3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the File Flush buffers routine for Fat called by the
20 // The Bug check file id for this module
23 #define BugCheckFileId (FAT_BUG_CHECK_FLUSH)
26 // The local debug trace level
29 #define Dbg (DEBUG_TRACE_FLUSH)
32 #pragma alloc_text(PAGE, FatCommonFlushBuffers)
33 #pragma alloc_text(PAGE, FatFlushDirectory)
34 #pragma alloc_text(PAGE, FatFlushFat)
35 #pragma alloc_text(PAGE, FatFlushFile)
36 #pragma alloc_text(PAGE, FatFlushVolume)
37 #pragma alloc_text(PAGE, FatFsdFlushBuffers)
38 #pragma alloc_text(PAGE, FatFlushDirentForFile)
39 #pragma alloc_text(PAGE, FatFlushFatEntries)
40 #pragma alloc_text(PAGE, FatHijackIrpAndFlushDevice)
44 // Local procedure prototypes
47 IO_COMPLETION_ROUTINE FatFlushCompletionRoutine
;
51 FatFlushCompletionRoutine (
52 _In_ PDEVICE_OBJECT DeviceObject
,
54 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
57 IO_COMPLETION_ROUTINE FatHijackCompletionRoutine
;
61 FatHijackCompletionRoutine (
62 _In_ PDEVICE_OBJECT DeviceObject
,
64 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
68 _Function_class_(IRP_MJ_FLUSH_BUFFERS
)
69 _Function_class_(DRIVER_DISPATCH
)\f
73 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject
,
81 This routine implements the FSD part of Flush buffers.
85 VolumeDeviceObject - Supplies the volume device object where the
86 file being flushed exists
88 Irp - Supplies the Irp being processed
92 NTSTATUS - The FSD status for the IRP
98 PIRP_CONTEXT IrpContext
= NULL
;
104 DebugTrace(+1, Dbg
, "FatFsdFlushBuffers\n", 0);
107 // Call the common Cleanup routine, with blocking allowed if synchronous
110 FsRtlEnterFileSystem();
112 TopLevel
= FatIsIrpTopLevel( Irp
);
116 IrpContext
= FatCreateIrpContext( Irp
, CanFsdWait( Irp
) );
118 Status
= FatCommonFlushBuffers( IrpContext
, Irp
);
120 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() )) {
123 // We had some trouble trying to perform the requested
124 // operation, so we'll abort the I/O request with
125 // the error status that we get back from the
129 Status
= FatProcessException( IrpContext
, Irp
, _SEH2_GetExceptionCode() );
132 if (TopLevel
) { IoSetTopLevelIrp( NULL
); }
134 FsRtlExitFileSystem();
137 // And return to our caller
140 DebugTrace(-1, Dbg
, "FatFsdFlushBuffers -> %08lx\n", Status
);
142 UNREFERENCED_PARAMETER( VolumeDeviceObject
);
148 _Requires_lock_held_(_Global_critical_region_
)
150 FatCommonFlushBuffers (
151 IN PIRP_CONTEXT IrpContext
,
159 This is the common routine for flushing a buffer.
163 Irp - Supplies the Irp to process
167 NTSTATUS - The return status for the operation
174 PIO_STACK_LOCATION IrpSp
;
176 PFILE_OBJECT FileObject
;
178 TYPE_OF_OPEN TypeOfOpen
;
184 BOOLEAN VcbAcquired
= FALSE
;
185 BOOLEAN FcbAcquired
= FALSE
;
186 BOOLEAN FatFlushRequired
= FALSE
;
190 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
192 DebugTrace(+1, Dbg
, "FatCommonFlushBuffers\n", 0);
193 DebugTrace( 0, Dbg
, "Irp = %p\n", Irp
);
194 DebugTrace( 0, Dbg
, "->FileObject = %p\n", IrpSp
->FileObject
);
197 // Extract and decode the file object
200 FileObject
= IrpSp
->FileObject
;
201 TypeOfOpen
= FatDecodeFileObject( FileObject
, &Vcb
, &Fcb
, &Ccb
);
204 // CcFlushCache is always synchronous, so if we can't wait enqueue
205 // the irp to the Fsp.
208 if ( !FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) ) {
210 Status
= FatFsdPostRequest( IrpContext
, Irp
);
212 DebugTrace(-1, Dbg
, "FatCommonFlushBuffers -> %08lx\n", Status
);
216 Status
= STATUS_SUCCESS
;
220 #if (NTDDI_VERSION >= NTDDI_WIN8)
222 if (FatDiskAccountingEnabled
) {
224 PETHREAD OriginatingThread
= NULL
;
227 // Charge the flush to the originating thread.
228 // Try the Thread in Irp's tail first, if that is NULL, then charge
229 // the flush to current thread.
232 if ((Irp
->Tail
.Overlay
.Thread
!= NULL
) &&
233 !IoIsSystemThread( Irp
->Tail
.Overlay
.Thread
)) {
235 OriginatingThread
= Irp
->Tail
.Overlay
.Thread
;
239 OriginatingThread
= PsGetCurrentThread();
242 NT_ASSERT( OriginatingThread
!= NULL
);
244 PsUpdateDiskCounters( PsGetThreadProcess( OriginatingThread
),
255 // Case on the type of open that we are trying to flush
258 switch (TypeOfOpen
) {
260 case VirtualVolumeFile
:
263 DebugTrace(0, Dbg
, "Flush that does nothing\n", 0);
268 DebugTrace(0, Dbg
, "Flush User File Open\n", 0);
270 (VOID
)FatAcquireExclusiveFcb( IrpContext
, Fcb
);
274 FatVerifyFcb( IrpContext
, Fcb
);
277 // If the file is cached then flush its cache
280 Status
= FatFlushFile( IrpContext
, Fcb
, Flush
);
283 // Also flush the file's dirent in the parent directory if the file
287 if (NT_SUCCESS( Status
)) {
290 // Insure that we get the filesize to disk correctly. This is
291 // benign if it was already good.
294 SetFlag(FileObject
->Flags
, FO_FILE_SIZE_CHANGED
);
297 FatUpdateDirentFromFcb( IrpContext
, FileObject
, Fcb
, Ccb
);
299 if (FlagOn(Fcb
->FcbState
, FCB_STATE_FLUSH_FAT
)) {
301 FatFlushRequired
= TRUE
;
305 // Flush the parent Dcb's to get any dirent updates to disk.
308 NextFcb
= Fcb
->ParentDcb
;
310 while (NextFcb
!= NULL
) {
313 // Make sure the Fcb is OK.
318 FatVerifyFcb( IrpContext
, NextFcb
);
320 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
321 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
323 FatResetExceptionState( IrpContext
);
326 if (NextFcb
->FcbCondition
== FcbGood
) {
328 NTSTATUS LocalStatus
;
330 LocalStatus
= FatFlushFile( IrpContext
, NextFcb
, Flush
);
332 if (!NT_SUCCESS(LocalStatus
)) {
334 Status
= LocalStatus
;
337 if (FlagOn(NextFcb
->FcbState
, FCB_STATE_FLUSH_FAT
)) {
339 FatFlushRequired
= TRUE
;
343 NextFcb
= NextFcb
->ParentDcb
;
347 // Flush the volume file to get any allocation information
351 if (FatFlushRequired
) {
353 Status
= FatFlushFat( IrpContext
, Vcb
);
355 ClearFlag(Fcb
->FcbState
, FCB_STATE_FLUSH_FAT
);
359 // Set the write through bit so that these modifications
360 // will be completed with the request.
363 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
);
368 case UserDirectoryOpen
:
371 // If the user had opened the root directory then we'll
372 // oblige by flushing the volume.
375 if (NodeType(Fcb
) != FAT_NTC_ROOT_DCB
) {
377 DebugTrace(0, Dbg
, "Flush a directory does nothing\n", 0);
383 DebugTrace(0, Dbg
, "Flush User Volume Open, or root dcb\n", 0);
386 // Acquire exclusive access to the Vcb.
392 #pragma prefast( suppress:28931, "needed for debug build" )
394 Finished
= FatAcquireExclusiveVcb( IrpContext
, Vcb
);
395 NT_ASSERT( Finished
);
401 // Mark the volume clean and then flush the volume file,
402 // and then all directories
405 Status
= FatFlushVolume( IrpContext
, Vcb
, Flush
);
408 // If the volume was dirty, do the processing that the delayed
409 // callback would have done.
412 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DIRTY
)) {
415 // Cancel any pending clean volumes.
418 (VOID
)KeCancelTimer( &Vcb
->CleanVolumeTimer
);
419 (VOID
)KeRemoveQueueDpc( &Vcb
->CleanVolumeDpc
);
422 // The volume is now clean, note it.
425 if (!FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_MOUNTED_DIRTY
)) {
427 FatMarkVolume( IrpContext
, Vcb
, VolumeClean
);
428 ClearFlag( Vcb
->VcbState
, VCB_STATE_FLAG_VOLUME_DIRTY
);
432 // Unlock the volume if it is removable.
435 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_REMOVABLE_MEDIA
) &&
436 !FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE
)) {
438 FatToggleMediaEjectDisable( IrpContext
, Vcb
, FALSE
);
447 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
449 FatBugCheck( TypeOfOpen
, 0, 0 );
452 FatUnpinRepinnedBcbs( IrpContext
);
456 DebugUnwind( FatCommonFlushBuffers
);
458 if (VcbAcquired
) { FatReleaseVcb( IrpContext
, Vcb
); }
460 if (FcbAcquired
) { FatReleaseFcb( IrpContext
, Fcb
); }
463 // If this is a normal termination then pass the request on
464 // to the target device object.
467 if (!_SEH2_AbnormalTermination()) {
469 #if (NTDDI_VERSION >= NTDDI_WIN8)
470 if ((IrpSp
->MinorFunction
!= IRP_MN_FLUSH_DATA_ONLY
) &&
471 (IrpSp
->MinorFunction
!= IRP_MN_FLUSH_NO_SYNC
)) {
474 NTSTATUS DriverStatus
;
477 // Get the next stack location, and copy over the stack location
480 IoCopyCurrentIrpStackLocationToNext(Irp
);
483 // Set up the completion routine
486 IoSetCompletionRoutine( Irp
,
487 FatFlushCompletionRoutine
,
488 ULongToPtr( Status
),
497 DriverStatus
= IoCallDriver(Vcb
->TargetDeviceObject
, Irp
);
499 if ((DriverStatus
== STATUS_PENDING
) ||
500 (!NT_SUCCESS(DriverStatus
) &&
501 (DriverStatus
!= STATUS_INVALID_DEVICE_REQUEST
))) {
503 Status
= DriverStatus
;
508 #if (NTDDI_VERSION >= NTDDI_WIN8)
513 // Complete the Irp if necessary and return to the caller.
516 FatCompleteRequest( IrpContext
, Irp
, Status
);
520 DebugTrace(-1, Dbg
, "FatCommonFlushBuffers -> %08lx\n", Status
);
527 _Requires_lock_held_(_Global_critical_region_
)
530 IN PIRP_CONTEXT IrpContext
,
532 IN FAT_FLUSH_TYPE FlushType
539 This routine non-recursively flushes a dcb tree.
543 Dcb - Supplies the Dcb being flushed
545 FlushType - Specifies the kind of flushing to perform
559 PBCB DirentBcb
= NULL
;
562 NTSTATUS ReturnStatus
= STATUS_SUCCESS
;
564 BOOLEAN ClearWriteThroughOnExit
= FALSE
;
565 BOOLEAN ClearWaitOnExit
= FALSE
;
567 ULONG CorrectedFileSize
= 0;
571 NT_ASSERT( FatVcbAcquiredExclusive(IrpContext
, Dcb
->Vcb
) );
573 DebugTrace(+1, Dbg
, "FatFlushDirectory, Dcb = %p\n", Dcb
);
576 // First flush all the files, then the directories, to make sure all the
577 // file sizes and times get sets correctly on disk.
579 // We also have to check here if the "Ea Data. Sf" fcb really
580 // corressponds to an existing file.
583 if (!FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
)) {
585 ClearWriteThroughOnExit
= TRUE
;
586 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
);
589 if (!FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
591 ClearWaitOnExit
= TRUE
;
592 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
598 while (Fcb
!= NULL
) {
600 NextFcb
= FatGetNextFcbTopDown(IrpContext
, Fcb
, Dcb
);
602 if ( (NodeType( Fcb
) == FAT_NTC_FCB
) &&
603 (Vcb
->EaFcb
!= Fcb
) &&
604 !IsFileDeleted(IrpContext
, Fcb
)) {
606 (VOID
)FatAcquireExclusiveFcb( IrpContext
, Fcb
);
608 ClearFlag( Vcb
->VcbState
, VCB_STATE_FLAG_DELETED_FCB
);
611 // Exception handler to catch and commute errors encountered
612 // doing the flush dance. We may encounter corruption, and
613 // should continue flushing the volume as much as possible.
619 // Standard handler to release resources, etc.
625 // Make sure the Fcb is OK.
630 FatVerifyFcb( IrpContext
, Fcb
);
632 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
633 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
635 FatResetExceptionState( IrpContext
);
639 // If this Fcb is not good skip it. Note that a 'continue'
640 // here would be very expensive as we inside a try{} body.
643 if (Fcb
->FcbCondition
!= FcbGood
) {
649 // In case a handle was never closed and the FS and AS are more
650 // than a cluster different, do this truncate.
653 if ( FlagOn(Fcb
->FcbState
, FCB_STATE_TRUNCATE_ON_CLOSE
) ) {
656 FatTruncateFileAllocation( IrpContext
,
658 Fcb
->Header
.FileSize
.LowPart
);
664 // Also compare the file's dirent in the parent directory
665 // with the size information in the Fcb and update
666 // it if neccessary. Note that we don't mark the Bcb dirty
667 // because we will be flushing the file object presently, and
668 // Mm knows what's really dirty.
671 FatGetDirentFromFcbOrDcb( IrpContext
,
678 CorrectedFileSize
= Fcb
->Header
.FileSize
.LowPart
;
681 if (Dirent
->FileSize
!= CorrectedFileSize
) {
683 Dirent
->FileSize
= CorrectedFileSize
;
689 // We must unpin the Bcb before the flush since we recursively tear up
690 // the tree if Mm decides that the data section is no longer referenced
691 // and the final close comes in for this file. If this parent has no
692 // more children as a result, we will try to initiate teardown on it
693 // and Cc will deadlock against the active count of this Bcb.
696 FatUnpinBcb( IrpContext
, DirentBcb
);
699 // Now flush the file. Note that this may make the Fcb
700 // go away if Mm dereferences its file object.
703 Status
= FatFlushFile( IrpContext
, Fcb
, FlushType
);
705 if (!NT_SUCCESS(Status
)) {
707 ReturnStatus
= Status
;
712 FatUnpinBcb( IrpContext
, DirentBcb
);
715 // Since we have the Vcb exclusive we know that if any closes
716 // come in it is because the CcPurgeCacheSection caused the
720 if ( !FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_DELETED_FCB
) ) {
722 FatReleaseFcb( (IRPCONTEXT
), Fcb
);
725 } _SEH2_EXCEPT( (FsRtlIsNtstatusExpected( ReturnStatus
= _SEH2_GetExceptionCode() ) != 0 ) ?
726 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
727 FatResetExceptionState( IrpContext
);
736 // OK, now flush the directories.
741 while (Fcb
!= NULL
) {
743 NextFcb
= FatGetNextFcbTopDown(IrpContext
, Fcb
, Dcb
);
745 if ( (NodeType( Fcb
) != FAT_NTC_FCB
) &&
746 !IsFileDeleted(IrpContext
, Fcb
) ) {
749 // Make sure the Fcb is OK.
754 FatVerifyFcb( IrpContext
, Fcb
);
756 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
757 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
759 FatResetExceptionState( IrpContext
);
762 if (Fcb
->FcbCondition
== FcbGood
) {
764 Status
= FatFlushFile( IrpContext
, Fcb
, FlushType
);
766 if (!NT_SUCCESS(Status
)) {
768 ReturnStatus
= Status
;
778 FatUnpinRepinnedBcbs( IrpContext
);
780 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() )) {
782 ReturnStatus
= IrpContext
->ExceptionStatus
;
785 if (ClearWriteThroughOnExit
) {
787 ClearFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
);
789 if (ClearWaitOnExit
) {
791 ClearFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
794 DebugTrace(-1, Dbg
, "FatFlushDirectory -> 0x%08lx\n", ReturnStatus
);
802 IN PIRP_CONTEXT IrpContext
,
810 The function carefully flushes the entire FAT for a volume. It is
811 nessecary to dance around a bit because of complicated synchronization
816 Vcb - Supplies the Vcb whose FAT is being flushed
827 IO_STATUS_BLOCK Iosb
;
828 LARGE_INTEGER Offset
;
830 NTSTATUS ReturnStatus
= STATUS_SUCCESS
;
835 // If this volume is write protected, no need to flush.
838 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
)) {
840 return STATUS_SUCCESS
;
844 // Make sure the Vcb is OK.
849 FatVerifyVcb( IrpContext
, Vcb
);
851 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
852 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
854 FatResetExceptionState( IrpContext
);
857 if (Vcb
->VcbCondition
!= VcbGood
) {
859 return STATUS_FILE_INVALID
;
863 // The only way we have to correctly synchronize things is to
864 // repin stuff, and then unpin repin it.
866 // With NT 5.0, we can use some new cache manager support to make
867 // this a lot more efficient (important for FAT32). Since we're
868 // only worried about ranges that are dirty - and since we're a
869 // modified-no-write stream - we can assume that if there is no
870 // BCB, there is no work to do in the range. I.e., the lazy writer
873 // This is much better than reading the entire FAT in and trying
874 // to punch it out (see the test in the write path to blow
875 // off writes that don't correspond to dirty ranges of the FAT).
876 // For FAT32, this would be a *lot* of reading.
879 if (Vcb
->AllocationSupport
.FatIndexBitSize
!= 12) {
882 // Walk through the Fat, one page at a time.
888 NumberOfPages
= ( FatReservedBytes(&Vcb
->Bpb
) +
889 FatBytesPerFat(&Vcb
->Bpb
) +
890 (PAGE_SIZE
- 1) ) / PAGE_SIZE
;
893 for ( Page
= 0, Offset
.QuadPart
= 0;
894 Page
< NumberOfPages
;
895 Page
++, Offset
.LowPart
+= PAGE_SIZE
) {
899 if (CcPinRead( Vcb
->VirtualVolumeFile
,
902 PIN_WAIT
| PIN_IF_BCB
,
906 CcSetDirtyPinnedData( Bcb
, NULL
);
909 CcUnpinRepinnedBcb( Bcb
, TRUE
, &Iosb
);
911 if (!NT_SUCCESS(Iosb
.Status
)) {
913 ReturnStatus
= Iosb
.Status
;
917 } _SEH2_EXCEPT(FatExceptionFilter(IrpContext
, _SEH2_GetExceptionInformation())) {
919 ReturnStatus
= IrpContext
->ExceptionStatus
;
927 // We read in the entire fat in the 12 bit case.
930 Offset
.QuadPart
= FatReservedBytes( &Vcb
->Bpb
);
934 if (CcPinRead( Vcb
->VirtualVolumeFile
,
936 FatBytesPerFat( &Vcb
->Bpb
),
937 PIN_WAIT
| PIN_IF_BCB
,
941 CcSetDirtyPinnedData( Bcb
, NULL
);
944 CcUnpinRepinnedBcb( Bcb
, TRUE
, &Iosb
);
946 if (!NT_SUCCESS(Iosb
.Status
)) {
948 ReturnStatus
= Iosb
.Status
;
952 } _SEH2_EXCEPT(FatExceptionFilter(IrpContext
, _SEH2_GetExceptionInformation())) {
954 ReturnStatus
= IrpContext
->ExceptionStatus
;
962 _Requires_lock_held_(_Global_critical_region_
)
965 IN PIRP_CONTEXT IrpContext
,
967 IN FAT_FLUSH_TYPE FlushType
974 The following routine is used to flush a volume to disk, including the
975 volume file, and ea file.
979 Vcb - Supplies the volume being flushed
981 FlushType - Specifies the kind of flushing to perform
985 NTSTATUS - The Status from the flush.
991 NTSTATUS ReturnStatus
= STATUS_SUCCESS
;
996 // If this volume is write protected, no need to flush.
999 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_WRITE_PROTECTED
)) {
1001 return STATUS_SUCCESS
;
1005 // Flush all the files and directories.
1008 Status
= FatFlushDirectory( IrpContext
, Vcb
->RootDcb
, FlushType
);
1010 if (!NT_SUCCESS(Status
)) {
1012 ReturnStatus
= Status
;
1016 // Now Flush the FAT
1019 Status
= FatFlushFat( IrpContext
, Vcb
);
1021 if (!NT_SUCCESS(Status
)) {
1023 ReturnStatus
= Status
;
1027 // Unlock the volume if it is removable.
1030 if (FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_REMOVABLE_MEDIA
) &&
1031 !FlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE
)) {
1033 FatToggleMediaEjectDisable( IrpContext
, Vcb
, FALSE
);
1036 return ReturnStatus
;
1040 _Requires_lock_held_(_Global_critical_region_
)
1043 IN PIRP_CONTEXT IrpContext
,
1045 IN FAT_FLUSH_TYPE FlushType
1050 Routine Description:
1052 This routine simply flushes the data section on a file.
1056 Fcb - Supplies the file being flushed
1058 FlushType - Specifies the kind of flushing to perform
1062 NTSTATUS - The Status from the flush.
1067 IO_STATUS_BLOCK Iosb
;
1068 PVCB Vcb
= Fcb
->Vcb
;
1072 CcFlushCache( &Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, &Iosb
);
1075 if ( !FlagOn( Vcb
->VcbState
, VCB_STATE_FLAG_DELETED_FCB
)) {
1078 // Grab and release PagingIo to serialize ourselves with the lazy writer.
1079 // This will work to ensure that all IO has completed on the cached
1082 // If we are to invalidate the file, now is the right time to do it. Do
1083 // it non-recursively so we don't thump children before their time.
1086 ExAcquireResourceExclusiveLite( Fcb
->Header
.PagingIoResource
, TRUE
);
1088 if (FlushType
== FlushAndInvalidate
) {
1090 FatMarkFcbCondition( IrpContext
, Fcb
, FcbBad
, FALSE
);
1093 ExReleaseResourceLite( Fcb
->Header
.PagingIoResource
);
1101 FatHijackIrpAndFlushDevice (
1102 IN PIRP_CONTEXT IrpContext
,
1104 IN PDEVICE_OBJECT TargetDeviceObject
1109 Routine Description:
1111 This routine is called when we need to send a flush to a device but
1112 we don't have a flush Irp. What this routine does is make a copy
1113 of its current Irp stack location, but changes the Irp Major code
1114 to a IRP_MJ_FLUSH_BUFFERS amd then send it down, but cut it off at
1115 the knees in the completion routine, fix it up and return to the
1116 user as if nothing had happened.
1120 Irp - The Irp to hijack
1122 TargetDeviceObject - The device to send the request to.
1126 NTSTATUS - The Status from the flush in case anybody cares.
1133 PIO_STACK_LOCATION NextIrpSp
;
1137 UNREFERENCED_PARAMETER( IrpContext
);
1140 // Get the next stack location, and copy over the stack location
1143 IoCopyCurrentIrpStackLocationToNext(Irp
);
1145 NextIrpSp
= IoGetNextIrpStackLocation( Irp
);
1146 NextIrpSp
->MajorFunction
= IRP_MJ_FLUSH_BUFFERS
;
1147 NextIrpSp
->MinorFunction
= 0;
1150 // Set up the completion routine
1153 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
1155 IoSetCompletionRoutine( Irp
,
1156 FatHijackCompletionRoutine
,
1163 // Send the request.
1166 Status
= IoCallDriver( TargetDeviceObject
, Irp
);
1168 if (Status
== STATUS_PENDING
) {
1170 KeWaitForSingleObject( &Event
, Executive
, KernelMode
, FALSE
, NULL
);
1172 Status
= Irp
->IoStatus
.Status
;
1176 // If the driver doesn't support flushes, return SUCCESS.
1179 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) {
1180 Status
= STATUS_SUCCESS
;
1183 Irp
->IoStatus
.Status
= 0;
1184 Irp
->IoStatus
.Information
= 0;
1191 FatFlushFatEntries (
1192 IN PIRP_CONTEXT IrpContext
,
1200 Routine Description:
1202 This macro flushes the FAT page(s) containing the passed in run.
1206 Vcb - Supplies the volume being flushed
1208 Cluster - The starting cluster
1210 Count - The number of FAT entries in the run
1220 LARGE_INTEGER FileOffset
;
1222 IO_STATUS_BLOCK Iosb
;
1226 FileOffset
.HighPart
= 0;
1227 FileOffset
.LowPart
= FatReservedBytes( &Vcb
->Bpb
);
1229 if (Vcb
->AllocationSupport
.FatIndexBitSize
== 12) {
1231 FileOffset
.LowPart
+= Cluster
* 3 / 2;
1232 ByteCount
= (Count
* 3 / 2) + 1;
1234 } else if (Vcb
->AllocationSupport
.FatIndexBitSize
== 32) {
1236 FileOffset
.LowPart
+= Cluster
* sizeof(ULONG
);
1237 ByteCount
= Count
* sizeof(ULONG
);
1241 FileOffset
.LowPart
+= Cluster
* sizeof( USHORT
);
1242 ByteCount
= Count
* sizeof( USHORT
);
1246 CcFlushCache( &Vcb
->SectionObjectPointers
,
1251 if (NT_SUCCESS(Iosb
.Status
)) {
1252 Iosb
.Status
= FatHijackIrpAndFlushDevice( IrpContext
,
1253 IrpContext
->OriginatingIrp
,
1254 Vcb
->TargetDeviceObject
);
1257 if (!NT_SUCCESS(Iosb
.Status
)) {
1258 FatNormalizeAndRaiseStatus(IrpContext
, Iosb
.Status
);
1264 FatFlushDirentForFile (
1265 IN PIRP_CONTEXT IrpContext
,
1271 Routine Description:
1273 This macro flushes the page containing a file's DIRENT in its parent.
1277 Fcb - Supplies the file whose DIRENT is being flushed
1286 LARGE_INTEGER FileOffset
;
1287 IO_STATUS_BLOCK Iosb
;
1291 FileOffset
.QuadPart
= Fcb
->DirentOffsetWithinDirectory
;
1293 CcFlushCache( &Fcb
->ParentDcb
->NonPaged
->SectionObjectPointers
,
1298 if (NT_SUCCESS(Iosb
.Status
)) {
1299 Iosb
.Status
= FatHijackIrpAndFlushDevice( IrpContext
,
1300 IrpContext
->OriginatingIrp
,
1301 Fcb
->Vcb
->TargetDeviceObject
);
1304 if (!NT_SUCCESS(Iosb
.Status
)) {
1305 FatNormalizeAndRaiseStatus(IrpContext
, Iosb
.Status
);
1311 // Local support routine
1316 FatFlushCompletionRoutine (
1317 IN PDEVICE_OBJECT DeviceObject
,
1323 NTSTATUS Status
= (NTSTATUS
) (ULONG_PTR
) Contxt
;
1325 if ( Irp
->PendingReturned
) {
1327 IoMarkIrpPending( Irp
);
1331 // If the Irp got STATUS_INVALID_DEVICE_REQUEST, normalize it
1332 // to STATUS_SUCCESS.
1335 if (NT_SUCCESS(Irp
->IoStatus
.Status
) ||
1336 (Irp
->IoStatus
.Status
== STATUS_INVALID_DEVICE_REQUEST
)) {
1338 Irp
->IoStatus
.Status
= Status
;
1341 UNREFERENCED_PARAMETER( DeviceObject
);
1342 UNREFERENCED_PARAMETER( Contxt
);
1344 return STATUS_SUCCESS
;
1348 // Local support routine
1353 FatHijackCompletionRoutine (
1354 _In_ PDEVICE_OBJECT DeviceObject
,
1356 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
1361 // Set the event so that our call will wake up.
1364 KeSetEvent( (PKEVENT
)Contxt
, 0, FALSE
);
1366 UNREFERENCED_PARAMETER( DeviceObject
);
1367 UNREFERENCED_PARAMETER( Irp
);
1369 return STATUS_MORE_PROCESSING_REQUIRED
;