ReactOS  0.4.15-dev-492-ga1108f6
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:
{ \
PFILESYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors].Common; \
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); \
} \
}
FORCEINLINE ULONG KeGetCurrentProcessorNumber(VOID)
Definition: ke.h:337
ULONG NumberProcessors
Definition: fatstruc.h:80
struct _VCB VCB
FAT_DATA FatData
Definition: fatdata.c:56
unsigned int ULONG
Definition: retypes.h:1

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 
143  FatPagingFileIo( Irp, Fcb );
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 }
#define TRUE
Definition: types.h:120
#define FsRtlEnterFileSystem
BOOLEAN FatIsIrpTopLevel(IN PIRP Irp)
Definition: fatdata.c:817
#define FSRTL_MOD_WRITE_TOP_LEVEL_IRP
Definition: fsrtltypes.h:61
NTSTATUS Status
Definition: write.c:2803
#define FsRtlExitFileSystem
_In_ PIRP Irp
Definition: csq.h:116
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
Definition: cdstruc.h:908
LONG NTSTATUS
Definition: precomp.h:26
#define FatDeviceIsFatFsdo(D)
Definition: fatprocs.h:3092
#define DebugTrace(INDENT, LEVEL, X, Y)
Definition: fatdata.h:313
_SEH2_TRY
Definition: create.c:4226
IN PFCB IN PCCB IN TYPE_OF_OPEN IN BOOLEAN IN BOOLEAN TopLevel
Definition: fatprocs.h:2410
#define IRP_MN_COMPLETE
Definition: iotypes.h:4066
#define FCB_STATE_PAGING_FILE
Definition: fatstruc.h:1194
VOID FatPagingFileIo(IN PIRP Irp, IN PFCB Fcb)
Definition: deviosup.c:211
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:11
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
NodeType
Definition: Node.h:5
PIRP_CONTEXT FatCreateIrpContext(IN PIRP Irp, IN BOOLEAN Wait)
Definition: strucsup.c:2289
#define STATUS_PENDING
Definition: ntstatus.h:82
FCB * PFCB
Definition: cdstruc.h:1046
PIRP NTAPI IoGetTopLevelIrp(VOID)
Definition: irp.c:1843
#define CanFsdWait(I)
Definition: cdprocs.h:2001
VOID NTAPI IoSetTopLevelIrp(IN PIRP Irp)
Definition: irp.c:2000
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
Status
Definition: gdiplustypes.h:24
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1569
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
PFILE_OBJECT FileObject
Definition: iotypes.h:2815
_SEH2_END
Definition: create.c:4400
ULONG FatExceptionFilter(IN PIRP_CONTEXT IrpContext, IN PEXCEPTION_POINTERS ExceptionPointer)
Definition: fatdata.c:204
NTSTATUS FatCompleteMdl(IN PIRP_CONTEXT IrpContext, IN PIRP Irp)
Definition: cachesup.c:1728
#define Dbg
Definition: write.c:29
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
_In_ PFCB Fcb
Definition: cdprocs.h:159
IoMarkIrpPending(Irp)
ULONG FcbState
Definition: cdstruc.h:977
#define FAT_NTC_FCB
Definition: nodetype.h:29
#define NT_ASSERT
Definition: rtlfuncs.h:3312

◆ _Requires_lock_held_()

_Requires_lock_held_ ( _Global_critical_region_  )

Definition at line 220 of file write.c.

