[FASTFAT_NEW] Fix build with FASTFATDBG set
[reactos.git] / drivers / filesystems / fastfat_new / flush.c
1 /*++
2
3 Copyright (c) 1989-2000 Microsoft Corporation
4
5 Module Name:
6
7 Flush.c
8
9 Abstract:
10
11 This module implements the File Flush buffers routine for Fat called by the
12 dispatch driver.
13
14
15 --*/
16
17 #include "fatprocs.h"
18
19 //
20 // The Bug check file id for this module
21 //
22
23 #define BugCheckFileId (FAT_BUG_CHECK_FLUSH)
24
25 //
26 // The local debug trace level
27 //
28
29 #define Dbg (DEBUG_TRACE_FLUSH)
30
31 #ifdef ALLOC_PRAGMA
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)
41 #endif
42
43 //
44 // Local procedure prototypes
45 //
46
47 NTSTATUS
48 NTAPI
49 FatFlushCompletionRoutine (
50 IN PDEVICE_OBJECT DeviceObject,
51 IN PIRP Irp,
52 IN PVOID Contxt
53 );
54
55 NTSTATUS
56 NTAPI
57 FatHijackCompletionRoutine (
58 IN PDEVICE_OBJECT DeviceObject,
59 IN PIRP Irp,
60 IN PVOID Contxt
61 );
62
63 \f
64 NTSTATUS
65 NTAPI
66 FatFsdFlushBuffers (
67 IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
68 IN PIRP Irp
69 )
70
71 /*++
72
73 Routine Description:
74
75 This routine implements the FSD part of Flush buffers.
76
77 Arguments:
78
79 VolumeDeviceObject - Supplies the volume device object where the
80 file being flushed exists
81
82 Irp - Supplies the Irp being processed
83
84 Return Value:
85
86 NTSTATUS - The FSD status for the IRP
87
88 --*/
89
90 {
91 NTSTATUS Status;
92 PIRP_CONTEXT IrpContext = NULL;
93
94 BOOLEAN TopLevel;
95
96 PAGED_CODE();
97
98 DebugTrace(+1, Dbg, "FatFsdFlushBuffers\n", 0);
99
100 //
101 // Call the common Cleanup routine, with blocking allowed if synchronous
102 //
103
104 FsRtlEnterFileSystem();
105
106 TopLevel = FatIsIrpTopLevel( Irp );
107
108 _SEH2_TRY {
109
110 IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
111
112 Status = FatCommonFlushBuffers( IrpContext, Irp );
113
114 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
115
116 //
117 // We had some trouble trying to perform the requested
118 // operation, so we'll abort the I/O request with
119 // the error status that we get back from the
120 // execption code
121 //
122
123 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
124 } _SEH2_END;
125
126 if (TopLevel) { IoSetTopLevelIrp( NULL ); }
127
128 FsRtlExitFileSystem();
129
130 //
131 // And return to our caller
132 //
133
134 DebugTrace(-1, Dbg, "FatFsdFlushBuffers -> %08lx\n", Status);
135
136 UNREFERENCED_PARAMETER( VolumeDeviceObject );
137
138 return Status;
139 }
140
141 \f
142 NTSTATUS
143 FatCommonFlushBuffers (
144 IN PIRP_CONTEXT IrpContext,
145 IN PIRP Irp
146 )
147
148 /*++
149
150 Routine Description:
151
152 This is the common routine for flushing a buffer.
153
154 Arguments:
155
156 Irp - Supplies the Irp to process
157
158 Return Value:
159
160 NTSTATUS - The return status for the operation
161
162 --*/
163
164 {
165 NTSTATUS Status;
166
167 PIO_STACK_LOCATION IrpSp;
168
169 PFILE_OBJECT FileObject;
170
171 TYPE_OF_OPEN TypeOfOpen;
172 PVCB Vcb;
173 PFCB Fcb;
174 PCCB Ccb;
175
176 BOOLEAN VcbAcquired = FALSE;
177 BOOLEAN FcbAcquired = FALSE;
178
179 #ifndef __REACTOS__
180 PDIRENT Dirent;
181 #endif
182 PBCB DirentBcb = NULL;
183
184 PAGED_CODE();
185
186 IrpSp = IoGetCurrentIrpStackLocation( Irp );
187
188 DebugTrace(+1, Dbg, "FatCommonFlushBuffers\n", 0);
189 DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
190 DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject);
191
192 //
193 // Extract and decode the file object
194 //
195
196 FileObject = IrpSp->FileObject;
197 TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
198
199 //
200 // CcFlushCache is always synchronous, so if we can't wait enqueue
201 // the irp to the Fsp.
202 //
203
204 if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) {
205
206 Status = FatFsdPostRequest( IrpContext, Irp );
207
208 DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status );
209 return Status;
210 }
211
212 Status = STATUS_SUCCESS;
213
214 _SEH2_TRY {
215
216 //
217 // Case on the type of open that we are trying to flush
218 //
219
220 switch (TypeOfOpen) {
221
222 case VirtualVolumeFile:
223 case EaFile:
224 case DirectoryFile:
225
226 DebugTrace(0, Dbg, "Flush that does nothing\n", 0);
227 break;
228
229 case UserFileOpen:
230
231 DebugTrace(0, Dbg, "Flush User File Open\n", 0);
232
233 (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
234
235 FcbAcquired = TRUE;
236
237 FatVerifyFcb( IrpContext, Fcb );
238
239 //
240 // If the file is cached then flush its cache
241 //
242
243 Status = FatFlushFile( IrpContext, Fcb, Flush );
244
245 //
246 // Also update and flush the file's dirent in the parent directory if the
247 // file flush worked.
248 //
249
250 if (NT_SUCCESS( Status )) {
251
252 //
253 // Insure that we get the filesize to disk correctly. This is
254 // benign if it was already good.
255 //
256 // (why do we need to do this?)
257 //
258
259 SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
260
261 FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
262
263 //
264 // Flush the volume file to get any allocation information
265 // updates to disk.
266 //
267
268 if (FlagOn(Fcb->FcbState, FCB_STATE_FLUSH_FAT)) {
269
270 Status = FatFlushFat( IrpContext, Vcb );
271
272 ClearFlag(Fcb->FcbState, FCB_STATE_FLUSH_FAT);
273 }
274
275 //
276 // Set the write through bit so that these modifications
277 // will be completed with the request.
278 //
279
280 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
281 }
282
283 break;
284
285 case UserDirectoryOpen:
286
287 //
288 // If the user had opened the root directory then we'll
289 // oblige by flushing the volume.
290 //
291
292 if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) {
293
294 DebugTrace(0, Dbg, "Flush a directory does nothing\n", 0);
295 break;
296 }
297
298 case UserVolumeOpen:
299
300 DebugTrace(0, Dbg, "Flush User Volume Open, or root dcb\n", 0);
301
302 //
303 // Acquire exclusive access to the Vcb.
304 //
305
306 {
307 BOOLEAN Finished;
308 Finished = FatAcquireExclusiveVcb( IrpContext, Vcb );
309 ASSERT( Finished );
310 }
311
312 VcbAcquired = TRUE;
313
314 //
315 // Mark the volume clean and then flush the volume file,
316 // and then all directories
317 //
318
319 Status = FatFlushVolume( IrpContext, Vcb, Flush );
320
321 //
322 // If the volume was dirty, do the processing that the delayed
323 // callback would have done.
324 //
325
326 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) {
327
328 //
329 // Cancel any pending clean volumes.
330 //
331
332 (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
333 (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
334
335 //
336 // The volume is now clean, note it.
337 //
338
339 if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
340
341 FatMarkVolume( IrpContext, Vcb, VolumeClean );
342 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
343 }
344
345 //
346 // Unlock the volume if it is removable.
347 //
348
349 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
350 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
351
352 FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
353 }
354 }
355
356 break;
357
358 default:
359
360 FatBugCheck( TypeOfOpen, 0, 0 );
361 }
362
363 FatUnpinBcb( IrpContext, DirentBcb );
364
365 FatUnpinRepinnedBcbs( IrpContext );
366
367 } _SEH2_FINALLY {
368
369 DebugUnwind( FatCommonFlushBuffers );
370
371 FatUnpinBcb( IrpContext, DirentBcb );
372
373 if (VcbAcquired) { FatReleaseVcb( IrpContext, Vcb ); }
374
375 if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); }
376
377 //
378 // If this is a normal termination then pass the request on
379 // to the target device object.
380 //
381
382 if (!_SEH2_AbnormalTermination()) {
383
384 NTSTATUS DriverStatus;
385 PIO_STACK_LOCATION NextIrpSp;
386
387 //
388 // Get the next stack location, and copy over the stack location
389 //
390
391 NextIrpSp = IoGetNextIrpStackLocation( Irp );
392
393 *NextIrpSp = *IrpSp;
394
395 //
396 // Set up the completion routine
397 //
398
399 IoSetCompletionRoutine( Irp,
400 FatFlushCompletionRoutine,
401 ULongToPtr( Status ),
402 TRUE,
403 TRUE,
404 TRUE );
405
406 //
407 // Send the request.
408 //
409
410 DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp);
411
412 Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ?
413 Status : DriverStatus;
414
415 //
416 // Free the IrpContext and return to the caller.
417 //
418
419 FatCompleteRequest( IrpContext, FatNull, STATUS_SUCCESS );
420 }
421
422 DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status);
423 } _SEH2_END;
424
425 return Status;
426 }
427
428 \f
429 NTSTATUS
430 FatFlushDirectory (
431 IN PIRP_CONTEXT IrpContext,
432 IN PDCB Dcb,
433 IN FAT_FLUSH_TYPE FlushType
434 )
435
436 /*++
437
438 Routine Description:
439
440 This routine non-recursively flushes a dcb tree.
441
442 Arguments:
443
444 Dcb - Supplies the Dcb being flushed
445
446 FlushType - Specifies the kind of flushing to perform
447
448 Return Value:
449
450 VOID
451
452 --*/
453
454 {
455 PFCB Fcb;
456 PVCB Vcb;
457 PFCB NextFcb;
458
459 PDIRENT Dirent;
460 PBCB DirentBcb = NULL;
461
462 NTSTATUS Status;
463 NTSTATUS ReturnStatus = STATUS_SUCCESS;
464
465 BOOLEAN ClearWriteThroughOnExit = FALSE;
466 BOOLEAN ClearWaitOnExit = FALSE;
467
468 PAGED_CODE();
469
470 ASSERT( FatVcbAcquiredExclusive(IrpContext, Dcb->Vcb) );
471
472 DebugTrace(+1, Dbg, "FatFlushDirectory, Dcb = %08lx\n", Dcb);
473
474 //
475 // First flush all the files, then the directories, to make sure all the
476 // file sizes and times get sets correctly on disk.
477 //
478 // We also have to check here if the "Ea Data. Sf" fcb really
479 // corressponds to an existing file.
480 //
481
482 if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) {
483
484 ClearWriteThroughOnExit = TRUE;
485 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
486 }
487
488 if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
489
490 ClearWaitOnExit = TRUE;
491 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
492 }
493
494 Vcb = Dcb->Vcb;
495 Fcb = Dcb;
496
497 while (Fcb != NULL) {
498
499 NextFcb = FatGetNextFcbTopDown(IrpContext, Fcb, Dcb);
500
501 if ( (NodeType( Fcb ) == FAT_NTC_FCB) &&
502 (Vcb->EaFcb != Fcb) &&
503 !IsFileDeleted(IrpContext, Fcb)) {
504
505 (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
506
507 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
508
509 //
510 // Exception handler to catch and commute errors encountered
511 // doing the flush dance. We may encounter corruption, and
512 // should continue flushing the volume as much as possible.
513 //
514
515 _SEH2_TRY {
516
517 //
518 // Standard handler to release resources, etc.
519 //
520
521 _SEH2_TRY {
522
523 //
524 // Make sure the Fcb is OK.
525 //
526
527 _SEH2_TRY {
528
529 FatVerifyFcb( IrpContext, Fcb );
530
531 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
532 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
533
534 FatResetExceptionState( IrpContext );
535 } _SEH2_END;
536
537 //
538 // If this Fcb is not good skip it. Note that a 'continue'
539 // here would be very expensive as we inside a try{} body.
540 //
541
542 if (Fcb->FcbCondition != FcbGood) {
543
544 goto NextFcb;
545 }
546
547 //
548 // In case a handle was never closed and the FS and AS are more
549 // than a cluster different, do this truncate.
550 //
551
552 if ( FlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE) ) {
553
554 FatTruncateFileAllocation( IrpContext,
555 Fcb,
556 Fcb->Header.FileSize.LowPart );
557 }
558
559 //
560 // Also compare the file's dirent in the parent directory
561 // with the size information in the Fcb and update
562 // it if neccessary. Note that we don't mark the Bcb dirty
563 // because we will be flushing the file object presently, and
564 // Mm knows what's really dirty.
565 //
566
567 FatGetDirentFromFcbOrDcb( IrpContext,
568 Fcb,
569 &Dirent,
570 &DirentBcb );
571
572 if (Dirent->FileSize != Fcb->Header.FileSize.LowPart) {
573
574 Dirent->FileSize = Fcb->Header.FileSize.LowPart;
575 }
576
577 //
578 // We must unpin the Bcb before the flush since we recursively tear up
579 // the tree if Mm decides that the data section is no longer referenced
580 // and the final close comes in for this file. If this parent has no
581 // more children as a result, we will try to initiate teardown on it
582 // and Cc will deadlock against the active count of this Bcb.
583 //
584
585 FatUnpinBcb( IrpContext, DirentBcb );
586
587 //
588 // Now flush the file. Note that this may make the Fcb
589 // go away if Mm dereferences its file object.
590 //
591
592 Status = FatFlushFile( IrpContext, Fcb, FlushType );
593
594 if (!NT_SUCCESS(Status)) {
595
596 ReturnStatus = Status;
597 }
598
599 NextFcb: NOTHING;
600 } _SEH2_FINALLY {
601
602 FatUnpinBcb( IrpContext, DirentBcb );
603
604 //
605 // Since we have the Vcb exclusive we know that if any closes
606 // come in it is because the CcPurgeCacheSection caused the
607 // Fcb to go away.
608 //
609
610 if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB) ) {
611
612 FatReleaseFcb( (IRPCONTEXT), Fcb );
613 }
614 } _SEH2_END;
615
616 } _SEH2_EXCEPT( (ReturnStatus = FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode())) ?
617 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
618
619 FatResetExceptionState( IrpContext );
620 } _SEH2_END;
621 }
622
623 Fcb = NextFcb;
624 }
625
626 //
627 // OK, now flush the directories.
628 //
629
630 Fcb = Dcb;
631
632 while (Fcb != NULL) {
633
634 NextFcb = FatGetNextFcbTopDown(IrpContext, Fcb, Dcb);
635
636 if ( (NodeType( Fcb ) != FAT_NTC_FCB) &&
637 !IsFileDeleted(IrpContext, Fcb) ) {
638
639 //
640 // Make sure the Fcb is OK.
641 //
642
643 _SEH2_TRY {
644
645 FatVerifyFcb( IrpContext, Fcb );
646
647 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
648 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
649
650 FatResetExceptionState( IrpContext );
651 } _SEH2_END;
652
653 if (Fcb->FcbCondition == FcbGood) {
654
655 Status = FatFlushFile( IrpContext, Fcb, FlushType );
656
657 if (!NT_SUCCESS(Status)) {
658
659 ReturnStatus = Status;
660 }
661 }
662 }
663
664 Fcb = NextFcb;
665 }
666
667 _SEH2_TRY {
668
669 FatUnpinRepinnedBcbs( IrpContext );
670
671 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
672
673 ReturnStatus = IrpContext->ExceptionStatus;
674 } _SEH2_END;
675
676 if (ClearWriteThroughOnExit) {
677
678 ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
679 }
680 if (ClearWaitOnExit) {
681
682 ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
683 }
684
685 DebugTrace(-1, Dbg, "FatFlushDirectory -> 0x%08lx\n", ReturnStatus);
686
687 return ReturnStatus;
688 }
689
690 \f
691 NTSTATUS
692 FatFlushFat (
693 IN PIRP_CONTEXT IrpContext,
694 IN PVCB Vcb
695 )
696
697 /*++
698
699 Routine Description:
700
701 The function carefully flushes the entire FAT for a volume. It is
702 nessecary to dance around a bit because of complicated synchronization
703 reasons.
704
705 Arguments:
706
707 Vcb - Supplies the Vcb whose FAT is being flushed
708
709 Return Value:
710
711 VOID
712
713 --*/
714
715 {
716 PBCB Bcb;
717 PVOID DontCare;
718 IO_STATUS_BLOCK Iosb;
719 LARGE_INTEGER Offset;
720
721 NTSTATUS ReturnStatus = STATUS_SUCCESS;
722
723 PAGED_CODE();
724
725 //
726 // If this volume is write protected, no need to flush.
727 //
728
729 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
730
731 return STATUS_SUCCESS;
732 }
733
734 //
735 // Make sure the Vcb is OK.
736 //
737
738 _SEH2_TRY {
739
740 FatVerifyVcb( IrpContext, Vcb );
741
742 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
743 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
744
745 FatResetExceptionState( IrpContext );
746 } _SEH2_END;
747
748 if (Vcb->VcbCondition != VcbGood) {
749
750 return STATUS_FILE_INVALID;
751 }
752
753 //
754 // The only way we have to correctly synchronize things is to
755 // repin stuff, and then unpin repin it.
756 //
757 // With NT 5.0, we can use some new cache manager support to make
758 // this a lot more efficient (important for FAT32). Since we're
759 // only worried about ranges that are dirty - and since we're a
760 // modified-no-write stream - we can assume that if there is no
761 // BCB, there is no work to do in the range. I.e., the lazy writer
762 // beat us to it.
763 //
764 // This is much better than reading the entire FAT in and trying
765 // to punch it out (see the test in the write path to blow
766 // off writes that don't correspond to dirty ranges of the FAT).
767 // For FAT32, this would be a *lot* of reading.
768 //
769
770 if (Vcb->AllocationSupport.FatIndexBitSize != 12) {
771
772 //
773 // Walk through the Fat, one page at a time.
774 //
775
776 ULONG NumberOfPages;
777 ULONG Page;
778
779 NumberOfPages = ( FatReservedBytes(&Vcb->Bpb) +
780 FatBytesPerFat(&Vcb->Bpb) +
781 (PAGE_SIZE - 1) ) / PAGE_SIZE;
782
783
784 for ( Page = 0, Offset.QuadPart = 0;
785 Page < NumberOfPages;
786 Page++, Offset.LowPart += PAGE_SIZE ) {
787
788 _SEH2_TRY {
789
790 if (CcPinRead( Vcb->VirtualVolumeFile,
791 &Offset,
792 PAGE_SIZE,
793 PIN_WAIT | PIN_IF_BCB,
794 &Bcb,
795 &DontCare )) {
796
797 CcSetDirtyPinnedData( Bcb, NULL );
798 CcRepinBcb( Bcb );
799 CcUnpinData( Bcb );
800 CcUnpinRepinnedBcb( Bcb, TRUE, &Iosb );
801
802 if (!NT_SUCCESS(Iosb.Status)) {
803
804 ReturnStatus = Iosb.Status;
805 }
806 }
807
808 } _SEH2_EXCEPT(FatExceptionFilter(IrpContext, _SEH2_GetExceptionInformation())) {
809
810 ReturnStatus = IrpContext->ExceptionStatus;
811 continue;
812 } _SEH2_END;
813 }
814
815 } else {
816
817 //
818 // We read in the entire fat in the 12 bit case.
819 //
820
821 Offset.QuadPart = FatReservedBytes( &Vcb->Bpb );
822
823 _SEH2_TRY {
824
825 if (CcPinRead( Vcb->VirtualVolumeFile,
826 &Offset,
827 FatBytesPerFat( &Vcb->Bpb ),
828 PIN_WAIT | PIN_IF_BCB,
829 &Bcb,
830 &DontCare )) {
831
832 CcSetDirtyPinnedData( Bcb, NULL );
833 CcRepinBcb( Bcb );
834 CcUnpinData( Bcb );
835 CcUnpinRepinnedBcb( Bcb, TRUE, &Iosb );
836
837 if (!NT_SUCCESS(Iosb.Status)) {
838
839 ReturnStatus = Iosb.Status;
840 }
841 }
842
843 } _SEH2_EXCEPT(FatExceptionFilter(IrpContext, _SEH2_GetExceptionInformation())) {
844
845 ReturnStatus = IrpContext->ExceptionStatus;
846 } _SEH2_END;
847 }
848
849 return ReturnStatus;
850 }
851 \f
852
853 NTSTATUS
854 FatFlushVolume (
855 IN PIRP_CONTEXT IrpContext,
856 IN PVCB Vcb,
857 IN FAT_FLUSH_TYPE FlushType
858 )
859
860 /*++
861
862 Routine Description:
863
864 The following routine is used to flush a volume to disk, including the
865 volume file, and ea file.
866
867 Arguments:
868
869 Vcb - Supplies the volume being flushed
870
871 FlushType - Specifies the kind of flushing to perform
872
873 Return Value:
874
875 NTSTATUS - The Status from the flush.
876
877 --*/
878
879 {
880 NTSTATUS Status;
881 NTSTATUS ReturnStatus = STATUS_SUCCESS;
882
883 PAGED_CODE();
884
885 //
886 // If this volume is write protected, no need to flush.
887 //
888
889 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
890
891 return STATUS_SUCCESS;
892 }
893
894 //
895 // Flush all the files and directories.
896 //
897
898 Status = FatFlushDirectory( IrpContext, Vcb->RootDcb, FlushType );
899
900 if (!NT_SUCCESS(Status)) {
901
902 ReturnStatus = Status;
903 }
904
905 //
906 // Now Flush the FAT
907 //
908
909 Status = FatFlushFat( IrpContext, Vcb );
910
911 if (!NT_SUCCESS(Status)) {
912
913 ReturnStatus = Status;
914 }
915
916 //
917 // Unlock the volume if it is removable.
918 //
919
920 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
921 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
922
923 FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
924 }
925
926 return ReturnStatus;
927 }
928
929 \f
930 NTSTATUS
931 FatFlushFile (
932 IN PIRP_CONTEXT IrpContext,
933 IN PFCB Fcb,
934 IN FAT_FLUSH_TYPE FlushType
935 )
936
937 /*++
938
939 Routine Description:
940
941 This routine simply flushes the data section on a file.
942
943 Arguments:
944
945 Fcb - Supplies the file being flushed
946
947 FlushType - Specifies the kind of flushing to perform
948
949 Return Value:
950
951 NTSTATUS - The Status from the flush.
952
953 --*/
954
955 {
956 IO_STATUS_BLOCK Iosb;
957 PVCB Vcb = Fcb->Vcb;
958
959 PAGED_CODE();
960
961 CcFlushCache( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, &Iosb );
962
963 if ( !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB )) {
964
965 //
966 // Grab and release PagingIo to serialize ourselves with the lazy writer.
967 // This will work to ensure that all IO has completed on the cached
968 // data.
969 //
970 // If we are to invalidate the file, now is the right time to do it. Do
971 // it non-recursively so we don't thump children before their time.
972 //
973
974 ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE);
975
976 if (FlushType == FlushAndInvalidate) {
977
978 FatMarkFcbCondition( IrpContext, Fcb, FcbBad, FALSE );
979 }
980
981 ExReleaseResourceLite( Fcb->Header.PagingIoResource );
982 }
983
984 return Iosb.Status;
985 }
986
987 \f
988 NTSTATUS
989 FatHijackIrpAndFlushDevice (
990 IN PIRP_CONTEXT IrpContext,
991 IN PIRP Irp,
992 IN PDEVICE_OBJECT TargetDeviceObject
993 )
994
995 /*++
996
997 Routine Description:
998
999 This routine is called when we need to send a flush to a device but
1000 we don't have a flush Irp. What this routine does is make a copy
1001 of its current Irp stack location, but changes the Irp Major code
1002 to a IRP_MJ_FLUSH_BUFFERS amd then send it down, but cut it off at
1003 the knees in the completion routine, fix it up and return to the
1004 user as if nothing had happened.
1005
1006 Arguments:
1007
1008 Irp - The Irp to hijack
1009
1010 TargetDeviceObject - The device to send the request to.
1011
1012 Return Value:
1013
1014 NTSTATUS - The Status from the flush in case anybody cares.
1015
1016 --*/
1017
1018 {
1019 KEVENT Event;
1020 NTSTATUS Status;
1021 PIO_STACK_LOCATION NextIrpSp;
1022
1023 PAGED_CODE();
1024
1025 //
1026 // Get the next stack location, and copy over the stack location
1027 //
1028
1029 NextIrpSp = IoGetNextIrpStackLocation( Irp );
1030
1031 *NextIrpSp = *IoGetCurrentIrpStackLocation( Irp );
1032
1033 NextIrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
1034 NextIrpSp->MinorFunction = 0;
1035
1036 //
1037 // Set up the completion routine
1038 //
1039
1040 KeInitializeEvent( &Event, NotificationEvent, FALSE );
1041
1042 IoSetCompletionRoutine( Irp,
1043 FatHijackCompletionRoutine,
1044 &Event,
1045 TRUE,
1046 TRUE,
1047 TRUE );
1048
1049 //
1050 // Send the request.
1051 //
1052
1053 Status = IoCallDriver( TargetDeviceObject, Irp );
1054
1055 if (Status == STATUS_PENDING) {
1056
1057 KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
1058
1059 Status = Irp->IoStatus.Status;
1060 }
1061
1062 //
1063 // If the driver doesn't support flushes, return SUCCESS.
1064 //
1065
1066 if (Status == STATUS_INVALID_DEVICE_REQUEST) {
1067 Status = STATUS_SUCCESS;
1068 }
1069
1070 Irp->IoStatus.Status = 0;
1071 Irp->IoStatus.Information = 0;
1072
1073 return Status;
1074 }
1075
1076 \f
1077 VOID
1078 FatFlushFatEntries (
1079 IN PIRP_CONTEXT IrpContext,
1080 IN PVCB Vcb,
1081 IN ULONG Cluster,
1082 IN ULONG Count
1083 )
1084
1085 /*++
1086
1087 Routine Description:
1088
1089 This macro flushes the FAT page(s) containing the passed in run.
1090
1091 Arguments:
1092
1093 Vcb - Supplies the volume being flushed
1094
1095 Cluster - The starting cluster
1096
1097 Count - The number of FAT entries in the run
1098
1099 Return Value:
1100
1101 VOID
1102
1103 --*/
1104
1105 {
1106 ULONG ByteCount;
1107 LARGE_INTEGER FileOffset;
1108
1109 IO_STATUS_BLOCK Iosb;
1110
1111 PAGED_CODE();
1112
1113 FileOffset.HighPart = 0;
1114 FileOffset.LowPart = FatReservedBytes( &Vcb->Bpb );
1115
1116 if (Vcb->AllocationSupport.FatIndexBitSize == 12) {
1117
1118 FileOffset.LowPart += Cluster * 3 / 2;
1119 ByteCount = (Count * 3 / 2) + 1;
1120
1121 } else if (Vcb->AllocationSupport.FatIndexBitSize == 32) {
1122
1123 FileOffset.LowPart += Cluster * sizeof(ULONG);
1124 ByteCount = Count * sizeof(ULONG);
1125
1126 } else {
1127
1128 FileOffset.LowPart += Cluster * sizeof( USHORT );
1129 ByteCount = Count * sizeof( USHORT );
1130
1131 }
1132
1133 CcFlushCache( &Vcb->SectionObjectPointers,
1134 &FileOffset,
1135 ByteCount,
1136 &Iosb );
1137
1138 if (NT_SUCCESS(Iosb.Status)) {
1139 Iosb.Status = FatHijackIrpAndFlushDevice( IrpContext,
1140 IrpContext->OriginatingIrp,
1141 Vcb->TargetDeviceObject );
1142 }
1143
1144 if (!NT_SUCCESS(Iosb.Status)) {
1145 FatNormalizeAndRaiseStatus(IrpContext, Iosb.Status);
1146 }
1147 }
1148
1149 \f
1150 VOID
1151 FatFlushDirentForFile (
1152 IN PIRP_CONTEXT IrpContext,
1153 IN PFCB Fcb
1154 )
1155
1156 /*++
1157
1158 Routine Description:
1159
1160 This macro flushes the page containing a file's DIRENT in its parent.
1161
1162 Arguments:
1163
1164 Fcb - Supplies the file whose DIRENT is being flushed
1165
1166 Return Value:
1167
1168 VOID
1169
1170 --*/
1171
1172 {
1173 LARGE_INTEGER FileOffset;
1174 IO_STATUS_BLOCK Iosb;
1175
1176 PAGED_CODE();
1177
1178 FileOffset.QuadPart = Fcb->DirentOffsetWithinDirectory;
1179
1180 CcFlushCache( &Fcb->ParentDcb->NonPaged->SectionObjectPointers,
1181 &FileOffset,
1182 sizeof( DIRENT ),
1183 &Iosb );
1184
1185 if (NT_SUCCESS(Iosb.Status)) {
1186 Iosb.Status = FatHijackIrpAndFlushDevice( IrpContext,
1187 IrpContext->OriginatingIrp,
1188 Fcb->Vcb->TargetDeviceObject );
1189 }
1190
1191 if (!NT_SUCCESS(Iosb.Status)) {
1192 FatNormalizeAndRaiseStatus(IrpContext, Iosb.Status);
1193 }
1194 }
1195
1196 \f
1197 //
1198 // Local support routine
1199 //
1200
1201 NTSTATUS
1202 NTAPI
1203 FatFlushCompletionRoutine (
1204 IN PDEVICE_OBJECT DeviceObject,
1205 IN PIRP Irp,
1206 IN PVOID Contxt
1207 )
1208
1209 {
1210 NTSTATUS Status = (NTSTATUS) (ULONG_PTR) Contxt;
1211
1212 //
1213 // Add the hack-o-ramma to fix formats.
1214 //
1215
1216 if ( Irp->PendingReturned ) {
1217
1218 IoMarkIrpPending( Irp );
1219 }
1220
1221 //
1222 // If the Irp got STATUS_INVALID_DEVICE_REQUEST, normalize it
1223 // to STATUS_SUCCESS.
1224 //
1225
1226 if (Irp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) {
1227
1228 Irp->IoStatus.Status = Status;
1229 }
1230
1231 UNREFERENCED_PARAMETER( DeviceObject );
1232 UNREFERENCED_PARAMETER( Contxt );
1233
1234 return STATUS_SUCCESS;
1235 }
1236 \f
1237 //
1238 // Local support routine
1239 //
1240
1241 NTSTATUS
1242 NTAPI
1243 FatHijackCompletionRoutine (
1244 IN PDEVICE_OBJECT DeviceObject,
1245 IN PIRP Irp,
1246 IN PVOID Contxt
1247 )
1248
1249 {
1250 //
1251 // Set the event so that our call will wake up.
1252 //
1253
1254 KeSetEvent( (PKEVENT)Contxt, 0, FALSE );
1255
1256 UNREFERENCED_PARAMETER( DeviceObject );
1257 UNREFERENCED_PARAMETER( Irp );
1258
1259 return STATUS_MORE_PROCESSING_REQUIRED;
1260 }
1261