ReactOS 0.4.15-dev-8138-g1e75ea8
write.c File Reference
#include "fatprocs.h"
Include dependency graph for write.c:

Go to the source code of this file.

Macros

#define BugCheckFileId   (FAT_BUG_CHECK_WRITE)
 
#define Dbg   (DEBUG_TRACE_WRITE)
 
#define CollectWriteStats(VCB, OPEN_TYPE, BYTE_COUNT)
 

Functions

VOID NTAPI FatDeferredFlushDpc (_In_ PKDPC Dpc, _In_opt_ PVOID DeferredContext, _In_opt_ PVOID SystemArgument1, _In_opt_ PVOID SystemArgument2)
 
VOID NTAPI FatDeferredFlush (_In_ PVOID Parameter)
 
 _Function_class_ (IRP_MJ_WRITE)
 
 _Requires_lock_held_ (_Global_critical_region_)
 

Variables

BOOLEAN FatNoAsync = FALSE
 
KDEFERRED_ROUTINE FatDeferredFlushDpc
 
WORKER_THREAD_ROUTINE FatDeferredFlush
 

Macro Definition Documentation

◆ BugCheckFileId

#define BugCheckFileId   (FAT_BUG_CHECK_WRITE)

Definition at line 23 of file write.c.

◆ CollectWriteStats

#define CollectWriteStats (   VCB,
  OPEN_TYPE,
  BYTE_COUNT 
)
Value:
{ \
if (((OPEN_TYPE) == UserFileOpen)) { \
Stats->UserFileWrites += 1; \
Stats->UserFileWriteBytes += (ULONG)(BYTE_COUNT); \
} else if (((OPEN_TYPE) == VirtualVolumeFile || ((OPEN_TYPE) == DirectoryFile))) { \
Stats->MetaDataWrites += 1; \
Stats->MetaDataWriteBytes += (ULONG)(BYTE_COUNT); \
} \
}
@ UserFileOpen
Definition: cdprocs.h:577
struct _VCB VCB
FAT_DATA FatData
Definition: fatdata.c:56
@ DirectoryFile
Definition: fatprocs.h:1046
@ VirtualVolumeFile
Definition: fatprocs.h:1045
FORCEINLINE ULONG KeGetCurrentProcessorNumber(VOID)
Definition: ke.h:341
ULONG NumberProcessors
Definition: fatstruc.h:81
uint32_t ULONG
Definition: typedefs.h:59

Definition at line 35 of file write.c.

◆ Dbg

#define Dbg   (DEBUG_TRACE_WRITE)

Definition at line 29 of file write.c.

Function Documentation

◆ _Function_class_()

_Function_class_ ( IRP_MJ_WRITE  )

Definition at line 77 of file write.c.

105{
106 PFCB Fcb;
108 PIRP_CONTEXT IrpContext = NULL;
109
110 BOOLEAN ModWriter = FALSE;
112
113 DebugTrace(+1, Dbg, "FatFsdWrite\n", 0);
114
115 //
116 // Call the common Write routine, with blocking allowed if synchronous
117 //
118
120
121 //
122 // We are first going to do a quick check for paging file IO. Since this
123 // is a fast path, we must replicate the check for the fsdo.
124 //
125
127
129
130 if ((NodeType(Fcb) == FAT_NTC_FCB) &&
132
133 //
134 // Do the usual STATUS_PENDING things.
135 //
136
138
139 //
140 // Perform the actual IO, it will be completed when the io finishes.
141 //
142
144
146
147 return STATUS_PENDING;
148 }
149 }
150
151 _SEH2_TRY {
152
154
155 IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
156
157 //
158 // This is a kludge for the mod writer case. The correct state
159 // of recursion is set in IrpContext, however, we much with the
160 // actual top level Irp field to get the correct WriteThrough
161 // behaviour.
162 //
163
165
166 ModWriter = TRUE;
167
169 }
170
171 //
172 // If this is an Mdl complete request, don't go through
173 // common write.
174 //
175
176 if (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE )) {
177
178 DebugTrace(0, Dbg, "Calling FatCompleteMdl\n", 0 );
179 Status = FatCompleteMdl( IrpContext, Irp );
180
181 } else {
182
183 Status = FatCommonWrite( IrpContext, Irp );
184 }
185
187
188 //
189 // We had some trouble trying to perform the requested
190 // operation, so we'll abort the I/O request with
191 // the error status that we get back from the
192 // execption code
193 //
194
195 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
196 } _SEH2_END;
197
198// NT_ASSERT( !(ModWriter && (Status == STATUS_CANT_WAIT)) );
199
200 NT_ASSERT( !(ModWriter && TopLevel) );
201
203
204 if (TopLevel) { IoSetTopLevelIrp( NULL ); }
205
207
208 //
209 // And return to our caller
210 //
211
212 DebugTrace(-1, Dbg, "FatFsdWrite -> %08lx\n", Status);
213
214 UNREFERENCED_PARAMETER( VolumeDeviceObject );
215
216 return Status;
217}
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define CanFsdWait(I)
Definition: cdprocs.h:2001
_In_ PFCB Fcb
Definition: cdprocs.h:159
FCB * PFCB
Definition: cdstruc.h:1040
_In_ PIRP Irp
Definition: csq.h:116
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NodeType(P)
Definition: nodetype.h:51
#define FAT_NTC_FCB
Definition: nodetype.h:29
#define Dbg
Definition: write.c:29
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
NTSTATUS FatCompleteMdl(IN PIRP_CONTEXT IrpContext, IN PIRP Irp)
Definition: cachesup.c:1728
VOID FatPagingFileIo(IN PIRP Irp, IN PFCB Fcb)
Definition: deviosup.c:211
ULONG FatExceptionFilter(IN PIRP_CONTEXT IrpContext, IN PEXCEPTION_POINTERS ExceptionPointer)
Definition: fatdata.c:204
BOOLEAN FatIsIrpTopLevel(IN PIRP Irp)
Definition: fatdata.c:817
#define DebugTrace(INDENT, LEVEL, X, Y)
Definition: fatdata.h:313
IN PFCB IN PCCB IN TYPE_OF_OPEN IN BOOLEAN IN BOOLEAN TopLevel
Definition: fatprocs.h:2417
#define FatDeviceIsFatFsdo(D)
Definition: fatprocs.h:3095
PIRP_CONTEXT FatCreateIrpContext(IN PIRP Irp, IN BOOLEAN Wait)
Definition: strucsup.c:2301
#define FCB_STATE_PAGING_FILE
Definition: fatstruc.h:1195
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
#define FsRtlEnterFileSystem
#define FsRtlExitFileSystem
#define FSRTL_MOD_WRITE_TOP_LEVEL_IRP
Definition: fsrtltypes.h:61
Status
Definition: gdiplustypes.h:25
IoMarkIrpPending(Irp)
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
PIRP NTAPI IoGetTopLevelIrp(VOID)
Definition: irp.c:1843
VOID NTAPI IoSetTopLevelIrp(IN PIRP Irp)
Definition: irp.c:2000
#define STATUS_PENDING
Definition: ntstatus.h:82
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:66
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:164
Definition: cdstruc.h:902
ULONG FcbState
Definition: cdstruc.h:971
PFILE_OBJECT FileObject
Definition: iotypes.h:3169
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define IRP_MN_COMPLETE
Definition: iotypes.h:4420
#define NT_ASSERT
Definition: rtlfuncs.h:3310

◆ _Requires_lock_held_()

_Requires_lock_held_ ( _Global_critical_region_  )

Definition at line 220 of file write.c.

