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