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

3052 {
3053 
3055  PVCB Vcb;
3056  PFCB FcbOrDcb;
3057  PCCB Ccb;
3058 
3059  PAGED_CODE();
3060 
3062 
3064  NT_ASSERT( FcbOrDcb != NULL );
3065 
3066  //
3067  // Make us appear as a top level FSP request so that we will
3068  // receive any errors from the flush.
3069  //
3070 
3072 
3074  ExAcquireResourceSharedLite( FcbOrDcb->Header.PagingIoResource, TRUE );
3075 
3076  CcFlushCache( File->SectionObjectPointer, NULL, 0, NULL );
3077 
3078  ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
3079  ExReleaseResourceLite( FcbOrDcb->Header.Resource );
3080 
3082 
3084 
3085  ExFreePool( Parameter );
3086 
3087 }
#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
#define PAGED_CODE()
Definition: video.h:57
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
IN PFCB FcbOrDcb
Definition: fatprocs.h:297
_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:1425
#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:1955
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:593
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 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 2977 of file write.c.

3002 {
3003  PDEFERRED_FLUSH_CONTEXT FlushContext;
3004 
3008 
3009  FlushContext = (PDEFERRED_FLUSH_CONTEXT)DeferredContext;
3010 
3011  //
3012  // Send it off
3013  //
3014 
3015  ExInitializeWorkItem( &FlushContext->Item,
3017  FlushContext );
3018 
3019 #ifdef _MSC_VER
3020 #pragma prefast( suppress:28159, "prefast indicates this API is obsolete, but it's ok for fastfat to keep using it" )
3021 #endif
3022  ExQueueWorkItem( &FlushContext->Item, CriticalWorkQueue );
3023 }
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_().