249 {
250  PVCB Vcb;
251  PFCB FcbOrDcb;
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;
283  BOOLEAN Wait;
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 
331  ByteCount = IrpSp->Parameters.Write.Length;
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;
431  FatCompleteRequest( IrpContext, Irp, STATUS_DISK_FULL );
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 
522  if (TypeOfOpen == VirtualVolumeFile) {
523 
524  LBO DirtyLbo;
525  LBO CleanLbo;
526 
527  VBO DirtyVbo;
528  VBO StartingDirtyVbo;
529 
530  ULONG DirtyByteCount;
531  ULONG CleanByteCount;
532 
533  ULONG WriteLength;
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,
587  StartingVbo,
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,
823  WriteLength,
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 
931  return STATUS_ACCESS_DENIED;
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 
1050  FatLockUserBuffer( IrpContext, Irp, IoReadAccess, ByteCount );
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 
1059  SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
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 
1174  IO_STATUS_BLOCK IoStatus = {0};
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 
1489  if ((ULONG_PTR)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG &&
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;
1789  try_return( NOTHING );
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 
1808  if (!FsRtlCheckLockForWriteAccess( &FcbOrDcb->Specific.Fcb.FileLock, Irp )) {
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 
1839  SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH);
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 
2032  if (CcIsFileCached(FileObject)) {
2033  CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize );
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 
2093  ULONG SectorSize;
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,
2269  StartingVbo,
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 
2404  SetFlag( FileObject->Flags, FO_WRITE_THROUGH );
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 
2548  ULONG SectorSize;
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,
2659  StartingVbo,
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 
2760  SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
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)) {
2821  CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize );
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 
2883  if (_SEH2_AbnormalTermination()) {
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 READ_AHEAD_GRANULARITY
Definition: btrfs_drv.h:118
#define ExGetCurrentResourceThread()
Definition: env_spec_w32.h:633
#define FatReleaseVolume(IRPCONTEXT, VCB)
Definition: fatprocs.h:1418
BOOLEAN NTAPI CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN UninitializeCacheMaps)
Definition: fssup.c:386
#define FILE_DEVICE_DISK
Definition: winioctl.h:112
#define TAG_IO_RUNS
Definition: nodetype.h:168
#define TRUE
Definition: types.h:120
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1221
#define FatNormalizeAndRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2992
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
PVOID FatMapUserBuffer(IN PIRP_CONTEXT IrpContext, IN OUT PIRP Irp)
Definition: deviosup.c:3357
NTSTATUS Status
Definition: write.c:2803
#define FCB_LOOKUP_ALLOCATIONSIZE_HINT
Definition: fatstruc.h:1240
PVOID NTAPI FsRtlAllocatePoolWithTag(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes, IN ULONG Tag)
Definition: filter.c:229
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
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
#define VCB_STATE_FLAG_DEFERRED_FLUSH
Definition: fatstruc.h:567
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:225
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:931
CACHE_MANAGER_CALLBACKS CacheManagerCallbacks
Definition: fatstruc.h:158
#define FatCompleteRequest(IRPCONTEXT, IRP, STATUS)
Definition: fatprocs.h:2630
#define CCB_FLAG_SENT_FORMAT_UNIT
Definition: fatstruc.h:1344
IN PLARGE_INTEGER IN ULONG IN BOOLEAN IN ULONG IN BOOLEAN OUT PIO_STATUS_BLOCK IoStatus
Definition: fatprocs.h:2659
_In_ PIRP Irp
Definition: csq.h:116
Definition: cdstruc.h:908
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
LOGICAL FatDiskAccountingEnabled
Definition: fatdata.c:129
VOID FatAddToWorkque(IN PIRP_CONTEXT IrpContext, IN PIRP Irp)
Definition: workque.c:277
#define IRP_CONTEXT_FLAG_WRITE_THROUGH
Definition: ext2fs.h:1079
#define IRP_CONTEXT_STACK_IO_CONTEXT
Definition: ext2fs.h:1084
VOID FatLockUserBuffer(IN PIRP_CONTEXT IrpContext, IN OUT PIRP Irp, IN LOCK_OPERATION Operation, IN ULONG BufferLength)
Definition: deviosup.c:3276
#define CCB_FLAG_ALLOW_EXTENDED_DASD_IO
Definition: cdstruc.h:1114
BOOLEAN NTAPI FsRtlCheckLockForWriteAccess(IN PFILE_LOCK FileLock, IN PIRP Irp)
Definition: filelock.c:714
VOID FatUnpinRepinnedBcbs(IN PIRP_CONTEXT IrpContext)
Definition: cachesup.c:1407
Definition: cdstruc.h:1073
ULONG32 VBO
Definition: fat.h:38
#define FatNotifyReportChange(I, V, F, FL, A)
Definition: fatprocs.h:2165
VOID NTAPI ExConvertExclusiveToSharedLite(IN PERESOURCE Resource)
Definition: resource.c:1402
VOID NTAPI FatOplockComplete(IN PVOID Context, IN PIRP Irp)
Definition: workque.c:35
LONG NTSTATUS
Definition: precomp.h:26
#define DebugTrace(INDENT, LEVEL, X, Y)
Definition: fatdata.h:313
KSPIN_LOCK GeneralSpinLock
Definition: fatstruc.h:151
#define IRP_NOCACHE
Definition: cdstruc.h:504
#define FILE_NOTIFY_CHANGE_SIZE
SECTION_OBJECT_POINTERS SectionObjectPointers
Definition: fatstruc.h:728
VOID FatWaitSync(IN PIRP_CONTEXT IrpContext)
Definition: deviosup.c:2367
CLONG PurgeFailureModeEnableCount
Definition: fatstruc.h:895
#define FatRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2974
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
ULONG NTAPI FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:769
struct _FCB::@711::@714 Fcb
_SEH2_TRY
Definition: create.c:4226
#define IRP_CONTEXT_FLAG_DEFERRED_WRITE
Definition: fatstruc.h:1563
uint32_t ULONG_PTR
Definition: typedefs.h:64
#define FO_SYNCHRONOUS_IO
Definition: iotypes.h:1735
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
#define FO_FILE_SIZE_CHANGED
Definition: iotypes.h:1748
#define FatReservedBytes(B)
Definition: fat.h:414
PEPROCESS __stdcall PsGetThreadProcess(_In_ PETHREAD Thread)
FORCEINLINE ULONG KeGetCurrentProcessorNumber(VOID)
Definition: ke.h:337
#define FO_FILE_MODIFIED
Definition: iotypes.h:1747
IN PFCB FcbOrDcb
Definition: fatprocs.h:306
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN TypeOfOpen
Definition: cdprocs.h:588
#define STATUS_FILE_CORRUPT_ERROR
Definition: udferr_usr.h:168
ULONG NumberProcessors
Definition: fatstruc.h:80
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
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
VOID(NTAPI * PCC_POST_DEFERRED_WRITE)(_In_ PVOID Context1, _In_ PVOID Context2)
Definition: cctypes.h:66
Definition: Header.h:8
#define FatAcquireExclusiveVolume(IRPCONTEXT, VCB)
Definition: fatprocs.h:1409
long LONG
Definition: pedump.c:60
LONGLONG LBO
Definition: fat.h:34
#define FatGetFcbOplock(F)
Definition: fatprocs.h:1656
#define CcIsFileCached(FO)
static INLINE BOOLEAN FatIsIoRangeValid(IN PVCB Vcb, IN LARGE_INTEGER Start, IN ULONG Length)
Definition: fatprocs.h:218
VOID FatRemoveMcbEntry(IN PVCB Vcb, IN PLARGE_MCB Mcb, IN VBO Vbo, IN ULONG SectorCount)
Definition: fsctrl.c:599
#define FatBugCheck(A, B, C)
Definition: nodetype.h:104
#define FatBytesPerFat(B)
Definition: fat.h:410
#define FILE_ACTION_MODIFIED
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
PNON_PAGED_FCB NonPaged
Definition: fatstruc.h:810
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
BOOLEAN NTAPI ExIsResourceAcquiredExclusiveLite(IN PERESOURCE Resource)
Definition: resource.c:1619
#define _SEH2_AbnormalTermination()
Definition: pseh2_64.h:13
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
BOOLEAN FatNoAsync
Definition: write.c:46
#define TAG_FAT_IO_CONTEXT
Definition: nodetype.h:165
void * PVOID
Definition: retypes.h:9
PKEVENT MoveFileEvent
Definition: fatstruc.h:1174
NodeType
Definition: Node.h:5
#define FCB_STATE_TRUNCATE_ON_CLOSE
Definition: fatstruc.h:1193
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:588
#define IRP_CONTEXT_FLAG_IN_FSP
Definition: cdstruc.h:1225
#define FILE_WRITE_TO_END_OF_FILE
Definition: ext2fs.h:273
#define IRP_CONTEXT_FLAG_USER_IO
Definition: ext2fs.h:1086
NTSTATUS FatFlushFat(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb)
Definition: flush.c:801
_Acquires_shared_lock_ Fcb FINISHED FatAcquireSharedFcbWaitForEx(IN PIRP_CONTEXT IrpContext, IN PFCB Fcb)
#define CCB_FLAG_COMPLETE_DISMOUNT
Definition: fatstruc.h:1330
#define DebugUnwind(X)
Definition: fatdata.h:315
FAT_DATA FatData
Definition: fatdata.c:56
#define FatReleaseFcb(IRPCONTEXT, Fcb)
Definition: fatprocs.h:1644
#define FatResetExceptionState(IRPCONTEXT)
Definition: fatprocs.h:2980
#define VCB_STATE_FLAG_LOCKED
Definition: fatstruc.h:558
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
BOOLEAN NTAPI CcCanIWrite(IN PFILE_OBJECT FileObject, IN ULONG BytesToWrite, IN BOOLEAN Wait, IN UCHAR Retrying)
Definition: copysup.c:214
#define try_return(S)
Definition: cdprocs.h:2179
uint64_t ULONGLONG
Definition: typedefs.h:66
#define Vcb
Definition: cdprocs.h:1415
#define CcGetFileSizePointer(FO)
Definition: ccfuncs.h:389
PIRP NTAPI IoGetTopLevelIrp(VOID)
Definition: irp.c:1843
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 Len
Definition: deflate.h:82
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
FINISHED FatZeroData(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_OBJECT FileObject, IN ULONG StartingZero, IN ULONG ByteCount)
Definition: cachesup.c:1659
#define FSRTL_MAX_TOP_LEVEL_IRP_FLAG
Definition: fsrtltypes.h:65
#define NT_ERROR(Status)
Definition: umtypes.h:106
#define STATUS_PURGE_FAILED
Definition: ntstatus.h:950
#define IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH
Definition: fatstruc.h:1560
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
* PFILE_OBJECT
Definition: iotypes.h:1957
ULONG Flags
Definition: ntfs.h:532
#define CCB_FLAG_DASD_FLUSH_DONE
Definition: fatstruc.h:1280
#define IO_TYPE_IRP
#define TAG_DEFERRED_FLUSH_CONTEXT
Definition: nodetype.h:172
#define VOID
Definition: acefi.h:82
#define IRP_MN_MDL
Definition: iotypes.h:4065
ULONG LowPart
Definition: typedefs.h:105
enum _TYPE_OF_OPEN TYPE_OF_OPEN
_Must_inspect_result_ _Out_ PLARGE_INTEGER FileSize
Definition: fsrtlfuncs.h:108
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:588
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define NOTHING
Definition: env_spec_w32.h:461
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
union _FCB::@711 Specific
KDEFERRED_ROUTINE FatDeferredFlushDpc
Definition: write.c:52
IN PVCB IN VBO StartingVbo
Definition: fatprocs.h:411
#define InterlockedExchange
Definition: armddk.h:54
ClearFlag(Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT)
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _In_ LARGE_INTEGER ByteCount
Definition: iotypes.h:1063
Status
Definition: gdiplustypes.h:24
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 ExAcquireSharedStarveExclusive(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:1063
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
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
#define VCB_STATE_FLAG_SHUTDOWN
Definition: fatstruc.h:562
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
PFILE_OBJECT FileObject
Definition: iotypes.h:2815
_SEH2_END
Definition: create.c:4400
#define CCB_FLAG_DASD_PURGE_DONE
Definition: fatstruc.h:1281
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define InterlockedIncrement
Definition: armddk.h:53
ULONG ValidDataToDisk
Definition: fatstruc.h:927
#define FatIsFastIoPossible(FCB)
Definition: fatprocs.h:2810
PKEVENT OutstandingAsyncEvent
Definition: fatstruc.h:742
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4137
VOID NTAPI CcSetFileSizes(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes)
Definition: fssup.c:356
_SEH2_FINALLY
Definition: create.c:4371
unsigned int * PULONG
Definition: retypes.h:1
#define TAG_EVENT
Definition: nodetype.h:162
#define IRP_PAGING_IO
BOOLEAN NTAPI ExAcquireResourceSharedLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:885
ULONG NTAPI ExInterlockedAddUlong(IN OUT PULONG Addend, IN ULONG Increment, IN OUT PKSPIN_LOCK Lock)
Definition: interlocked.c:88
#define STATUS_FILE_LOCK_CONFLICT
Definition: ntstatus.h:306
NTSTATUS FatFsdPostRequest(IN PIRP_CONTEXT IrpContext, IN PIRP Irp)
Definition: workque.c:229
#define ObReferenceObject
Definition: obfuncs.h:204
#define STATUS_DISK_FULL
Definition: udferr_usr.h:155
if(!find_data_address_in_chunk(Vcb, c, length, &address)) return false
unsigned int ULONG
Definition: retypes.h:1
#define IRP_CONTEXT_FLAG_RECURSIVE_CALL
Definition: fatstruc.h:1561
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define Dbg
Definition: write.c:29
#define ULONG_PTR
Definition: config.h:101
#define IRP_MJ_WRITE
Definition: rdpdr.c:47
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
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:1172
ExFreePool(ed)
#define CollectWriteStats(VCB, OPEN_TYPE, BYTE_COUNT)
Definition: write.c:35
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
VOID FatMultipleAsync(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PIRP MasterIrp, IN ULONG MultipleIrpCount, IN PIO_RUN IoRuns)
Definition: deviosup.c:1622
_In_ ULONG SectorSize
Definition: halfuncs.h:291
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2774
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:711
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
#define FSRTL_CACHE_TOP_LEVEL_IRP
Definition: fsrtltypes.h:60
#define FatDeleteIrpContext(IRPCONTEXT)
Definition: fatprocs.h:1762
#define IRP_CONTEXT_FLAG_OVERRIDE_VERIFY
Definition: fatstruc.h:1569
return STATUS_SUCCESS
Definition: btrfs.c:3014
VOID NTAPI FatPrePostIrp(IN PVOID Context, IN PIRP Irp)
Definition: workque.c:91
#define SL_FORCE_DIRECT_WRITE
Definition: iotypes.h:1785
VOID FatQuickVerifyVcb(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb)
Definition: verfysup.c:1662
ULONG FcbState
Definition: cdstruc.h:977
#define STATUS_TOO_LATE
Definition: ntstatus.h:612
TYPE_OF_OPEN FatDecodeFileObject(_In_ PFILE_OBJECT FileObject, _Outptr_ PVCB *Vcb, _Outptr_ PFCB *FcbOrDcb, _Outptr_ PCCB *Ccb)
Definition: filobsup.c:176
#define Int32x32To64(a, b)
#define FSRTL_FLAG_USER_MAPPED_FILE
Definition: fsrtltypes.h:50
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
#define IRP_SYNCHRONOUS_PAGING_IO
VOID FatSingleAsync(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN LBO Lbo, IN ULONG ByteCount, IN PIRP Irp)
Definition: deviosup.c:1990
LONGLONG QuadPart
Definition: typedefs.h:113
#define FO_WRITE_THROUGH
Definition: iotypes.h:1738
#define PAGED_CODE()
IN BOOLEAN Wait
Definition: fatprocs.h:1538
#define DebugDump(STR, LEVEL, PTR)
Definition: fatdata.h:314
#define NT_ASSERT
Definition: rtlfuncs.h:3312
ULONG OutstandingAsyncWrites
Definition: fatstruc.h:736
VOID NTAPI CcSetReadAheadGranularity(IN PFILE_OBJECT FileObject, IN ULONG Granularity)
Definition: cachesub.c:36

◆ 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 );
3063  ExReleaseResourceLite( FcbOrDcb->Header.Resource );
3064 
3066 
3068 
3069  ExFreePool( Parameter );
3070 
3071 }
#define TRUE
Definition: types.h:120
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
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:931
Definition: cdstruc.h:908
Definition: cdstruc.h:1073
Definition: cdstruc.h:504
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
_In_ PVOID Parameter
Definition: ldrtypes.h:241
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
IN PFCB FcbOrDcb
Definition: fatprocs.h:306
_In_opt_ PVOID _In_ PCSTR File
Definition: iofuncs.h:615
smooth NULL
Definition: ftsmooth.c:416
File()
Definition: File.h:18
#define Vcb
Definition: cdprocs.h:1415
#define FSRTL_FSP_TOP_LEVEL_IRP
Definition: fsrtltypes.h:59
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
* PFILE_OBJECT
Definition: iotypes.h:1957
VOID NTAPI IoSetTopLevelIrp(IN PIRP Irp)
Definition: irp.c:2000
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:588
BOOLEAN NTAPI ExAcquireResourceSharedLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:885
ExFreePool(ed)
Definition: File.h:15
TYPE_OF_OPEN FatDecodeFileObject(_In_ PFILE_OBJECT FileObject, _Outptr_ PVCB *Vcb, _Outptr_ PFCB *FcbOrDcb, _Outptr_ PCCB *Ccb)
Definition: filobsup.c:176
DEFERRED_FLUSH_CONTEXT * PDEFERRED_FLUSH_CONTEXT
Definition: fatstruc.h:1685
#define PAGED_CODE()
#define NT_ASSERT
Definition: rtlfuncs.h:3312

◆ 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 
2993  FlushContext = (PDEFERRED_FLUSH_CONTEXT)DeferredContext;
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 }
VOID NTAPI ExQueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, IN WORK_QUEUE_TYPE QueueType)
Definition: work.c:717
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
WORK_QUEUE_ITEM Item
Definition: fatstruc.h:1679
WORKER_THREAD_ROUTINE FatDeferredFlush
Definition: write.c:63
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:675
_In_ LARGE_INTEGER _In_opt_ PKDPC Dpc
Definition: kefuncs.h:511
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:675
DEFERRED_FLUSH_CONTEXT * PDEFERRED_FLUSH_CONTEXT
Definition: fatstruc.h:1685
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675

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_().