249{
250 PVCB Vcb;
252 PCCB Ccb;
253
256 ULONG FileSize = 0;
257 ULONG InitialFileSize = 0;
258 ULONG InitialValidDataLength = 0;
259
263
264 BOOLEAN PostIrp = FALSE;
265 BOOLEAN OplockPostIrp = FALSE;
266 BOOLEAN ExtendingFile = FALSE;
267 BOOLEAN FcbOrDcbAcquired = FALSE;
268 BOOLEAN SwitchBackToAsync = FALSE;
269 BOOLEAN CalledByLazyWriter = FALSE;
270 BOOLEAN ExtendingValidData = FALSE;
271 BOOLEAN FcbAcquiredExclusive = FALSE;
272 BOOLEAN FcbCanDemoteToShared = FALSE;
273 BOOLEAN WriteFileSizeToDirent = FALSE;
274 BOOLEAN RecursiveWriteThrough = FALSE;
275 BOOLEAN UnwindOutstandingAsync = FALSE;
276 BOOLEAN PagingIoResourceAcquired = FALSE;
277 BOOLEAN SuccessfulPurge = FALSE;
278
279 BOOLEAN SynchronousIo;
280 BOOLEAN WriteToEof;
281 BOOLEAN PagingIo;
282 BOOLEAN NonCachedIo;
285
286 FAT_IO_CONTEXT StackFatIoContext;
287
288 //
289 // A system buffer is only used if we have to access the buffer directly
290 // from the Fsp to clear a portion or to do a synchronous I/O, or a
291 // cached transfer. It is possible that our caller may have already
292 // mapped a system buffer, in which case we must remember this so
293 // we do not unmap it on the way out.
294 //
295
296 PVOID SystemBuffer = (PVOID) NULL;
297
298 LARGE_INTEGER StartingByte;
299
300 PAGED_CODE();
301
302 //
303 // Get current Irp stack location and file object
304 //
305
308
309
310 DebugTrace(+1, Dbg, "FatCommonWrite\n", 0);
311 DebugTrace( 0, Dbg, "Irp = %p\n", Irp);
312 DebugTrace( 0, Dbg, "ByteCount = %8lx\n", IrpSp->Parameters.Write.Length);
313 DebugTrace( 0, Dbg, "ByteOffset.LowPart = %8lx\n", IrpSp->Parameters.Write.ByteOffset.LowPart);
314 DebugTrace( 0, Dbg, "ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Write.ByteOffset.HighPart);
315
316 //
317 // Initialize the appropriate local variables.
318 //
319
320 Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
321 PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
322 NonCachedIo = BooleanFlagOn(Irp->Flags,IRP_NOCACHE);
323 SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
324
325 //NT_ASSERT( PagingIo || FileObject->WriteAccess );
326
327 //
328 // Extract the bytecount and do our noop/throttle checking.
329 //
330
332
333 //
334 // If there is nothing to write, return immediately.
335 //
336
337 if (ByteCount == 0) {
338
339 Irp->IoStatus.Information = 0;
340 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
341 return STATUS_SUCCESS;
342 }
343
344 //
345 // See if we have to defer the write.
346 //
347
348 if (!NonCachedIo &&
350 ByteCount,
351 (BOOLEAN)(Wait && !BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_IN_FSP)),
352 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE))) {
353
354 BOOLEAN Retrying = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE);
355
356 FatPrePostIrp( IrpContext, Irp );
357
358 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE );
359
362 IrpContext,
363 Irp,
364 ByteCount,
365 Retrying );
366
367 return STATUS_PENDING;
368 }
369
370 //
371 // Determine our starting position and type. If we are writing
372 // at EOF, then we will need additional synchronization before
373 // the IO is issued to determine where the data will go.
374 //
375
376 StartingByte = IrpSp->Parameters.Write.ByteOffset;
377 StartingVbo = StartingByte.LowPart;
378
379 WriteToEof = ( (StartingByte.LowPart == FILE_WRITE_TO_END_OF_FILE) &&
380 (StartingByte.HighPart == -1) );
381
382 //
383 // Extract the nature of the write from the file object, and case on it
384 //
385
387
388 NT_ASSERT( Vcb != NULL );
389
390 //
391 // Save callers who try to do cached IO to the raw volume from themselves.
392 //
393
394 if (TypeOfOpen == UserVolumeOpen) {
395
396 NonCachedIo = TRUE;
397 }
398
399 NT_ASSERT(!(NonCachedIo == FALSE && TypeOfOpen == VirtualVolumeFile));
400
401 //
402 // Collect interesting statistics. The FLAG_USER_IO bit will indicate
403 // what type of io we're doing in the FatNonCachedIo function.
404 //
405
406 if (PagingIo) {
408
409 if (TypeOfOpen == UserFileOpen) {
410 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
411 } else {
412 ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
413 }
414 }
415
416 //
417 // We must disallow writes to regular objects that would require us
418 // to maintain an AllocationSize of greater than 32 significant bits.
419 //
420 // If this is paging IO, this is simply a case where we need to trim.
421 // This will occur in due course.
422 //
423
424 if (!PagingIo && !WriteToEof && (TypeOfOpen != UserVolumeOpen)) {
425
426
427 if (!FatIsIoRangeValid( Vcb, StartingByte, ByteCount)) {
428
429
430 Irp->IoStatus.Information = 0;
432
433 return STATUS_DISK_FULL;
434 }
435 }
436
437 //
438 // Allocate if necessary and initialize a FAT_IO_CONTEXT block for
439 // all non cached Io. For synchronous Io
440 // we use stack storage, otherwise we allocate pool.
441 //
442
443 if (NonCachedIo) {
444
445 if (IrpContext->FatIoContext == NULL) {
446
447 if (!Wait) {
448
449 IrpContext->FatIoContext =
450 FsRtlAllocatePoolWithTag( NonPagedPoolNx,
451 sizeof(FAT_IO_CONTEXT),
453
454 } else {
455
456 IrpContext->FatIoContext = &StackFatIoContext;
457
458 SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT );
459 }
460 }
461
462 RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );
463
464 if (Wait) {
465
466 KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
468 FALSE );
469
470 } else {
471
472 if (PagingIo) {
473
474 IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
476
477 } else {
478
479 IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
480 ((ULONG_PTR)IrpContext->FatIoContext) | 3;
481 }
482
483 IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
484 ByteCount;
485
486 IrpContext->FatIoContext->Wait.Async.FileObject = FileObject;
487 }
488
489 }
490
491 //
492 // Check if this volume has already been shut down. If it has, fail
493 // this write request.
494 //
495
496 if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN) ) {
497
498 Irp->IoStatus.Information = 0;
499 FatCompleteRequest( IrpContext, Irp, STATUS_TOO_LATE );
500 return STATUS_TOO_LATE;
501 }
502
503 //
504 // This case corresponds to a write of the volume file (only the first
505 // fat allowed, the other fats are written automatically in parallel).
506 //
507 // We use an Mcb keep track of dirty sectors. Actual entries are Vbos
508 // and Lbos (ie. bytes), though they are all added in sector chunks.
509 // Since Vbo == Lbo for the volume file, the Mcb entries
510 // alternate between runs of Vbo == Lbo, and holes (Lbo == 0). We use
511 // the prior to represent runs of dirty fat sectors, and the latter
512 // for runs of clean fat. Note that since the first part of the volume
513 // file (boot sector) is always clean (a hole), and an Mcb never ends in
514 // a hole, there must always be an even number of runs(entries) in the Mcb.
515 //
516 // The strategy is to find the first and last dirty run in the desired
517 // write range (which will always be a set of pages), and write from the
518 // former to the later. The may result in writing some clean data, but
519 // will generally be more efficient than writing each runs seperately.
520 //
521
523
524 LBO DirtyLbo;
525 LBO CleanLbo;
526
527 VBO DirtyVbo;
528 VBO StartingDirtyVbo;
529
530 ULONG DirtyByteCount;
531 ULONG CleanByteCount;
532
534
535 BOOLEAN MoreDirtyRuns = TRUE;
536
537 IO_STATUS_BLOCK RaiseIosb;
538
539 DebugTrace(0, Dbg, "Type of write is Virtual Volume File\n", 0);
540
541 //
542 // If we can't wait we have to post this.
543 //
544
545 if (!Wait) {
546
547 DebugTrace( 0, Dbg, "Passing request to Fsp\n", 0 );
548
549 Status = FatFsdPostRequest(IrpContext, Irp);
550
551 return Status;
552 }
553
554 //
555 // If we weren't called by the Lazy Writer, then this write
556 // must be the result of a write-through or flush operation.
557 // Setting the IrpContext flag, will cause DevIoSup.c to
558 // write-through the data to the disk.
559 //
560
562
563 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );
564 }
565
566 //
567 // Assert an even number of entries in the Mcb, an odd number would
568 // mean that the Mcb is corrupt.
569 //
570
571 NT_ASSERT( (FsRtlNumberOfRunsInLargeMcb( &Vcb->DirtyFatMcb ) & 1) == 0);
572
573 //
574 // We need to skip over any clean sectors at the start of the write.
575 //
576 // Also check the two cases where there are no dirty fats in the
577 // desired write range, and complete them with success.
578 //
579 // 1) There is no Mcb entry corresponding to StartingVbo, meaning
580 // we are beyond the end of the Mcb, and thus dirty fats.
581 //
582 // 2) The run at StartingVbo is clean and continues beyond the
583 // desired write range.
584 //
585
586 if (!FatLookupMcbEntry( Vcb, &Vcb->DirtyFatMcb,
588 &DirtyLbo,
589 &DirtyByteCount,
590 NULL )
591
592 || ( (DirtyLbo == 0) && (DirtyByteCount >= ByteCount) ) ) {
593
594 DebugTrace(0, DEBUG_TRACE_DEBUG_HOOKS,
595 "No dirty fat sectors in the write range.\n", 0);
596
597 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
598 return STATUS_SUCCESS;
599 }
600
601 DirtyVbo = (VBO)DirtyLbo;
602
603 //
604 // If the last run was a hole (clean), up DirtyVbo to the next
605 // run, which must be dirty.
606 //
607
608 if (DirtyVbo == 0) {
609
610 DirtyVbo = StartingVbo + DirtyByteCount;
611 }
612
613 //
614 // This is where the write will start.
615 //
616
617 StartingDirtyVbo = DirtyVbo;
618
619 //
620 //
621 // Now start enumerating the dirty fat sectors spanning the desired
622 // write range, this first one of which is now DirtyVbo.
623 //
624
625 while ( MoreDirtyRuns ) {
626
627 //
628 // Find the next dirty run, if it is not there, the Mcb ended
629 // in a hole, or there is some other corruption of the Mcb.
630 //
631
632 if (!FatLookupMcbEntry( Vcb, &Vcb->DirtyFatMcb,
633 DirtyVbo,
634 &DirtyLbo,
635 &DirtyByteCount,
636 NULL )) {
637
638#ifdef _MSC_VER
639#pragma prefast( suppress:28931, "needed for debug build" )
640#endif
641 DirtyVbo = (VBO)DirtyLbo;
642
643 DebugTrace(0, Dbg, "Last dirty fat Mcb entry was a hole: corrupt.\n", 0);
644
645#ifdef _MSC_VER
646#pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
647#endif
648 FatBugCheck( 0, 0, 0 );
649
650 } else {
651
652 DirtyVbo = (VBO)DirtyLbo;
653
654 //
655 // This has to correspond to a dirty run, and must start
656 // within the write range since we check it at entry to,
657 // and at the bottom of this loop.
658 //
659
660 NT_ASSERT((DirtyVbo != 0) && (DirtyVbo < StartingVbo + ByteCount));
661
662 //
663 // There are three ways we can know that this was the
664 // last dirty run we want to write.
665 //
666 // 1) The current dirty run extends beyond or to the
667 // desired write range.
668 //
669 // 2) On trying to find the following clean run, we
670 // discover that this is the last run in the Mcb.
671 //
672 // 3) The following clean run extend beyond the
673 // desired write range.
674 //
675 // In any of these cases we set MoreDirtyRuns = FALSE.
676 //
677
678 //
679 // If the run is larger than we are writing, we also
680 // must truncate the WriteLength. This is benign in
681 // the equals case.
682 //
683
684 if (DirtyVbo + DirtyByteCount >= StartingVbo + ByteCount) {
685
686 DirtyByteCount = StartingVbo + ByteCount - DirtyVbo;
687
688 MoreDirtyRuns = FALSE;
689
690 } else {
691
692 //
693 // Scan the clean hole after this dirty run. If this
694 // run was the last, prepare to exit the loop
695 //
696
697 if (!FatLookupMcbEntry( Vcb, &Vcb->DirtyFatMcb,
698 DirtyVbo + DirtyByteCount,
699 &CleanLbo,
700 &CleanByteCount,
701 NULL )) {
702
703 MoreDirtyRuns = FALSE;
704
705 } else {
706
707 //
708 // Assert that we actually found a clean run.
709 // and compute the start of the next dirty run.
710 //
711
712 NT_ASSERT (CleanLbo == 0);
713
714 //
715 // If the next dirty run starts beyond the desired
716 // write, we have found all the runs we need, so
717 // prepare to exit.
718 //
719
720 if (DirtyVbo + DirtyByteCount + CleanByteCount >=
722
723 MoreDirtyRuns = FALSE;
724
725 } else {
726
727 //
728 // Compute the start of the next dirty run.
729 //
730
731 DirtyVbo += DirtyByteCount + CleanByteCount;
732 }
733 }
734 }
735 }
736 } // while ( MoreDirtyRuns )
737
738 //
739 // At this point DirtyVbo and DirtyByteCount correctly reflect the
740 // final dirty run, constrained to the desired write range.
741 //
742 // Now compute the length we finally must write.
743 //
744
745 WriteLength = (DirtyVbo + DirtyByteCount) - StartingDirtyVbo;
746
747 //
748 // We must now assume that the write will complete with success,
749 // and initialize our expected status in RaiseIosb. It will be
750 // modified below if an error occurs.
751 //
752
753 RaiseIosb.Status = STATUS_SUCCESS;
754 RaiseIosb.Information = ByteCount;
755
756 //
757 // Loop through all the fats, setting up a multiple async to
758 // write them all. If there are more than FAT_MAX_PARALLEL_IOS
759 // then we do several muilple asyncs.
760 //
761
762 {
763 ULONG Fat;
764 ULONG BytesPerFat;
765 IO_RUN StackIoRuns[2];
766 PIO_RUN IoRuns;
767
768 BytesPerFat = FatBytesPerFat( &Vcb->Bpb );
769
770 if ((ULONG)Vcb->Bpb.Fats > 2) {
771
773 (ULONG)(Vcb->Bpb.Fats*sizeof(IO_RUN)),
774 TAG_IO_RUNS );
775
776 } else {
777
778 IoRuns = StackIoRuns;
779 }
780
781 for (Fat = 0; Fat < (ULONG)Vcb->Bpb.Fats; Fat++) {
782
783 IoRuns[Fat].Vbo = StartingDirtyVbo;
784 IoRuns[Fat].Lbo = Fat * BytesPerFat + StartingDirtyVbo;
785 IoRuns[Fat].Offset = StartingDirtyVbo - StartingVbo;
786 IoRuns[Fat].ByteCount = WriteLength;
787 }
788
789 //
790 // Keep track of meta-data disk ios.
791 //
792
793 Vcb->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors].Common.MetaDataDiskWrites += Vcb->Bpb.Fats;
794
795 _SEH2_TRY {
796
797 FatMultipleAsync( IrpContext,
798 Vcb,
799 Irp,
800 (ULONG)Vcb->Bpb.Fats,
801 IoRuns );
802
803 } _SEH2_FINALLY {
804
805 if (IoRuns != StackIoRuns) {
806
807 ExFreePool( IoRuns );
808 }
809 } _SEH2_END;
810
811#if (NTDDI_VERSION >= NTDDI_WIN8)
812
813 //
814 // Account for DASD Ios
815 //
816
818
819 PETHREAD ThreadIssuingIo = PsGetCurrentThread();
820
821 PsUpdateDiskCounters( PsGetThreadProcess( ThreadIssuingIo ),
822 0,
824 0,
825 1,
826 0 );
827 }
828
829#endif
830 //
831 // Wait for all the writes to finish
832 //
833
834 FatWaitSync( IrpContext );
835
836 //
837 // If we got an error, or verify required, remember it.
838 //
839
840 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
841
842 DebugTrace( 0,
843 Dbg,
844 "Error %X while writing volume file.\n",
845 Irp->IoStatus.Status );
846
847 RaiseIosb = Irp->IoStatus;
848 }
849 }
850
851 //
852 // If the writes were a success, set the sectors clean, else
853 // raise the error status and mark the volume as needing
854 // verification. This will automatically reset the volume
855 // structures.
856 //
857 // If not, then mark this volume as needing verification to
858 // automatically cause everything to get cleaned up.
859 //
860
861 Irp->IoStatus = RaiseIosb;
862
863 if ( NT_SUCCESS( Status = Irp->IoStatus.Status )) {
864
865 FatRemoveMcbEntry( Vcb, &Vcb->DirtyFatMcb,
866 StartingDirtyVbo,
867 WriteLength );
868
869 } else {
870
871 FatNormalizeAndRaiseStatus( IrpContext, Status );
872 }
873
874 DebugTrace(-1, Dbg, "CommonWrite -> %08lx\n", Status );
875
876 FatCompleteRequest( IrpContext, Irp, Status );
877 return Status;
878 }
879
880 //
881 // This case corresponds to a general opened volume (DASD), ie.
882 // open ("a:").
883 //
884
885 if (TypeOfOpen == UserVolumeOpen) {
886
887 LBO StartingLbo;
888 LBO VolumeSize;
889
890 //
891 // Precalculate the volume size since we're nearly always going
892 // to be wanting to use it.
893 //
894
895 VolumeSize = (LBO) Int32x32To64( Vcb->Bpb.BytesPerSector,
896 (Vcb->Bpb.Sectors != 0 ? Vcb->Bpb.Sectors :
897 Vcb->Bpb.LargeSectors));
898
899 StartingLbo = StartingByte.QuadPart;
900
901 DebugTrace(0, Dbg, "Type of write is User Volume.\n", 0);
902
903 //
904 // If this is a write on a disk-based volume that is not locked, we need to limit
905 // the sectors we allow to be written within the volume. Specifically, we only
906 // allow writes to the reserved area. Note that extended DASD can still be used
907 // to write past the end of the volume. We also allow kernel mode callers to force
908 // access via a flag in the IRP. A handle that issued a dismount can write anywhere
909 // as well.
910 //
911
912 if ((Vcb->TargetDeviceObject->DeviceType == FILE_DEVICE_DISK) &&
913 !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) &&
916
917 //
918 // First check for a write beyond the end of the volume.
919 //
920
921 if (!WriteToEof && (StartingLbo < VolumeSize)) {
922
923 //
924 // This write is within the volume. Make sure it is not beyond the reserved section.
925 //
926
927 if ((StartingLbo >= FatReservedBytes( &(Vcb->Bpb) )) ||
928 (ByteCount > (FatReservedBytes( &(Vcb->Bpb) ) - StartingLbo))) {
929
932 }
933 }
934 }
935
936 //
937 // Verify that the volume for this handle is still valid, permitting
938 // operations to proceed on dismounted volumes via the handle which
939 // performed the dismount or sent a format unit command.
940 //
941
943
944 FatQuickVerifyVcb( IrpContext, Vcb );
945 }
946
947 //
948 // If the caller previously sent a format unit command, then we will allow
949 // their read/write requests to ignore the verify flag on the device, since some
950 // devices send a media change event after format unit, but we don't want to
951 // process it yet since we're probably in the process of formatting the
952 // media.
953 //
954
956
957 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY );
958 }
959
961
962 BOOLEAN PreviousWait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
963
964 //
965 // Grab the entire volume so that even the normally unsafe action
966 // of writing to an unlocked volume won't open us to a race between
967 // the flush and purge of the FAT below.
968 //
969 // I really don't think this is particularly important to worry about,
970 // but a repro case for another bug happens to dance into this race
971 // condition pretty easily. Eh.
972 //
973
974 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
975 FatAcquireExclusiveVolume( IrpContext, Vcb );
976
977 _SEH2_TRY {
978
979 //
980 // If the volume isn't locked, flush and purge it.
981 //
982
983 if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
984
985 FatFlushFat( IrpContext, Vcb );
986 CcPurgeCacheSection( &Vcb->SectionObjectPointers,
987 NULL,
988 0,
989 FALSE );
990
991 FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
992 }
993
994 } _SEH2_FINALLY {
995
996 FatReleaseVolume( IrpContext, Vcb );
997 if (!PreviousWait) {
998 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
999 }
1000 } _SEH2_END;
1001
1004 }
1005
1007
1008 //
1009 // Make sure we don't try to write past end of volume,
1010 // reducing the requested byte count if necessary.
1011 //
1012
1013 if (WriteToEof || StartingLbo >= VolumeSize) {
1014 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
1015 return STATUS_SUCCESS;
1016 }
1017
1018 if (ByteCount > VolumeSize - StartingLbo) {
1019
1020 ByteCount = (ULONG) (VolumeSize - StartingLbo);
1021
1022 //
1023 // For async writes we had set the byte count in the FatIoContext
1024 // above, so fix that here.
1025 //
1026
1027 if (!Wait) {
1028
1029 IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
1030 ByteCount;
1031 }
1032 }
1033 } else {
1034
1035 //
1036 // This has a peculiar interpretation, but just adjust the starting
1037 // byte to the end of the visible volume.
1038 //
1039
1040 if (WriteToEof) {
1041
1042 StartingLbo = VolumeSize;
1043 }
1044 }
1045
1046 //
1047 // For DASD we have to probe and lock the user's buffer
1048 //
1049
1051
1052 //
1053 // Set the FO_MODIFIED flag here to trigger a verify when this
1054 // handle is closed. Note that we can err on the conservative
1055 // side with no problem, i.e. if we accidently do an extra
1056 // verify there is no problem.
1057 //
1058
1060
1061 //
1062 // Write the data and wait for the results
1063 //
1064
1065 FatSingleAsync( IrpContext,
1066 Vcb,
1067 StartingLbo,
1068 ByteCount,
1069 Irp );
1070
1071#if (NTDDI_VERSION >= NTDDI_WIN8)
1072
1073 //
1074 // Account for DASD Ios
1075 //
1076
1078
1079 PETHREAD ThreadIssuingIo = PsGetCurrentThread();
1080
1081 PsUpdateDiskCounters( PsGetThreadProcess( ThreadIssuingIo ),
1082 0,
1083 ByteCount,
1084 0,
1085 1,
1086 0 );
1087 }
1088
1089#endif
1090
1091 if (!Wait) {
1092
1093 //
1094 // We, nor anybody else, need the IrpContext any more.
1095 //
1096
1097 IrpContext->FatIoContext = NULL;
1098
1099 FatDeleteIrpContext( IrpContext );
1100
1101 DebugTrace(-1, Dbg, "FatNonCachedIo -> STATUS_PENDING\n", 0);
1102
1103 return STATUS_PENDING;
1104 }
1105
1106 FatWaitSync( IrpContext );
1107
1108 //
1109 // If the call didn't succeed, raise the error status
1110 //
1111 // Also mark this volume as needing verification to automatically
1112 // cause everything to get cleaned up.
1113 //
1114
1115 if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
1116
1117 FatNormalizeAndRaiseStatus( IrpContext, Status );
1118 }
1119
1120 //
1121 // Update the current file position. We assume that
1122 // open/create zeros out the CurrentByteOffset field.
1123 //
1124
1125 if (SynchronousIo && !PagingIo) {
1126 FileObject->CurrentByteOffset.QuadPart =
1127 StartingLbo + Irp->IoStatus.Information;
1128 }
1129
1130 DebugTrace(-1, Dbg, "FatCommonWrite -> %08lx\n", Status );
1131
1132 FatCompleteRequest( IrpContext, Irp, Status );
1133 return Status;
1134 }
1135
1136 //
1137 // At this point we know there is an Fcb/Dcb.
1138 //
1139
1140 NT_ASSERT( FcbOrDcb != NULL );
1141
1142 //
1143 // Use a try-finally to free Fcb/Dcb and buffers on the way out.
1144 //
1145
1146 _SEH2_TRY {
1147
1148 //
1149 // This case corresponds to a normal user write file.
1150 //
1151
1152 if ( TypeOfOpen == UserFileOpen
1153 ) {
1154
1155 ULONG ValidDataLength;
1156 ULONG ValidDataToDisk;
1157 ULONG ValidDataToCheck;
1158
1159 DebugTrace(0, Dbg, "Type of write is user file open\n", 0);
1160
1161 //
1162 // If this is a noncached transfer and is not a paging I/O, and
1163 // the file has been opened cached, then we will do a flush here
1164 // to avoid stale data problems. Note that we must flush before
1165 // acquiring the Fcb shared since the write may try to acquire
1166 // it exclusive.
1167 //
1168 // The Purge following the flush will guarentee cache coherency.
1169 //
1170
1171 if (NonCachedIo && !PagingIo &&
1172 (FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
1173
1175
1176 //
1177 // We need the Fcb exclsuive to do the CcPurgeCache
1178 //
1179
1180 if (!FatAcquireExclusiveFcb( IrpContext, FcbOrDcb )) {
1181
1182 DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %p shared without waiting\n", FcbOrDcb );
1183
1184 try_return( PostIrp = TRUE );
1185 }
1186
1187 FcbOrDcbAcquired = TRUE;
1188 FcbAcquiredExclusive = TRUE;
1189
1190 //
1191 // Preacquire pagingio for the flush.
1192 //
1193
1194 ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
1195
1196#if (NTDDI_VERSION >= NTDDI_WIN7)
1197
1198 //
1199 // Remember that we are holding the paging I/O resource.
1200 //
1201
1202 PagingIoResourceAcquired = TRUE;
1203
1204 //
1205 // We hold so that we will prevent a pagefault from occuring and seeing
1206 // soon-to-be stale data from the disk. We used to believe this was
1207 // something to be left to the app to synchronize; we now realize that
1208 // noncached IO on a fileserver is doomed without the filesystem forcing
1209 // the coherency issue. By only penalizing noncached coherency when
1210 // needed, this is about the best we can do.
1211 //
1212
1213 //
1214 // Now perform the coherency flush and purge operation. This version of the call
1215 // will try to invalidate mapped pages to prevent data corruption.
1216 //
1217
1218 CcCoherencyFlushAndPurgeCache( FileObject->SectionObjectPointer,
1219 WriteToEof ? &FcbOrDcb->Header.FileSize : &StartingByte,
1220 ByteCount,
1221 &IoStatus,
1222 0 );
1223
1224 SuccessfulPurge = NT_SUCCESS( IoStatus.Status );
1225
1226#else
1227
1228 CcFlushCache( FileObject->SectionObjectPointer,
1229 WriteToEof ? &FcbOrDcb->Header.FileSize : &StartingByte,
1230 ByteCount,
1231 &IoStatus );
1232
1233 if (!NT_SUCCESS( IoStatus.Status )) {
1234
1235 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
1236 try_return( IoStatus.Status );
1237 }
1238
1239 //
1240 // Remember that we are holding the paging I/O resource.
1241 //
1242
1243 PagingIoResourceAcquired = TRUE;
1244
1245 //
1246 // We hold so that we will prevent a pagefault from occuring and seeing
1247 // soon-to-be stale data from the disk. We used to believe this was
1248 // something to be left to the app to synchronize; we now realize that
1249 // noncached IO on a fileserver is doomed without the filesystem forcing
1250 // the coherency issue. By only penalizing noncached coherency when
1251 // needed, this is about the best we can do.
1252 //
1253
1254 SuccessfulPurge = CcPurgeCacheSection( FileObject->SectionObjectPointer,
1255 WriteToEof ? &FcbOrDcb->Header.FileSize : &StartingByte,
1256 ByteCount,
1257 FALSE );
1258
1259#endif
1260
1261 if (!SuccessfulPurge && (FcbOrDcb->PurgeFailureModeEnableCount > 0)) {
1262
1263 //
1264 // Purge failure mode only applies to user files.
1265 //
1266
1268
1269 //
1270 // Do not swallow the purge failure if in purge failure
1271 // mode. Someone outside the file system intends to handle
1272 // the error and prevent any application compatibilty
1273 // issue.
1274 //
1275 // NOTE: If the file system were not preventing a pagefault
1276 // from processing while this write is in flight, which it does
1277 // by holding the paging resource across the write, it would
1278 // need to fail the operation even if a purge succeeded. If
1279 // not a memory mapped read could bring in a stale page before
1280 // the write makes it to disk.
1281 //
1282
1284 }
1285
1286 //
1287 // Indicate we're OK with the fcb being demoted to shared access
1288 // if that turns out to be possible later on after VDL extension
1289 // is checked for.
1290 //
1291 // PagingIo must be held all the way through.
1292 //
1293
1294 FcbCanDemoteToShared = TRUE;
1295 }
1296
1297 //
1298 // We assert that Paging Io writes will never WriteToEof.
1299 //
1300
1301 NT_ASSERT( WriteToEof ? !PagingIo : TRUE );
1302
1303 //
1304 // First let's acquire the Fcb shared. Shared is enough if we
1305 // are not writing beyond EOF.
1306 //
1307
1308 if ( PagingIo ) {
1309
1310 (VOID)ExAcquireResourceSharedLite( FcbOrDcb->Header.PagingIoResource, TRUE );
1311 PagingIoResourceAcquired = TRUE;
1312
1313 if (!Wait) {
1314
1315 IrpContext->FatIoContext->Wait.Async.Resource =
1316 FcbOrDcb->Header.PagingIoResource;
1317 }
1318
1319 //
1320 // Check to see if we colided with a MoveFile call, and if
1321 // so block until it completes.
1322 //
1323
1324 if (FcbOrDcb->MoveFileEvent) {
1325
1327 Executive,
1328 KernelMode,
1329 FALSE,
1330 NULL );
1331 }
1332
1333 } else {
1334
1335 //
1336 // We may already have the Fcb due to noncached coherency
1337 // work done just above; however, we may still have to extend
1338 // valid data length. We can't demote this to shared, matching
1339 // what occured before, until we figure that out a bit later.
1340 //
1341 // We kept ahold of it since our lockorder is main->paging,
1342 // and paging must now held across the noncached write from
1343 // the purge on.
1344 //
1345
1346 //
1347 // If this is async I/O, we will wait if there is an exclusive
1348 // waiter.
1349 //
1350
1351 if (!Wait && NonCachedIo) {
1352
1353 if (!FcbOrDcbAcquired &&
1354 !FatAcquireSharedFcbWaitForEx( IrpContext, FcbOrDcb )) {
1355
1356 DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %p shared without waiting\n", FcbOrDcb );
1357 try_return( PostIrp = TRUE );
1358 }
1359
1360 //
1361 // Note we will have to release this resource elsewhere. If we came
1362 // out of the noncached coherency path, we will also have to drop
1363 // the paging io resource.
1364 //
1365
1366 IrpContext->FatIoContext->Wait.Async.Resource = FcbOrDcb->Header.Resource;
1367
1368 if (FcbCanDemoteToShared) {
1369
1370 IrpContext->FatIoContext->Wait.Async.Resource2 = FcbOrDcb->Header.PagingIoResource;
1371 }
1372 } else {
1373
1374 if (!FcbOrDcbAcquired &&
1375 !FatAcquireSharedFcb( IrpContext, FcbOrDcb )) {
1376
1377 DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %p shared without waiting\n", FcbOrDcb );
1378 try_return( PostIrp = TRUE );
1379 }
1380 }
1381
1382 FcbOrDcbAcquired = TRUE;
1383 }
1384
1385 //
1386 // Get a first tentative file size and valid data length.
1387 // We must get ValidDataLength first since it is always
1388 // increased second (in case we are unprotected) and
1389 // we don't want to capture ValidDataLength > FileSize.
1390 //
1391
1392 ValidDataToDisk = FcbOrDcb->ValidDataToDisk;
1393 ValidDataLength = FcbOrDcb->Header.ValidDataLength.LowPart;
1394 FileSize = FcbOrDcb->Header.FileSize.LowPart;
1395
1396 NT_ASSERT( ValidDataLength <= FileSize );
1397
1398 //
1399 // If are paging io, then we do not want
1400 // to write beyond end of file. If the base is beyond Eof, we will just
1401 // Noop the call. If the transfer starts before Eof, but extends
1402 // beyond, we will truncate the transfer to the last sector
1403 // boundary.
1404 //
1405
1406 //
1407 // Just in case this is paging io, limit write to file size.
1408 // Otherwise, in case of write through, since Mm rounds up
1409 // to a page, we might try to acquire the resource exclusive
1410 // when our top level guy only acquired it shared. Thus, =><=.
1411 //
1412
1413 if ( PagingIo ) {
1414
1415 if (StartingVbo >= FileSize) {
1416
1417 DebugTrace( 0, Dbg, "PagingIo started beyond EOF.\n", 0 );
1418
1419 Irp->IoStatus.Information = 0;
1420
1422 }
1423
1424 if (ByteCount > FileSize - StartingVbo) {
1425
1426 DebugTrace( 0, Dbg, "PagingIo extending beyond EOF.\n", 0 );
1427
1429 }
1430 }
1431
1432 //
1433 // Determine if we were called by the lazywriter.
1434 // (see resrcsup.c)
1435 //
1436
1437 if (FcbOrDcb->Specific.Fcb.LazyWriteThread == PsGetCurrentThread()) {
1438
1439 CalledByLazyWriter = TRUE;
1440
1442
1443 //
1444 // Fail if the start of this request is beyond valid data length.
1445 // Don't worry if this is an unsafe test. MM and CC won't
1446 // throw this page away if it is really dirty.
1447 //
1448
1449 if ((StartingVbo + ByteCount > ValidDataLength) &&
1450 (StartingVbo < FileSize)) {
1451
1452 //
1453 // It's OK if byte range is within the page containing valid data length,
1454 // since we will use ValidDataToDisk as the start point.
1455 //
1456
1457 if (StartingVbo + ByteCount > ((ValidDataLength + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
1458
1459 //
1460 // Don't flush this now.
1461 //
1462
1464 }
1465 }
1466 }
1467 }
1468
1469 //
1470 // This code detects if we are a recursive synchronous page write
1471 // on a write through file object.
1472 //
1473
1474 if (FlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) &&
1475 FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL)) {
1476
1477 PIRP TopIrp;
1478
1479 TopIrp = IoGetTopLevelIrp();
1480
1481 //
1482 // This clause determines if the top level request was
1483 // in the FastIo path. Gack. Since we don't have a
1484 // real sharing protocol for the top level IRP field ...
1485 // yet ... if someone put things other than a pure IRP in
1486 // there we best be careful.
1487 //
1488
1490 NodeType(TopIrp) == IO_TYPE_IRP) {
1491
1492 PIO_STACK_LOCATION IrpStack;
1493
1494 IrpStack = IoGetCurrentIrpStackLocation(TopIrp);
1495
1496 //
1497 // Finally this routine detects if the Top irp was a
1498 // cached write to this file and thus we are the writethrough.
1499 //
1500
1501 if ((IrpStack->MajorFunction == IRP_MJ_WRITE) &&
1502 (IrpStack->FileObject->FsContext == FileObject->FsContext) &&
1503 !FlagOn(TopIrp->Flags,IRP_NOCACHE)) {
1504
1505 RecursiveWriteThrough = TRUE;
1506 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );
1507 }
1508 }
1509 }
1510
1511 //
1512 // Here is the deal with ValidDataLength and FileSize:
1513 //
1514 // Rule 1: PagingIo is never allowed to extend file size.
1515 //
1516 // Rule 2: Only the top level requestor may extend Valid
1517 // Data Length. This may be paging IO, as when a
1518 // a user maps a file, but will never be as a result
1519 // of cache lazy writer writes since they are not the
1520 // top level request.
1521 //
1522 // Rule 3: If, using Rules 1 and 2, we decide we must extend
1523 // file size or valid data, we take the Fcb exclusive.
1524 //
1525
1526 //
1527 // Now see if we are writing beyond valid data length, and thus
1528 // maybe beyond the file size. If so, then we must
1529 // release the Fcb and reacquire it exclusive. Note that it is
1530 // important that when not writing beyond EOF that we check it
1531 // while acquired shared and keep the FCB acquired, in case some
1532 // turkey truncates the file.
1533 //
1534
1535 //
1536 // Note that the lazy writer must not be allowed to try and
1537 // acquire the resource exclusive. This is not a problem since
1538 // the lazy writer is paging IO and thus not allowed to extend
1539 // file size, and is never the top level guy, thus not able to
1540 // extend valid data length.
1541 //
1542
1543 if ( !CalledByLazyWriter &&
1544
1545 !RecursiveWriteThrough &&
1546
1547 (WriteToEof ||
1548 StartingVbo + ByteCount > ValidDataLength)) {
1549
1550 //
1551 // If this was an asynchronous write, we are going to make
1552 // the request synchronous at this point, but only kinda.
1553 // At the last moment, before sending the write off to the
1554 // driver, we may shift back to async.
1555 //
1556 // The modified page writer already has the resources
1557 // he requires, so this will complete in small finite
1558 // time.
1559 //
1560
1561 if (!Wait) {
1562
1563 Wait = TRUE;
1564 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
1565
1566 if (NonCachedIo) {
1567
1569
1570 SwitchBackToAsync = TRUE;
1571 }
1572 }
1573
1574 //
1575 // We need Exclusive access to the Fcb/Dcb since we will
1576 // probably have to extend valid data and/or file.
1577 //
1578
1579 //
1580 // Y'know, the PagingIo case is a mapped page writer, and
1581 // MmFlushSection or the mapped page writer itself already
1582 // snatched up the main exclusive for us via the AcquireForCcFlush
1583 // or AcquireForModWrite logic (the default logic parallels FAT's
1584 // requirements since this order/model came first). Should ASSERT
1585 // this since it'll just go 1->2, and a few more unnecesary DPC
1586 // transitions.
1587 //
1588 // The preacquire is done to avoid inversion over the collided flush
1589 // meta-resource in Mm. The one time this is not true is at final
1590 // system shutdown time, when Mm goes off and flushes all the dirty
1591 // pages. Since the callback is defined as Wait == FALSE he can't
1592 // guarantee acquisition (though with clean process shutdown being
1593 // enforced, it really should be now). Permit this to float.
1594 //
1595 // Note that since we're going to fall back on the acquisition aleady
1596 // done for us, don't confuse things by thinking we did the work
1597 // for it.
1598 //
1599
1600 if ( PagingIo ) {
1601
1602 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
1603 PagingIoResourceAcquired = FALSE;
1604
1605 } else {
1606
1607 //
1608 // The Fcb may already be acquired exclusive due to coherency
1609 // work performed earlier. If so, obviously no work to do.
1610 //
1611
1612 if (!FcbAcquiredExclusive) {
1613
1614 FatReleaseFcb( IrpContext, FcbOrDcb );
1615 FcbOrDcbAcquired = FALSE;
1616
1617 if (!FatAcquireExclusiveFcb( IrpContext, FcbOrDcb )) {
1618
1619 DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %p shared without waiting\n", FcbOrDcb );
1620
1621 try_return( PostIrp = TRUE );
1622 }
1623
1624 FcbOrDcbAcquired = TRUE;
1625
1626#ifdef _MSC_VER
1627#pragma prefast( suppress:28931, "convenient for debugging" )
1628#endif
1629 FcbAcquiredExclusive = TRUE;
1630 }
1631 }
1632
1633 //
1634 // Now that we have the Fcb exclusive, see if this write
1635 // qualifies for being made async again. The key point
1636 // here is that we are going to update ValidDataLength in
1637 // the Fcb before returning. We must make sure this will
1638 // not cause a problem. One thing we must do is keep out
1639 // the FastIo path.
1640 //
1641
1642 if (SwitchBackToAsync) {
1643
1645 (StartingVbo + ByteCount > FcbOrDcb->Header.ValidDataLength.LowPart) ||
1646 FatNoAsync) {
1647
1648 RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );
1649
1650 KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
1652 FALSE );
1653
1654 SwitchBackToAsync = FALSE;
1655
1656 } else {
1657
1659
1661 FsRtlAllocatePoolWithTag( NonPagedPoolNx,
1662 sizeof(KEVENT),
1663 TAG_EVENT );
1664
1667 FALSE );
1668 }
1669
1670 //
1671 // If we are transitioning from 0 to 1, reset the event.
1672 //
1673
1675 1,
1676 &FatData.GeneralSpinLock ) == 0) {
1677
1679 }
1680
1681 UnwindOutstandingAsync = TRUE;
1682
1683 IrpContext->FatIoContext->Wait.Async.NonPagedFcb = FcbOrDcb->NonPaged;
1684 }
1685 }
1686
1687 //
1688 // Now that we have the Fcb exclusive, get a new batch of
1689 // filesize and ValidDataLength.
1690 //
1691
1692 ValidDataToDisk = FcbOrDcb->ValidDataToDisk;
1693 ValidDataLength = FcbOrDcb->Header.ValidDataLength.LowPart;
1694 FileSize = FcbOrDcb->Header.FileSize.LowPart;
1695
1696 //
1697 // If this is PagingIo check again if any pruning is
1698 // required. It is important to start from basic
1699 // princples in case the file was *grown* ...
1700 //
1701
1702 if ( PagingIo ) {
1703
1704 if (StartingVbo >= FileSize) {
1705 Irp->IoStatus.Information = 0;
1707 }
1708
1709 ByteCount = IrpSp->Parameters.Write.Length;
1710
1711 if (ByteCount > FileSize - StartingVbo) {
1713 }
1714 }
1715 }
1716
1717 //
1718 // Remember the final requested byte count
1719 //
1720
1721 if (NonCachedIo && !Wait) {
1722
1723 IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
1724 ByteCount;
1725 }
1726
1727 //
1728 // Remember the initial file size and valid data length,
1729 // just in case .....
1730 //
1731
1732 InitialFileSize = FileSize;
1733
1734 InitialValidDataLength = ValidDataLength;
1735
1736 //
1737 // Make sure the FcbOrDcb is still good
1738 //
1739
1740 FatVerifyFcb( IrpContext, FcbOrDcb );
1741
1742 //
1743 // Check for writing to end of File. If we are, then we have to
1744 // recalculate a number of fields.
1745 //
1746
1747 if ( WriteToEof ) {
1748
1750 StartingByte = FcbOrDcb->Header.FileSize;
1751
1752 //
1753 // Since we couldn't know this information until now, perform the
1754 // necessary bounds checking that we ommited at the top because
1755 // this is a WriteToEof operation.
1756 //
1757
1758
1759 if (!FatIsIoRangeValid( Vcb, StartingByte, ByteCount)) {
1760
1761 Irp->IoStatus.Information = 0;
1763 }
1764
1765
1766 }
1767
1768 //
1769 // If this is a non paging write to a data stream object we have to
1770 // check for access according to the current state op/filelocks.
1771 //
1772 // Note that after this point, operations will be performed on the file.
1773 // No modifying activity can occur prior to this point in the write
1774 // path.
1775 //
1776
1777 if (!PagingIo && TypeOfOpen == UserFileOpen) {
1778
1780 Irp,
1781 IrpContext,
1783 FatPrePostIrp );
1784
1785 if (Status != STATUS_SUCCESS) {
1786
1787 OplockPostIrp = TRUE;
1788 PostIrp = TRUE;
1790 }
1791
1792 //
1793 // This oplock call can affect whether fast IO is possible.
1794 // We may have broken an oplock to no oplock held. If the
1795 // current state of the file is FastIoIsNotPossible then
1796 // recheck the fast IO state.
1797 //
1798
1799 if (FcbOrDcb->Header.IsFastIoPossible == FastIoIsNotPossible) {
1800
1801 FcbOrDcb->Header.IsFastIoPossible = FatIsFastIoPossible( FcbOrDcb );
1802 }
1803
1804 //
1805 // And finally check the regular file locks.
1806 //
1807
1809
1811 }
1812 }
1813
1814 //
1815 // Determine if we will deal with extending the file. Note that
1816 // this implies extending valid data, and so we already have all
1817 // of the required synchronization done.
1818 //
1819
1820 if (!PagingIo && (StartingVbo + ByteCount > FileSize)) {
1821
1822 ExtendingFile = TRUE;
1823 }
1824
1825 if ( ExtendingFile ) {
1826
1827
1828 //
1829 // EXTENDING THE FILE
1830 //
1831
1832 //
1833 // For an extending write on hotplug media, we are going to defer the metadata
1834 // updates via Cc's lazy writer. They will also be flushed when the handle is closed.
1835 //
1836
1837 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH)) {
1838
1840 }
1841
1842 //
1843 // Update our local copy of FileSize
1844 //
1845
1847
1848
1849 if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
1850
1851 FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
1852 }
1853
1854 //
1855 // If the write goes beyond the allocation size, add some
1856 // file allocation.
1857 //
1858
1859
1860 if ( (FileSize) > FcbOrDcb->Header.AllocationSize.LowPart ) {
1861
1862
1863 BOOLEAN AllocateMinimumSize = TRUE;
1864
1865 //
1866 // Only do allocation chuncking on writes if this is
1867 // not the first allocation added to the file.
1868 //
1869
1870 if (FcbOrDcb->Header.AllocationSize.LowPart != 0 ) {
1871
1872 ULONGLONG ApproximateClusterCount;
1873 ULONGLONG TargetAllocation;
1874 ULONGLONG AddedAllocation;
1875 ULONGLONG Multiplier;
1876 ULONG BytesPerCluster;
1877 ULONG ClusterAlignedFileSize;
1878
1879 //
1880 // We are going to try and allocate a bigger chunk than
1881 // we actually need in order to maximize FastIo usage.
1882 //
1883 // The multiplier is computed as follows:
1884 //
1885 //
1886 // (FreeDiskSpace )
1887 // Mult = ( (-------------------------) / 32 ) + 1
1888 // (FileSize - AllocationSize)
1889 //
1890 // and max out at 32.
1891 //
1892 // With this formula we start winding down chunking
1893 // as we get near the disk space wall.
1894 //
1895 // For instance on an empty 1 MEG floppy doing an 8K
1896 // write, the multiplier is 6, or 48K to allocate.
1897 // When this disk is half full, the multipler is 3,
1898 // and when it is 3/4 full, the mupltiplier is only 1.
1899 //
1900 // On a larger disk, the multiplier for a 8K read will
1901 // reach its maximum of 32 when there is at least ~8 Megs
1902 // available.
1903 //
1904
1905 //
1906 // Small write performance note, use cluster aligned
1907 // file size in above equation.
1908 //
1909
1910 //
1911 // We need to carefully consider what happens when we approach
1912 // a 2^32 byte filesize. Overflows will cause problems.
1913 //
1914
1915 BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
1916
1917 //
1918 // This can overflow if the target filesize is in the last cluster.
1919 // In this case, we can obviously skip over all of this fancy
1920 // logic and just max out the file right now.
1921 //
1922
1923
1924 ClusterAlignedFileSize = ((FileSize) + (BytesPerCluster - 1)) &
1925 ~(BytesPerCluster - 1);
1926
1927
1928 if (ClusterAlignedFileSize != 0) {
1929
1930 //
1931 // This actually has a chance but the possibility of overflowing
1932 // the numerator is pretty unlikely, made more unlikely by moving
1933 // the divide by 32 up to scale the BytesPerCluster. However, even if it does the
1934 // effect is completely benign.
1935 //
1936 // FAT32 with a 64k cluster and over 2^21 clusters would do it (and
1937 // so forth - 2^(16 - 5 + 21) == 2^32). Since this implies a partition
1938 // of 32gb and a number of clusters (and cluster size) we plan to
1939 // disallow in format for FAT32, the odds of this happening are pretty
1940 // low anyway.
1941 Multiplier = ((Vcb->AllocationSupport.NumberOfFreeClusters *
1942 (BytesPerCluster >> 5)) /
1943 (ClusterAlignedFileSize -
1944 FcbOrDcb->Header.AllocationSize.LowPart)) + 1;
1945
1946 if (Multiplier > 32) { Multiplier = 32; }
1947
1948 // These computations will never overflow a ULONGLONG because a file is capped at 4GB, and
1949 // a single write can be a max of 4GB.
1950 AddedAllocation = Multiplier * (ClusterAlignedFileSize - FcbOrDcb->Header.AllocationSize.LowPart);
1951
1952 TargetAllocation = FcbOrDcb->Header.AllocationSize.LowPart + AddedAllocation;
1953
1954 //
1955 // We know that TargetAllocation is in whole clusters. Now
1956 // we check if it exceeded the maximum valid FAT file size.
1957 // If it did, we fall back to allocating up to the maximum legal size.
1958 //
1959
1960 if (TargetAllocation > ~BytesPerCluster + 1) {
1961
1962 TargetAllocation = ~BytesPerCluster + 1;
1963 AddedAllocation = TargetAllocation - FcbOrDcb->Header.AllocationSize.LowPart;
1964 }
1965
1966 //
1967 // Now do an unsafe check here to see if we should even
1968 // try to allocate this much. If not, just allocate
1969 // the minimum size we need, if so so try it, but if it
1970 // fails, just allocate the minimum size we need.
1971 //
1972
1973 ApproximateClusterCount = (AddedAllocation / BytesPerCluster);
1974
1975 if (ApproximateClusterCount <= Vcb->AllocationSupport.NumberOfFreeClusters) {
1976
1977 _SEH2_TRY {
1978
1979 FatAddFileAllocation( IrpContext,
1980 FcbOrDcb,
1981 FileObject,
1982 (ULONG)TargetAllocation );
1983
1984 AllocateMinimumSize = FALSE;
1986
1989
1990 FatResetExceptionState( IrpContext );
1991 } _SEH2_END;
1992 }
1993 }
1994 }
1995
1996 if ( AllocateMinimumSize ) {
1997
1998
1999 FatAddFileAllocation( IrpContext,
2000 FcbOrDcb,
2001 FileObject,
2002 FileSize );
2003
2004
2005 }
2006
2007 //
2008 // Assert that the allocation worked
2009 //
2010
2011
2012 NT_ASSERT( FcbOrDcb->Header.AllocationSize.LowPart >= FileSize );
2013
2014
2015 }
2016
2017 //
2018 // Set the new file size in the Fcb
2019 //
2020
2021
2022 NT_ASSERT( FileSize <= FcbOrDcb->Header.AllocationSize.LowPart );
2023
2024
2025 FcbOrDcb->Header.FileSize.LowPart = FileSize;
2026
2027 //
2028 // Extend the cache map, letting mm knows the new file size.
2029 // We only have to do this if the file is cached.
2030 //
2031
2034 }
2035 }
2036
2037 //
2038 // Determine if we will deal with extending valid data.
2039 //
2040
2041 if ( !CalledByLazyWriter &&
2042 !RecursiveWriteThrough &&
2043 (StartingVbo + ByteCount > ValidDataLength) ) {
2044
2045 ExtendingValidData = TRUE;
2046
2047 } else {
2048
2049 //
2050 // If not extending valid data, and we otherwise believe we
2051 // could demote from exclusive to shared, do so. This will
2052 // occur when we synchronize tight for noncached coherency
2053 // but must defer the demotion until after we decide about
2054 // valid data length, which requires it exclusive. Since we
2055 // can't drop/re-pick the resources without letting a pagefault
2056 // squirt through, the resource decision was kept up in the air
2057 // until now.
2058 //
2059 // Note that we've still got PagingIo exclusive in these cases.
2060 //
2061
2062 if (FcbCanDemoteToShared) {
2063
2064 NT_ASSERT( FcbAcquiredExclusive && ExIsResourceAcquiredExclusiveLite( FcbOrDcb->Header.Resource ));
2066 FcbAcquiredExclusive = FALSE;
2067 }
2068 }
2069
2070 if (ValidDataToDisk > ValidDataLength) {
2071
2072 ValidDataToCheck = ValidDataToDisk;
2073
2074 } else {
2075
2076 ValidDataToCheck = ValidDataLength;
2077 }
2078
2079
2080
2081 //
2082 // HANDLE THE NON-CACHED CASE
2083 //
2084
2085 if ( NonCachedIo ) {
2086
2087 //
2088 // Declare some local variables for enumeration through the
2089 // runs of the file, and an array to store parameters for
2090 // parallel I/Os
2091 //
2092
2094
2095 ULONG BytesToWrite;
2096
2097 DebugTrace(0, Dbg, "Non cached write.\n", 0);
2098
2099 //
2100 // Round up to sector boundry. The end of the write interval
2101 // must, however, be beyond EOF.
2102 //
2103
2104 SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
2105
2106 BytesToWrite = (ByteCount + (SectorSize - 1))
2107 & ~(SectorSize - 1);
2108
2109 //
2110 // All requests should be well formed and
2111 // make sure we don't wipe out any data
2112 //
2113
2114 if (((StartingVbo & (SectorSize - 1)) != 0) ||
2115
2116 ((BytesToWrite != ByteCount) &&
2117 (StartingVbo + ByteCount < ValidDataLength))) {
2118
2119 NT_ASSERT( FALSE );
2120
2121 DebugTrace( 0, Dbg, "FatCommonWrite -> STATUS_NOT_IMPLEMENTED\n", 0);
2123 }
2124
2125 //
2126 // If this noncached transfer is at least one sector beyond
2127 // the current ValidDataLength in the Fcb, then we have to
2128 // zero the sectors in between. This can happen if the user
2129 // has opened the file noncached, or if the user has mapped
2130 // the file and modified a page beyond ValidDataLength. It
2131 // *cannot* happen if the user opened the file cached, because
2132 // ValidDataLength in the Fcb is updated when he does the cached
2133 // write (we also zero data in the cache at that time), and
2134 // therefore, we will bypass this test when the data
2135 // is ultimately written through (by the Lazy Writer).
2136 //
2137 // For the paging file we don't care about security (ie.
2138 // stale data), do don't bother zeroing.
2139 //
2140 // We can actually get writes wholly beyond valid data length
2141 // from the LazyWriter because of paging Io decoupling.
2142 //
2143
2144 if (!CalledByLazyWriter &&
2145 !RecursiveWriteThrough &&
2146 (StartingVbo > ValidDataToCheck)) {
2147
2148 FatZeroData( IrpContext,
2149 Vcb,
2150 FileObject,
2151 ValidDataToCheck,
2152 StartingVbo - ValidDataToCheck );
2153 }
2154
2155 //
2156 // Make sure we write FileSize to the dirent if we
2157 // are extending it and we are successful. (This may or
2158 // may not occur Write Through, but that is fine.)
2159 //
2160
2161 WriteFileSizeToDirent = TRUE;
2162
2163 //
2164 // Perform the actual IO
2165 //
2166
2167 if (SwitchBackToAsync) {
2168
2169 Wait = FALSE;
2170 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
2171 }
2172
2173#ifdef SYSCACHE_COMPILE
2174
2175#define MY_SIZE 0x1000000
2176#define LONGMAP_COUNTER
2177
2178#ifdef BITMAP
2179 //
2180 // Maintain a bitmap of IO started on this file.
2181 //
2182
2183 {
2184 PULONG WriteMask = FcbOrDcb->WriteMask;
2185
2186 if (NULL == WriteMask) {
2187
2188 WriteMask = FsRtlAllocatePoolWithTag( NonPagedPoolNx,
2189 (MY_SIZE/PAGE_SIZE) / 8,
2190 'wtaF' );
2191
2192 FcbOrDcb->WriteMask = WriteMask;
2193 RtlZeroMemory(WriteMask, (MY_SIZE/PAGE_SIZE) / 8);
2194 }
2195
2196 if (StartingVbo < MY_SIZE) {
2197
2198 ULONG Off = StartingVbo;
2199 ULONG Len = BytesToWrite;
2200
2201 if (Off + Len > MY_SIZE) {
2202 Len = MY_SIZE - Off;
2203 }
2204
2205 while (Len != 0) {
2206 WriteMask[(Off/PAGE_SIZE) / 32] |=
2207 1 << (Off/PAGE_SIZE) % 32;
2208
2209 Off += PAGE_SIZE;
2210 if (Len <= PAGE_SIZE) {
2211 break;
2212 }
2213 Len -= PAGE_SIZE;
2214 }
2215 }
2216 }
2217#endif
2218
2219#ifdef LONGMAP_COUNTER
2220 //
2221 // Maintain a longmap of IO started on this file, each ulong containing
2222 // the value of an ascending counter per write (gives us order information).
2223 //
2224 // Unlike the old bitmask stuff, this is mostly well synchronized.
2225 //
2226
2227 {
2228 PULONG WriteMask = (PULONG)FcbOrDcb->WriteMask;
2229
2230 if (NULL == WriteMask) {
2231
2232 WriteMask = FsRtlAllocatePoolWithTag( NonPagedPoolNx,
2233 (MY_SIZE/PAGE_SIZE) * sizeof(ULONG),
2234 'wtaF' );
2235
2236 FcbOrDcb->WriteMask = WriteMask;
2237 RtlZeroMemory(WriteMask, (MY_SIZE/PAGE_SIZE) * sizeof(ULONG));
2238 }
2239
2240 if (StartingVbo < MY_SIZE) {
2241
2242 ULONG Off = StartingVbo;
2243 ULONG Len = BytesToWrite;
2244 ULONG Tick = InterlockedIncrement( &FcbOrDcb->WriteMaskData );
2245
2246 if (Off + Len > MY_SIZE) {
2247 Len = MY_SIZE - Off;
2248 }
2249
2250 while (Len != 0) {
2251 InterlockedExchange( WriteMask + Off/PAGE_SIZE, Tick );
2252
2253 Off += PAGE_SIZE;
2254 if (Len <= PAGE_SIZE) {
2255 break;
2256 }
2257 Len -= PAGE_SIZE;
2258 }
2259 }
2260 }
2261#endif
2262
2263#endif
2264
2265
2266 if (FatNonCachedIo( IrpContext,
2267 Irp,
2268 FcbOrDcb,
2270 BytesToWrite,
2271 BytesToWrite,
2272 0) == STATUS_PENDING) {
2273
2274
2275 UnwindOutstandingAsync = FALSE;
2276
2277#ifdef _MSC_VER
2278#pragma prefast( suppress:28931, "convenient for debugging" )
2279#endif
2280 Wait = TRUE;
2281 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
2282
2283 IrpContext->FatIoContext = NULL;
2284 Irp = NULL;
2285
2286 //
2287 // As a matter of fact, if we hit this we are in deep trouble
2288 // if VDL is being extended. We are no longer attached to the
2289 // IRP, and have thus lost synchronization. Note that we should
2290 // not hit this case anymore since we will not re-async vdl extension.
2291 //
2292
2293 NT_ASSERT( !ExtendingValidData );
2294
2296 }
2297
2298 //
2299 // If the call didn't succeed, raise the error status
2300 //
2301
2302 if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
2303
2304 FatNormalizeAndRaiseStatus( IrpContext, Status );
2305
2306 } else {
2307
2308 ULONG NewValidDataToDisk;
2309
2310 //
2311 // Else set the context block to reflect the entire write
2312 // Also assert we got how many bytes we asked for.
2313 //
2314
2315 NT_ASSERT( Irp->IoStatus.Information == BytesToWrite );
2316
2317 Irp->IoStatus.Information = ByteCount;
2318
2319 //
2320 // Take this opportunity to update ValidDataToDisk.
2321 //
2322
2323 NewValidDataToDisk = StartingVbo + ByteCount;
2324
2325 if (NewValidDataToDisk > FileSize) {
2326 NewValidDataToDisk = FileSize;
2327 }
2328
2329 if (FcbOrDcb->ValidDataToDisk < NewValidDataToDisk) {
2330 FcbOrDcb->ValidDataToDisk = NewValidDataToDisk;
2331 }
2332 }
2333
2334 //
2335 // The transfer is either complete, or the Iosb contains the
2336 // appropriate status.
2337 //
2338
2339 try_return( Status );
2340
2341 } // if No Intermediate Buffering
2342
2343
2344 //
2345 // HANDLE CACHED CASE
2346 //
2347
2348 else {
2349
2350 NT_ASSERT( !PagingIo );
2351
2352 //
2353 // We delay setting up the file cache until now, in case the
2354 // caller never does any I/O to the file, and thus
2355 // FileObject->PrivateCacheMap == NULL.
2356 //
2357
2358 if ( FileObject->PrivateCacheMap == NULL ) {
2359
2360 DebugTrace(0, Dbg, "Initialize cache mapping.\n", 0);
2361
2362 //
2363 // Get the file allocation size, and if it is less than
2364 // the file size, raise file corrupt error.
2365 //
2366
2367 if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
2368
2369 FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
2370 }
2371
2372 if ( FileSize > FcbOrDcb->Header.AllocationSize.LowPart ) {
2373
2374 FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
2375
2377 }
2378
2379 //
2380 // Now initialize the cache map.
2381 //
2382
2384 (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize,
2385 FALSE,
2387 FcbOrDcb );
2388
2390
2391 //
2392 // Special case large floppy tranfers, and make the file
2393 // object write through. For small floppy transfers,
2394 // set a timer to go off in a second and flush the file.
2395 //
2396 //
2397
2398 if (!FlagOn( FileObject->Flags, FO_WRITE_THROUGH ) &&
2400
2401 if (((StartingByte.LowPart & (PAGE_SIZE-1)) == 0) &&
2402 (ByteCount >= PAGE_SIZE)) {
2403
2405
2406 } else {
2407
2408 LARGE_INTEGER OneSecondFromNow;
2409 PDEFERRED_FLUSH_CONTEXT FlushContext;
2410
2411 //
2412 // Get pool and initialize the timer and DPC
2413 //
2414
2415 FlushContext = FsRtlAllocatePoolWithTag( NonPagedPoolNx,
2416 sizeof(DEFERRED_FLUSH_CONTEXT),
2418
2419 KeInitializeTimer( &FlushContext->Timer );
2420
2421 KeInitializeDpc( &FlushContext->Dpc,
2423 FlushContext );
2424
2425
2426 //
2427 // We have to reference the file object here.
2428 //
2429
2431
2432 FlushContext->File = FileObject;
2433
2434 //
2435 // Let'er rip!
2436 //
2437
2438 OneSecondFromNow.QuadPart = (LONG)-1*1000*1000*10;
2439
2440 KeSetTimer( &FlushContext->Timer,
2441 OneSecondFromNow,
2442 &FlushContext->Dpc );
2443 }
2444 }
2445 }
2446
2447 //
2448 // If this write is beyond valid data length, then we
2449 // must zero the data in between.
2450 //
2451
2452 if ( StartingVbo > ValidDataToCheck ) {
2453
2454 //
2455 // Call the Cache Manager to zero the data.
2456 //
2457
2458 if (!FatZeroData( IrpContext,
2459 Vcb,
2460 FileObject,
2461 ValidDataToCheck,
2462 StartingVbo - ValidDataToCheck )) {
2463
2464 DebugTrace( 0, Dbg, "Cached Write could not wait to zero\n", 0 );
2465
2466 try_return( PostIrp = TRUE );
2467 }
2468 }
2469
2470 WriteFileSizeToDirent = BooleanFlagOn(IrpContext->Flags,
2472
2473
2474 //
2475 // DO A NORMAL CACHED WRITE, if the MDL bit is not set,
2476 //
2477
2478 if (!FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
2479
2480 DebugTrace(0, Dbg, "Cached write.\n", 0);
2481
2482 //
2483 // Get hold of the user's buffer.
2484 //
2485
2486 SystemBuffer = FatMapUserBuffer( IrpContext, Irp );
2487
2488 //
2489 // Do the write, possibly writing through
2490 //
2491
2492#if (NTDDI_VERSION >= NTDDI_WIN8)
2493 if (!CcCopyWriteEx( FileObject,
2494 &StartingByte,
2495 ByteCount,
2496 Wait,
2497 SystemBuffer,
2498 Irp->Tail.Overlay.Thread )) {
2499#else
2500 if (!CcCopyWrite( FileObject,
2501 &StartingByte,
2502 ByteCount,
2503 Wait,
2504 SystemBuffer )) {
2505#endif
2506
2507 DebugTrace( 0, Dbg, "Cached Write could not wait\n", 0 );
2508
2509 try_return( PostIrp = TRUE );
2510 }
2511
2512 Irp->IoStatus.Status = STATUS_SUCCESS;
2513 Irp->IoStatus.Information = ByteCount;
2514
2516
2517 } else {
2518
2519 //
2520 // DO AN MDL WRITE
2521 //
2522
2523 DebugTrace(0, Dbg, "MDL write.\n", 0);
2524
2525 NT_ASSERT( Wait );
2526
2528 &StartingByte,
2529 ByteCount,
2530 &Irp->MdlAddress,
2531 &Irp->IoStatus );
2532
2533 Status = Irp->IoStatus.Status;
2534
2535 try_return( Status );
2536 }
2537 }
2538 }
2539
2540 //
2541 // These two cases correspond to a system write directory file and
2542 // ea file.
2543 //
2544
2545 if (( TypeOfOpen == DirectoryFile ) || ( TypeOfOpen == EaFile)
2546 ) {
2547
2549
2550#if FASTFATDBG
2551 if ( TypeOfOpen == DirectoryFile ) {
2552 DebugTrace(0, Dbg, "Type of write is directoryfile\n", 0);
2553 } else if ( TypeOfOpen == EaFile) {
2554 DebugTrace(0, Dbg, "Type of write is eafile\n", 0);
2555 }
2556#endif
2557
2558 //
2559 // Make sure the FcbOrDcb is still good
2560 //
2561
2562 FatVerifyFcb( IrpContext, FcbOrDcb );
2563
2564 //
2565 // Synchronize here with people deleting directories and
2566 // mucking with the internals of the EA file.
2567 //
2568
2569 if (!ExAcquireSharedStarveExclusive( FcbOrDcb->Header.PagingIoResource,
2570 Wait )) {
2571
2572 DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %p shared without waiting\n", FcbOrDcb );
2573
2574 try_return( PostIrp = TRUE );
2575 }
2576
2577 PagingIoResourceAcquired = TRUE;
2578
2579 if (!Wait) {
2580
2581 IrpContext->FatIoContext->Wait.Async.Resource =
2582 FcbOrDcb->Header.PagingIoResource;
2583 }
2584
2585 //
2586 // Check to see if we colided with a MoveFile call, and if
2587 // so block until it completes.
2588 //
2589
2590 if (FcbOrDcb->MoveFileEvent) {
2591
2593 Executive,
2594 KernelMode,
2595 FALSE,
2596 NULL );
2597 }
2598
2599 //
2600 // If we weren't called by the Lazy Writer, then this write
2601 // must be the result of a write-through or flush operation.
2602 // Setting the IrpContext flag, will cause DevIoSup.c to
2603 // write-through the data to the disk.
2604 //
2605
2607
2608 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );
2609 }
2610
2611 //
2612 // For the noncached case, assert that everything is sector
2613 // alligned.
2614 //
2615
2616#ifdef _MSC_VER
2617#pragma prefast( suppress:28931, "needed for debug build" )
2618#endif
2619 SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
2620
2621 //
2622 // We make several assumptions about these two types of files.
2623 // Make sure all of them are true.
2624 //
2625
2626 NT_ASSERT( NonCachedIo && PagingIo );
2627 NT_ASSERT( ((StartingVbo | ByteCount) & (SectorSize - 1)) == 0 );
2628
2629
2630 //
2631 // These calls must always be within the allocation size, which is
2632 // convienently the same as filesize, which conveniently doesn't
2633 // get reset to a hint value when we verify the volume.
2634 //
2635
2636 if (StartingVbo >= FcbOrDcb->Header.FileSize.LowPart) {
2637
2638 DebugTrace( 0, Dbg, "PagingIo dirent started beyond EOF.\n", 0 );
2639
2640 Irp->IoStatus.Information = 0;
2641
2643 }
2644
2645 if ( StartingVbo + ByteCount > FcbOrDcb->Header.FileSize.LowPart ) {
2646
2647 DebugTrace( 0, Dbg, "PagingIo dirent extending beyond EOF.\n", 0 );
2648 ByteCount = FcbOrDcb->Header.FileSize.LowPart - StartingVbo;
2649 }
2650
2651
2652 //
2653 // Perform the actual IO
2654 //
2655
2656 if (FatNonCachedIo( IrpContext,
2657 Irp,
2658 FcbOrDcb,
2660 ByteCount,
2661 ByteCount,
2662 0 ) == STATUS_PENDING) {
2663
2664 IrpContext->FatIoContext = NULL;
2665
2666 Irp = NULL;
2667
2669 }
2670
2671 //
2672 // The transfer is either complete, or the Iosb contains the
2673 // appropriate status.
2674 //
2675 // Also, mark the volume as needing verification to automatically
2676 // clean up stuff.
2677 //
2678
2679 if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
2680
2681 FatNormalizeAndRaiseStatus( IrpContext, Status );
2682 }
2683
2684 try_return( Status );
2685 }
2686
2687 //
2688 // This is the case of a user who openned a directory. No writing is
2689 // allowed.
2690 //
2691
2692 if ( TypeOfOpen == UserDirectoryOpen ) {
2693
2694 DebugTrace( 0, Dbg, "FatCommonWrite -> STATUS_INVALID_PARAMETER\n", 0);
2695
2697 }
2698
2699 //
2700 // If we get this far, something really serious is wrong.
2701 //
2702
2703 DebugDump("Illegal TypeOfOpen\n", 0, FcbOrDcb );
2704
2705#ifdef _MSC_VER
2706#pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
2707#endif
2709
2710 try_exit: NOTHING;
2711
2712
2713 //
2714 // If the request was not posted and there is still an Irp,
2715 // deal with it.
2716 //
2717
2718 if (Irp) {
2719
2720 if ( !PostIrp ) {
2721
2722 ULONG ActualBytesWrote;
2723
2724 DebugTrace( 0, Dbg, "Completing request with status = %08lx\n",
2725 Status);
2726
2727 DebugTrace( 0, Dbg, " Information = %08lx\n",
2728 Irp->IoStatus.Information);
2729
2730 //
2731 // Record the total number of bytes actually written
2732 //
2733
2734 ActualBytesWrote = (ULONG)Irp->IoStatus.Information;
2735
2736 //
2737 // If the file was opened for Synchronous IO, update the current
2738 // file position.
2739 //
2740
2741 if (SynchronousIo && !PagingIo) {
2742
2743 FileObject->CurrentByteOffset.LowPart =
2744 StartingVbo + (NT_ERROR( Status ) ? 0 : ActualBytesWrote);
2745 }
2746
2747 //
2748 // The following are things we only do if we were successful
2749 //
2750
2751 if ( NT_SUCCESS( Status ) ) {
2752
2753 //
2754 // If this was not PagingIo, mark that the modify
2755 // time on the dirent needs to be updated on close.
2756 //
2757
2758 if ( !PagingIo ) {
2759
2761 }
2762
2763 //
2764 // If we extended the file size and we are meant to
2765 // immediately update the dirent, do so. (This flag is
2766 // set for either Write Through or noncached, because
2767 // in either case the data and any necessary zeros are
2768 // actually written to the file.)
2769 //
2770
2771 if ( ExtendingFile && WriteFileSizeToDirent ) {
2772
2773 NT_ASSERT( FileObject->DeleteAccess || FileObject->WriteAccess );
2774
2775 FatSetFileSizeInDirent( IrpContext, FcbOrDcb, NULL );
2776
2777 //
2778 // Report that a file size has changed.
2779 //
2780
2781 FatNotifyReportChange( IrpContext,
2782 Vcb,
2783 FcbOrDcb,
2786 }
2787
2788 if ( ExtendingFile && !WriteFileSizeToDirent ) {
2789
2791 }
2792
2793 if ( ExtendingValidData ) {
2794
2795 ULONG EndingVboWritten = StartingVbo + ActualBytesWrote;
2796
2797 //
2798 // Never set a ValidDataLength greater than FileSize.
2799 //
2800
2801 if ( FileSize < EndingVboWritten ) {
2802
2803 FcbOrDcb->Header.ValidDataLength.LowPart = FileSize;
2804
2805 } else {
2806
2807 FcbOrDcb->Header.ValidDataLength.LowPart = EndingVboWritten;
2808 }
2809
2810 //
2811 // Now, if we are noncached and the file is cached, we must
2812 // tell the cache manager about the VDL extension so that
2813 // async cached IO will not be optimized into zero-page faults
2814 // beyond where it believes VDL is.
2815 //
2816 // In the cached case, since Cc did the work, it has updated
2817 // itself already.
2818 //
2819
2820 if (NonCachedIo && CcIsFileCached(FileObject)) {
2822 }
2823 }
2824
2825 }
2826
2827 //
2828 // Note that we have to unpin repinned Bcbs here after the above
2829 // work, but if we are going to post the request, we must do this
2830 // before the post (below).
2831 //
2832
2833 FatUnpinRepinnedBcbs( IrpContext );
2834
2835 } else {
2836
2837 //
2838 // Take action if the Oplock package is not going to post the Irp.
2839 //
2840
2841 if (!OplockPostIrp) {
2842
2843 FatUnpinRepinnedBcbs( IrpContext );
2844
2845 if ( ExtendingFile ) {
2846
2847 //
2848 // We need the PagingIo resource exclusive whenever we
2849 // pull back either file size or valid data length.
2850 //
2851
2852 NT_ASSERT( FcbOrDcb->Header.PagingIoResource != NULL );
2853
2855
2856 FcbOrDcb->Header.FileSize.LowPart = InitialFileSize;
2857
2858 NT_ASSERT( FcbOrDcb->Header.FileSize.LowPart <= FcbOrDcb->Header.AllocationSize.LowPart );
2859
2860 //
2861 // Pull back the cache map as well
2862 //
2863
2864 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
2865
2867 }
2868
2869 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
2870 }
2871
2872 DebugTrace( 0, Dbg, "Passing request to Fsp\n", 0 );
2873
2874 Status = FatFsdPostRequest(IrpContext, Irp);
2875 }
2876 }
2877 }
2878
2879 } _SEH2_FINALLY {
2880
2881 DebugUnwind( FatCommonWrite );
2882
2884
2885 //
2886 // Restore initial file size and valid data length
2887 //
2888
2889 if (ExtendingFile || ExtendingValidData) {
2890
2891 //
2892 // We got an error, pull back the file size if we extended it.
2893 //
2894
2895 FcbOrDcb->Header.FileSize.LowPart = InitialFileSize;
2896 FcbOrDcb->Header.ValidDataLength.LowPart = InitialValidDataLength;
2897
2898 NT_ASSERT( FcbOrDcb->Header.FileSize.LowPart <= FcbOrDcb->Header.AllocationSize.LowPart );
2899
2900 //
2901 // Pull back the cache map as well
2902 //
2903
2904 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
2905
2907 }
2908 }
2909 }
2910
2911 //
2912 // Check if this needs to be backed out.
2913 //
2914
2915 if (UnwindOutstandingAsync) {
2916
2918 0xffffffff,
2920 }
2921
2922 //
2923 // If the FcbOrDcb has been acquired, release it.
2924 //
2925
2926 if (FcbOrDcbAcquired && Irp) {
2927
2929 }
2930
2931 if (PagingIoResourceAcquired && Irp) {
2932
2933 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
2934 }
2935
2936 //
2937 // Complete the request if we didn't post it and no exception
2938 //
2939 // Note that FatCompleteRequest does the right thing if either
2940 // IrpContext or Irp are NULL
2941 //
2942
2943 if ( !PostIrp && !_SEH2_AbnormalTermination() ) {
2944
2945 FatCompleteRequest( IrpContext, Irp, Status );
2946 }
2947
2948 DebugTrace(-1, Dbg, "FatCommonWrite -> %08lx\n", Status );
2949 } _SEH2_END;
2950
2951 return Status;
2952}
#define PAGED_CODE()
ULONG WriteLength
Definition: CcPinRead_drv.c:40
#define VOID
Definition: acefi.h:82
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedExchange
Definition: armddk.h:54
#define READ_AHEAD_GRANULARITY
Definition: btrfs_drv.h:114
PEPROCESS __stdcall PsGetThreadProcess(_In_ PETHREAD Thread)
VOID NTAPI CcPrepareMdlWrite(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus)
Definition: mdlsup.c:91
VOID NTAPI CcSetReadAheadGranularity(IN PFILE_OBJECT FileObject, IN ULONG Granularity)
Definition: cachesub.c:36
VOID NTAPI CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, OUT OPTIONAL PIO_STATUS_BLOCK IoStatus)
Definition: cachesub.c:222
NTKERNELAPI VOID NTAPI CcCoherencyFlushAndPurgeCache(_In_ PSECTION_OBJECT_POINTERS SectionObjectPointer, _In_opt_ PLARGE_INTEGER FileOffset, _In_ ULONG Length, _Out_ PIO_STATUS_BLOCK IoStatus, _In_opt_ ULONG Flags)
#define CcGetFileSizePointer(FO)
Definition: ccfuncs.h:389
#define CcIsFileCached(FO)
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN TypeOfOpen
Definition: cdprocs.h:589
@ UserDirectoryOpen
Definition: cdprocs.h:576
@ UserVolumeOpen
Definition: cdprocs.h:575
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:592
enum _TYPE_OF_OPEN TYPE_OF_OPEN
#define try_return(S)
Definition: cdprocs.h:2179
#define CCB_FLAG_ALLOW_EXTENDED_DASD_IO
Definition: cdstruc.h:1108
#define IRP_CONTEXT_FLAG_IN_FSP
Definition: cdstruc.h:1219
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1215
Definition: Header.h:9
#define Len
Definition: deflate.h:82
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:712
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4137
LONGLONG LBO
Definition: fat.h:34
#define FatReservedBytes(B)
Definition: fat.h:414
ULONG32 VBO
Definition: fat.h:38
#define FatBytesPerFat(B)
Definition: fat.h:410
#define TAG_DEFERRED_FLUSH_CONTEXT
Definition: nodetype.h:172
#define TAG_FAT_IO_CONTEXT
Definition: nodetype.h:165
#define FatBugCheck(A, B, C)
Definition: nodetype.h:104
#define TAG_EVENT
Definition: nodetype.h:162
#define TAG_IO_RUNS
Definition: nodetype.h:168
KDEFERRED_ROUTINE FatDeferredFlushDpc
Definition: write.c:52
#define CollectWriteStats(VCB, OPEN_TYPE, BYTE_COUNT)
Definition: write.c:35
BOOLEAN FatNoAsync
Definition: write.c:46
#define ULONG_PTR
Definition: config.h:101
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define ExGetCurrentResourceThread()
Definition: env_spec_w32.h:633
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define ExConvertExclusiveToSharedLite(res)
Definition: env_spec_w32.h:652
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
#define ExAcquireResourceSharedLite(res, wait)
Definition: env_spec_w32.h:621
#define PagedPool
Definition: env_spec_w32.h:308
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
#define ClearFlag(_F, _SF)
Definition: ext2fs.h:191
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
#define IRP_CONTEXT_FLAG_USER_IO
Definition: ext2fs.h:1095
#define FILE_WRITE_TO_END_OF_FILE
Definition: ext2fs.h:278
#define IRP_CONTEXT_FLAG_WRITE_THROUGH
Definition: ext2fs.h:1088
#define IRP_CONTEXT_STACK_IO_CONTEXT
Definition: ext2fs.h:1093
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
VOID FatUnpinRepinnedBcbs(IN PIRP_CONTEXT IrpContext)
Definition: cachesup.c:1407
VOID FatInitializeCacheMap(_In_ PFILE_OBJECT FileObject, _In_ PCC_FILE_SIZES FileSizes, _In_ BOOLEAN PinAccess, _In_ PCACHE_MANAGER_CALLBACKS Callbacks, _In_ PVOID LazyWriteContext)
Definition: cachesup.c:62
FINISHED FatZeroData(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_OBJECT FileObject, IN ULONG StartingZero, IN ULONG ByteCount)
Definition: cachesup.c:1659
PVOID FatMapUserBuffer(IN PIRP_CONTEXT IrpContext, IN OUT PIRP Irp)
Definition: deviosup.c:3357
VOID FatMultipleAsync(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PIRP MasterIrp, IN ULONG MultipleIrpCount, IN PIO_RUN IoRuns)
Definition: deviosup.c:1622
VOID FatWaitSync(IN PIRP_CONTEXT IrpContext)
Definition: deviosup.c:2367
VOID FatSingleAsync(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN LBO Lbo, IN ULONG ByteCount, IN PIRP Irp)
Definition: deviosup.c:1990
VOID FatLockUserBuffer(IN PIRP_CONTEXT IrpContext, IN OUT PIRP Irp, IN LOCK_OPERATION Operation, IN ULONG BufferLength)
Definition: deviosup.c:3276
LOGICAL FatDiskAccountingEnabled
Definition: fatdata.c:129
#define DebugDump(STR, LEVEL, PTR)
Definition: fatdata.h:314
#define DebugUnwind(X)
Definition: fatdata.h:315
VOID FatQuickVerifyVcb(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb)
Definition: verfysup.c:1662
#define FatDeleteIrpContext(IRPCONTEXT)
Definition: fatprocs.h:1762
IN PVCB IN VBO StartingVbo
Definition: fatprocs.h:412
NTSTATUS FatFsdPostRequest(IN PIRP_CONTEXT IrpContext, IN PIRP Irp)
Definition: workque.c:229
#define FatAcquireExclusiveVolume(IRPCONTEXT, VCB)
Definition: fatprocs.h:1409
TYPE_OF_OPEN FatDecodeFileObject(_In_ PFILE_OBJECT FileObject, _Outptr_ PVCB *Vcb, _Outptr_ PFCB *FcbOrDcb, _Outptr_ PCCB *Ccb)
Definition: filobsup.c:176
BOOLEAN FatLookupMcbEntry(IN PVCB Vcb, IN PLARGE_MCB Mcb, IN VBO Vbo, OUT PLBO Lbo, OUT PULONG ByteCount OPTIONAL, OUT PULONG Index OPTIONAL)
Definition: fsctrl.c:418
#define FatReleaseVolume(IRPCONTEXT, VCB)
Definition: fatprocs.h:1418
#define FatCompleteRequest(IRPCONTEXT, IRP, STATUS)
Definition: fatprocs.h:2633
#define FatNotifyReportChange(I, V, F, FL, A)
Definition: fatprocs.h:2168
@ EaFile
Definition: fatprocs.h:1047
#define FatReleaseFcb(IRPCONTEXT, Fcb)
Definition: fatprocs.h:1644
NTSTATUS FatFlushFat(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb)
Definition: flush.c:801
VOID NTAPI FatPrePostIrp(IN PVOID Context, IN PIRP Irp)
Definition: workque.c:91
#define FatResetExceptionState(IRPCONTEXT)
Definition: fatprocs.h:2983
IN PFCB FcbOrDcb
Definition: fatprocs.h:306
VOID FatRemoveMcbEntry(IN PVCB Vcb, IN PLARGE_MCB Mcb, IN VBO Vbo, IN ULONG SectorCount)
Definition: fsctrl.c:599
#define FatIsFastIoPossible(FCB)
Definition: fatprocs.h:2813
VOID NTAPI FatOplockComplete(IN PVOID Context, IN PIRP Irp)
Definition: workque.c:35
#define FatNormalizeAndRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2995
#define FatRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2977
_Acquires_shared_lock_ Fcb FINISHED FatAcquireSharedFcbWaitForEx(IN PIRP_CONTEXT IrpContext, IN PFCB Fcb)
@ Flush
Definition: fatprocs.h:1054
#define FatGetFcbOplock(F)
Definition: fatprocs.h:1656
VOID FatAddToWorkque(IN PIRP_CONTEXT IrpContext, IN PIRP Irp)
Definition: workque.c:280
static INLINE BOOLEAN FatIsIoRangeValid(IN PVCB Vcb, IN LARGE_INTEGER Start, IN ULONG Length)
Definition: fatprocs.h:218
#define IRP_CONTEXT_FLAG_RECURSIVE_CALL
Definition: fatstruc.h:1566
#define VCB_STATE_FLAG_LOCKED
Definition: fatstruc.h:559
#define VCB_STATE_FLAG_SHUTDOWN
Definition: fatstruc.h:563
#define IRP_CONTEXT_FLAG_DEFERRED_WRITE
Definition: fatstruc.h:1568
#define VCB_STATE_FLAG_DEFERRED_FLUSH
Definition: fatstruc.h:568
#define IRP_CONTEXT_FLAG_OVERRIDE_VERIFY
Definition: fatstruc.h:1574
#define FCB_LOOKUP_ALLOCATIONSIZE_HINT
Definition: fatstruc.h:1241
#define FCB_STATE_TRUNCATE_ON_CLOSE
Definition: fatstruc.h:1194
#define CCB_FLAG_DASD_FLUSH_DONE
Definition: fatstruc.h:1281
#define CCB_FLAG_SENT_FORMAT_UNIT
Definition: fatstruc.h:1345
#define IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH
Definition: fatstruc.h:1565
#define CCB_FLAG_DASD_PURGE_DONE
Definition: fatstruc.h:1282
#define CCB_FLAG_COMPLETE_DISMOUNT
Definition: fatstruc.h:1331
BOOLEAN NTAPI FsRtlCheckLockForWriteAccess(IN PFILE_LOCK FileLock, IN PIRP Irp)
Definition: filelock.c:710
#define _SEH2_FINALLY
Definition: filesup.c:21
_Must_inspect_result_ _Out_ PLARGE_INTEGER FileSize
Definition: fsrtlfuncs.h:108
#define FSRTL_CACHE_TOP_LEVEL_IRP
Definition: fsrtltypes.h:60
@ FastIoIsNotPossible
Definition: fsrtltypes.h:240
#define FSRTL_FLAG_USER_MAPPED_FILE
Definition: fsrtltypes.h:50
#define FSRTL_MAX_TOP_LEVEL_IRP_FLAG
Definition: fsrtltypes.h:65
VOID NTAPI CcSetFileSizes(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes)
Definition: fssup.c:356
BOOLEAN NTAPI CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN UninitializeCacheMaps)
Definition: fssup.c:386
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
#define NOTHING
Definition: input_list.c:10
ULONG NTAPI ExInterlockedAddUlong(IN OUT PULONG Addend, IN ULONG Increment, IN OUT PKSPIN_LOCK Lock)
Definition: interlocked.c:88
ULONG NTAPI FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:765
if(dx< 0)
Definition: linetemp.h:194
__in UCHAR __in POWER_STATE __in_opt PVOID __in PIO_STATUS_BLOCK IoStatus
Definition: mxum.h:159
#define KernelMode
Definition: asm.h:34
#define Int32x32To64(a, b)
@ NotificationEvent
BOOLEAN NTAPI CcCopyWrite(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN PVOID Buffer)
Definition: copysup.c:129
BOOLEAN NTAPI CcCanIWrite(IN PFILE_OBJECT FileObject, IN ULONG BytesToWrite, IN BOOLEAN Wait, IN UCHAR Retrying)
Definition: copysup.c:214
VOID NTAPI CcDeferWrite(IN PFILE_OBJECT FileObject, IN PCC_POST_DEFERRED_WRITE PostRoutine, IN PVOID Context1, IN PVOID Context2, IN ULONG BytesToWrite, IN BOOLEAN Retrying)
Definition: copysup.c:225
BOOLEAN NTAPI ExAcquireSharedStarveExclusive(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:1068
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
BOOLEAN NTAPI ExIsResourceAcquiredExclusiveLite(IN PERESOURCE Resource)
Definition: resource.c:1624
PVOID NTAPI FsRtlAllocatePoolWithTag(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes, IN ULONG Tag)
Definition: filter.c:229
#define STATUS_PURGE_FAILED
Definition: ntstatus.h:964
#define STATUS_FILE_LOCK_CONFLICT
Definition: ntstatus.h:320
#define STATUS_TOO_LATE
Definition: ntstatus.h:626
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
NTSTATUS NTAPI FsRtlCheckOplock(IN POPLOCK Oplock, IN PIRP Irp, IN PVOID Context, IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL)
Definition: oplock.c:1170
long LONG
Definition: pedump.c:60
#define Vcb
Definition: cdprocs.h:1415
#define FILE_DEVICE_DISK
Definition: winioctl.h:113
#define _SEH2_AbnormalTermination()
Definition: pseh2_64.h:166
#define IRP_MJ_WRITE
Definition: rdpdr.c:47
#define STATUS_SUCCESS
Definition: shellext.h:65
Definition: cdstruc.h:1067
KSPIN_LOCK GeneralSpinLock
Definition: fatstruc.h:152
CACHE_MANAGER_CALLBACKS CacheManagerCallbacks
Definition: fatstruc.h:159
ULONG Flags
Definition: ntfs.h:536
struct _FCB::@724::@727 Fcb
union _FCB::@724 Specific
ULONG ValidDataToDisk
Definition: fatstruc.h:928
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:925
PKEVENT MoveFileEvent
Definition: fatstruc.h:1175
PNON_PAGED_FCB NonPaged
Definition: fatstruc.h:811
CLONG PurgeFailureModeEnableCount
Definition: fatstruc.h:896
struct _IO_STACK_LOCATION::@3983::@3988 Write
union _IO_STACK_LOCATION::@1568 Parameters
PKEVENT OutstandingAsyncEvent
Definition: fatstruc.h:743
ULONG OutstandingAsyncWrites
Definition: fatstruc.h:737
SECTION_OBJECT_POINTERS SectionObjectPointers
Definition: fatstruc.h:729
Definition: cdstruc.h:498
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
uint32_t * PULONG
Definition: typedefs.h:59
void * PVOID
Definition: typedefs.h:50
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint64_t ULONGLONG
Definition: typedefs.h:67
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_DISK_FULL
Definition: udferr_usr.h:155
#define STATUS_FILE_CORRUPT_ERROR
Definition: udferr_usr.h:168
#define NT_ERROR(Status)
Definition: umtypes.h:106
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG LowPart
Definition: typedefs.h:106
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:170
VOID(NTAPI * PCC_POST_DEFERRED_WRITE)(_In_ PVOID Context1, _In_ PVOID Context2)
Definition: cctypes.h:66
_In_ ULONG SectorSize
Definition: halfuncs.h:291
#define FILE_NOTIFY_CHANGE_SIZE
#define IO_TYPE_IRP
#define FILE_ACTION_MODIFIED
#define IRP_PAGING_IO
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _In_ LARGE_INTEGER ByteCount
Definition: iotypes.h:1099
#define FO_WRITE_THROUGH
Definition: iotypes.h:1779
#define FO_FILE_MODIFIED
Definition: iotypes.h:1788
#define SL_FORCE_DIRECT_WRITE
Definition: iotypes.h:1826
* PFILE_OBJECT
Definition: iotypes.h:1998
#define IRP_MN_MDL
Definition: iotypes.h:4419
#define FO_FILE_SIZE_CHANGED
Definition: iotypes.h:1789
#define FO_SYNCHRONOUS_IO
Definition: iotypes.h:1776
#define IRP_SYNCHRONOUS_PAGING_IO
#define IRP_NOCACHE
@ Executive
Definition: ketypes.h:415
@ IoReadAccess
Definition: ketypes.h:863
#define ObReferenceObject
Definition: obfuncs.h:204

◆ FatDeferredFlush()

VOID NTAPI FatDeferredFlush ( _In_ PVOID  Parameter)

Definition at line 3016 of file write.c.

3036{
3037
3039 PVCB Vcb;
3040 PFCB FcbOrDcb;
3041 PCCB Ccb;
3042
3043 PAGED_CODE();
3044
3046
3048 NT_ASSERT( FcbOrDcb != NULL );
3049
3050 //
3051 // Make us appear as a top level FSP request so that we will
3052 // receive any errors from the flush.
3053 //
3054
3056
3058 ExAcquireResourceSharedLite( FcbOrDcb->Header.PagingIoResource, TRUE );
3059
3060 CcFlushCache( File->SectionObjectPointer, NULL, 0, NULL );
3061
3062 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
3064
3066
3068
3070
3071}
Definition: File.h:16
File()
Definition: File.h:18
DEFERRED_FLUSH_CONTEXT * PDEFERRED_FLUSH_CONTEXT
Definition: fatstruc.h:1690
#define FSRTL_FSP_TOP_LEVEL_IRP
Definition: fsrtltypes.h:59
#define ObDereferenceObject
Definition: obfuncs.h:203
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:323

◆ FatDeferredFlushDpc()

VOID NTAPI FatDeferredFlushDpc ( _In_ PKDPC  Dpc,
_In_opt_ PVOID  DeferredContext,
_In_opt_ PVOID  SystemArgument1,
_In_opt_ PVOID  SystemArgument2 
)

Definition at line 2961 of file write.c.

2986{
2987 PDEFERRED_FLUSH_CONTEXT FlushContext;
2988
2992
2994
2995 //
2996 // Send it off
2997 //
2998
2999 ExInitializeWorkItem( &FlushContext->Item,
3001 FlushContext );
3002
3003#ifdef _MSC_VER
3004#pragma prefast( suppress:28159, "prefast indicates this API is obsolete, but it's ok for fastfat to keep using it" )
3005#endif
3006 ExQueueWorkItem( &FlushContext->Item, CriticalWorkQueue );
3007}
WORKER_THREAD_ROUTINE FatDeferredFlush
Definition: write.c:63
WORK_QUEUE_ITEM Item
Definition: fatstruc.h:1684
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
VOID NTAPI ExQueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, IN WORK_QUEUE_TYPE QueueType)
Definition: work.c:723
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
@ CriticalWorkQueue
Definition: extypes.h:189
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:688
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:687
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:689

Variable Documentation

◆ FatDeferredFlush

VOID NTAPI FatDeferredFlush

Definition at line 63 of file write.c.

Referenced by FatDeferredFlushDpc().

◆ FatDeferredFlushDpc

VOID NTAPI FatDeferredFlushDpc

Definition at line 52 of file write.c.

Referenced by _Requires_lock_held_().

◆ FatNoAsync

BOOLEAN FatNoAsync = FALSE

Definition at line 46 of file write.c.

Referenced by _Requires_lock_held_().