3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the low lever disk read/write support for Fat.
19 // The Bug check file id for this module
22 #define BugCheckFileId (FAT_BUG_CHECK_DEVIOSUP)
25 // Local debug trace level
28 #define Dbg (DEBUG_TRACE_DEVIOSUP)
30 #define CollectDiskIoStats(VCB,FUNCTION,IS_USER_IO,COUNT) { \
31 PFILESYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors].Common; \
33 if ((FUNCTION) == IRP_MJ_WRITE) { \
34 Stats->UserDiskWrites += (COUNT); \
36 Stats->UserDiskReads += (COUNT); \
39 if ((FUNCTION) == IRP_MJ_WRITE) { \
40 Stats->MetaDataDiskWrites += (COUNT); \
42 Stats->MetaDataDiskReads += (COUNT); \
47 typedef struct _FAT_SYNC_CONTEXT
{
50 // Io status block for the request
56 // Event to be signaled when the request completes
61 } FAT_SYNC_CONTEXT
, *PFAT_SYNC_CONTEXT
;
65 // Completion Routine declarations
68 IO_COMPLETION_ROUTINE FatMultiSyncCompletionRoutine
;
72 FatMultiSyncCompletionRoutine (
73 _In_ PDEVICE_OBJECT DeviceObject
,
75 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
78 IO_COMPLETION_ROUTINE FatMultiAsyncCompletionRoutine
;
82 FatMultiAsyncCompletionRoutine (
83 _In_ PDEVICE_OBJECT DeviceObject
,
85 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
88 IO_COMPLETION_ROUTINE FatSpecialSyncCompletionRoutine
;
92 FatSpecialSyncCompletionRoutine (
93 _In_ PDEVICE_OBJECT DeviceObject
,
95 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
98 IO_COMPLETION_ROUTINE FatSingleSyncCompletionRoutine
;
102 FatSingleSyncCompletionRoutine (
103 _In_ PDEVICE_OBJECT DeviceObject
,
105 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
108 IO_COMPLETION_ROUTINE FatSingleAsyncCompletionRoutine
;
112 FatSingleAsyncCompletionRoutine (
113 _In_ PDEVICE_OBJECT DeviceObject
,
115 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
118 IO_COMPLETION_ROUTINE FatPagingFileCompletionRoutine
;
122 FatPagingFileCompletionRoutine (
123 _In_ PDEVICE_OBJECT DeviceObject
,
125 _In_reads_opt_(_Inexpressible_("varies")) PVOID MasterIrp
128 IO_COMPLETION_ROUTINE FatPagingFileCompletionRoutineCatch
;
132 FatPagingFileCompletionRoutineCatch (
133 _In_ PDEVICE_OBJECT DeviceObject
,
135 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
139 FatSingleNonAlignedSync (
140 IN PIRP_CONTEXT IrpContext
,
149 // The following macro decides whether to send a request directly to
150 // the device driver, or to other routines. It was meant to
151 // replace IoCallDriver as transparently as possible. It must only be
152 // called with a read or write Irp.
155 // FatLowLevelReadWrite (
156 // PIRP_CONTEXT IrpContext,
157 // PDEVICE_OBJECT DeviceObject,
163 #define FatLowLevelReadWrite(IRPCONTEXT,DO,IRP,VCB) ( \
164 IoCallDriver((DO),(IRP)) \
168 // The following macro handles completion-time zeroing of buffers.
171 #define FatDoCompletionZero( I, C ) \
172 if ((C)->ZeroMdl) { \
173 NT_ASSERT( (C)->ZeroMdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | \
174 MDL_SOURCE_IS_NONPAGED_POOL));\
175 if (NT_SUCCESS((I)->IoStatus.Status)) { \
176 RtlZeroMemory( (C)->ZeroMdl->MappedSystemVa, \
177 (C)->ZeroMdl->ByteCount ); \
179 IoFreeMdl((C)->ZeroMdl); \
180 (C)->ZeroMdl = NULL; \
183 #if (NTDDI_VERSION >= NTDDI_WIN8)
184 #define FatUpdateIOCountersPCW(IsAWrite,Count) \
185 FsRtlUpdateDiskCounters( ((IsAWrite) ? 0 : (Count) ), \
186 ((IsAWrite) ? (Count) : 0) )
188 #define FatUpdateIOCountersPCW(IsAWrite,Count)
192 #pragma alloc_text(PAGE, FatMultipleAsync)
193 #pragma alloc_text(PAGE, FatSingleAsync)
194 #pragma alloc_text(PAGE, FatSingleNonAlignedSync)
195 #pragma alloc_text(PAGE, FatWaitSync)
196 #pragma alloc_text(PAGE, FatLockUserBuffer)
197 #pragma alloc_text(PAGE, FatBufferUserBuffer)
198 #pragma alloc_text(PAGE, FatMapUserBuffer)
199 #pragma alloc_text(PAGE, FatNonCachedIo)
200 #pragma alloc_text(PAGE, FatNonCachedNonAlignedRead)
201 #pragma alloc_text(PAGE, FatPerformDevIoCtrl)
204 typedef struct FAT_PAGING_FILE_CONTEXT
{
207 } FAT_PAGING_FILE_CONTEXT
, *PFAT_PAGING_FILE_CONTEXT
;
220 This routine performs the non-cached disk io described in its parameters.
221 This routine nevers blocks, and should only be used with the paging
222 file since no completion processing is performed.
226 Irp - Supplies the requesting Irp.
228 Fcb - Supplies the file to act on.
238 // Declare some local variables for enumeration through the
249 ULONG RemainingByteCount
;
259 BOOLEAN MdlIsReserve
= FALSE
;
260 BOOLEAN IrpIsMaster
= FALSE
;
261 FAT_PAGING_FILE_CONTEXT Context
;
265 PIO_STACK_LOCATION IrpSp
;
266 PIO_STACK_LOCATION NextIrpSp
;
268 PDEVICE_OBJECT DeviceObject
;
271 BOOLEAN IsAWrite
= FALSE
;
274 DebugTrace(+1, Dbg
, "FatPagingFileIo\n", 0);
275 DebugTrace( 0, Dbg
, "Irp = %p\n", Irp
);
276 DebugTrace( 0, Dbg
, "Fcb = %p\n", Fcb
);
278 NT_ASSERT( FlagOn( Fcb
->FcbState
, FCB_STATE_PAGING_FILE
));
281 // Initialize some locals.
285 DeviceObject
= Fcb
->Vcb
->TargetDeviceObject
;
286 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
288 Vbo
= IrpSp
->Parameters
.Read
.ByteOffset
.LowPart
;
289 ByteCount
= IrpSp
->Parameters
.Read
.Length
;
291 IsAWrite
= (IrpSp
->MajorFunction
== IRP_MJ_WRITE
);
294 MustSucceed
= FatLookupMcbEntry( Fcb
->Vcb
, &Fcb
->Mcb
,
301 // If this run isn't present, something is very wrong.
307 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
309 FatBugCheck( Vbo
, ByteCount
, 0 );
312 #if (NTDDI_VERSION >= NTDDI_WIN8)
315 // Charge the IO to paging file to current thread
318 if (FatDiskAccountingEnabled
) {
320 PETHREAD ThreadIssuingIo
= PsGetCurrentThread();
321 BOOLEAN IsWriteOperation
= FALSE
;
323 if (IrpSp
->MajorFunction
== IRP_MJ_WRITE
) {
324 IsWriteOperation
= TRUE
;
327 PsUpdateDiskCounters( PsGetThreadProcess( ThreadIssuingIo
),
328 (IsWriteOperation
? 0 : ByteCount
), // bytes to read
329 (IsWriteOperation
? ByteCount
: 0), // bytes to write
330 (IsWriteOperation
? 0 : 1), // # of reads
331 (IsWriteOperation
? 1 : 0), // # of writes
336 // See if the write covers a single valid run, and if so pass
340 if ( NextByteCount
>= ByteCount
) {
342 DebugTrace( 0, Dbg
, "Passing Irp on to Disk Driver\n", 0 );
345 // Setup the next IRP stack location for the disk driver beneath us.
348 NextIrpSp
= IoGetNextIrpStackLocation( Irp
);
350 NextIrpSp
->MajorFunction
= IrpSp
->MajorFunction
;
351 NextIrpSp
->Parameters
.Read
.Length
= ByteCount
;
352 NextIrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= NextLbo
;
355 // Since this is Paging file IO, we'll just ignore the verify bit.
358 SetFlag( NextIrpSp
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
361 // Set up the completion routine address in our stack frame.
362 // This is only invoked on error or cancel, and just copies
363 // the error Status into master irp's iosb.
365 // If the error implies a media problem, it also enqueues a
366 // worker item to write out the dirty bit so that the next
367 // time we run we will do a autochk /r
370 IoSetCompletionRoutine( Irp
,
371 &FatPagingFileCompletionRoutine
,
378 // Issue the read/write request
380 // If IoCallDriver returns an error, it has completed the Irp
381 // and the error will be dealt with as a normal IO error.
384 (VOID
)IoCallDriver( DeviceObject
, Irp
);
387 // We just issued an IO to the storage stack, update the counters indicating so.
390 if (FatDiskAccountingEnabled
) {
392 FatUpdateIOCountersPCW( IsAWrite
, ByteCount
);
395 DebugTrace(-1, Dbg
, "FatPagingFileIo -> VOID\n", 0);
400 // Find out how may runs there are.
403 MustSucceed
= FatLookupMcbEntry( Fcb
->Vcb
, &Fcb
->Mcb
,
410 // If this run isn't present, something is very wrong.
416 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
418 FatBugCheck( Vbo
+ ByteCount
- 1, 1, 0 );
421 CurrentIndex
= FirstIndex
;
424 // Now set up the Irp->IoStatus. It will be modified by the
425 // multi-completion routine in case of error or verify required.
428 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
429 Irp
->IoStatus
.Information
= ByteCount
;
432 // Loop while there are still byte writes to satisfy. The way we'll work this
433 // is to hope for the best - one associated IRP per run, which will let us be
434 // completely async after launching all the IO.
436 // IrpCount will indicate the remaining number of associated Irps to launch.
438 // All we have to do is make sure IrpCount doesn't hit zero before we're building
439 // the very last Irp. If it is positive when we're done, it means we have to
440 // wait for the rest of the associated Irps to come back before we complete the
443 // This will keep the master from completing early.
446 Irp
->AssociatedIrp
.IrpCount
= IrpCount
= LastIndex
- FirstIndex
+ 1;
448 while (CurrentIndex
<= LastIndex
) {
451 // Reset this for unwinding purposes
457 // If next run is larger than we need, "ya get what ya need".
460 if (NextByteCount
> ByteCount
) {
461 NextByteCount
= ByteCount
;
464 RemainingByteCount
= 0;
467 // Allocate and build a partial Mdl for the request.
470 Mdl
= IoAllocateMdl( (PCHAR
)Irp
->UserBuffer
+ BufferOffset
,
479 // Pick up the reserve MDL
482 KeWaitForSingleObject( &FatReserveEvent
, Executive
, KernelMode
, FALSE
, NULL
);
488 // Trim to fit the size of the reserve MDL.
491 if (NextByteCount
> FAT_RESERVE_MDL_SIZE
* PAGE_SIZE
) {
493 RemainingByteCount
= NextByteCount
- FAT_RESERVE_MDL_SIZE
* PAGE_SIZE
;
494 NextByteCount
= FAT_RESERVE_MDL_SIZE
* PAGE_SIZE
;
498 IoBuildPartialMdl( Irp
->MdlAddress
,
500 (PCHAR
)Irp
->UserBuffer
+ BufferOffset
,
504 // Now that we have properly bounded this piece of the transfer, it is
505 // time to read/write it. We can simplify life slightly by always
506 // re-using the master IRP for cases where we use the reserve MDL,
507 // since we'll always be synchronous for those and can use a single
508 // completion context on our local stack.
510 // We also must prevent ourselves from issuing an associated IRP that would
511 // complete the master UNLESS this is the very last IRP we'll issue.
513 // This logic looks a bit complicated, but is hopefully understandable.
518 (CurrentIndex
== LastIndex
&&
519 RemainingByteCount
== 0))) {
521 AssocIrp
= IoMakeAssociatedIrp( Irp
, (CCHAR
)(DeviceObject
->StackSize
+ 1) );
524 if (AssocIrp
== NULL
) {
530 // We need to drain the associated Irps so we can reliably figure out if
531 // the master Irp is showing a failed status, in which case we bail out
532 // immediately - as opposed to putting the value in the status field in
533 // jeopardy due to our re-use of the master Irp.
536 while (Irp
->AssociatedIrp
.IrpCount
!= IrpCount
) {
538 KeDelayExecutionThread (KernelMode
, FALSE
, &Fat30Milliseconds
);
542 // Note that since we failed to launch this associated Irp, that the completion
543 // code at the bottom will take care of completing the master Irp.
546 if (!NT_SUCCESS(Irp
->IoStatus
.Status
)) {
548 NT_ASSERT( IrpCount
);
555 // Indicate we used an associated Irp.
562 // With an associated IRP, we must take over the first stack location so
563 // we can have one to put the completion routine on. When re-using the
564 // master IRP, its already there.
570 // Get the first IRP stack location in the associated Irp
573 IoSetNextIrpStackLocation( AssocIrp
);
574 NextIrpSp
= IoGetCurrentIrpStackLocation( AssocIrp
);
577 // Setup the Stack location to describe our read.
580 NextIrpSp
->MajorFunction
= IrpSp
->MajorFunction
;
581 NextIrpSp
->Parameters
.Read
.Length
= NextByteCount
;
582 NextIrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= Vbo
;
585 // We also need the VolumeDeviceObject in the Irp stack in case
586 // we take the failure path.
589 NextIrpSp
->DeviceObject
= IrpSp
->DeviceObject
;
594 // Save the MDL in the IRP and prepare the stack
595 // context for the completion routine.
598 KeInitializeEvent( &Context
.Event
, SynchronizationEvent
, FALSE
);
599 Context
.RestoreMdl
= Irp
->MdlAddress
;
603 // And drop our Mdl into the Irp.
606 AssocIrp
->MdlAddress
= Mdl
;
609 // Set up the completion routine address in our stack frame.
610 // For true associated IRPs, this is only invoked on error or
611 // cancel, and just copies the error Status into master irp's
614 // If the error implies a media problem, it also enqueues a
615 // worker item to write out the dirty bit so that the next
616 // time we run we will do a autochk /r
621 IoSetCompletionRoutine( AssocIrp
,
622 FatPagingFileCompletionRoutineCatch
,
630 IoSetCompletionRoutine( AssocIrp
,
631 FatPagingFileCompletionRoutine
,
639 // Setup the next IRP stack location for the disk driver beneath us.
642 NextIrpSp
= IoGetNextIrpStackLocation( AssocIrp
);
645 // Since this is paging file IO, we'll just ignore the verify bit.
648 SetFlag( NextIrpSp
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
651 // Setup the Stack location to do a read from the disk driver.
654 NextIrpSp
->MajorFunction
= IrpSp
->MajorFunction
;
655 NextIrpSp
->Parameters
.Read
.Length
= NextByteCount
;
656 NextIrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= NextLbo
;
658 (VOID
)IoCallDriver( DeviceObject
, AssocIrp
);
661 // We just issued an IO to the storage stack, update the counters indicating so.
664 if (FatDiskAccountingEnabled
) {
666 FatUpdateIOCountersPCW( IsAWrite
, (ULONG64
)NextByteCount
);
670 // Wait for the Irp in the catch case and drop the flags.
675 KeWaitForSingleObject( &Context
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
676 IrpIsMaster
= MdlIsReserve
= FALSE
;
679 // If the Irp is showing a failed status, there is no point in continuing.
680 // In doing so, we get to avoid squirreling away the failed status in case
681 // we were to re-use the master irp again.
683 // Note that since we re-used the master, we must not have issued the "last"
684 // associated Irp, and thus the completion code at the bottom will take care
688 if (!NT_SUCCESS(Irp
->IoStatus
.Status
)) {
690 NT_ASSERT( IrpCount
);
696 // Now adjust everything for the next pass through the loop.
699 Vbo
+= NextByteCount
;
700 BufferOffset
+= NextByteCount
;
701 ByteCount
-= NextByteCount
;
704 // Try to lookup the next run, if we are not done and we got
705 // all the way through the current run.
708 if (RemainingByteCount
) {
711 // Advance the Lbo/Vbo if we have more to do in the current run.
714 NextLbo
+= NextByteCount
;
715 NextVbo
+= NextByteCount
;
717 NextByteCount
= RemainingByteCount
;
723 if ( CurrentIndex
<= LastIndex
) {
725 NT_ASSERT( ByteCount
!= 0 );
727 FatGetNextMcbEntry( Fcb
->Vcb
, &Fcb
->Mcb
,
733 NT_ASSERT( NextVbo
== Vbo
);
736 } // while ( CurrentIndex <= LastIndex )
739 // If we didn't get enough associated Irps going to make this asynchronous, we
740 // twiddle our thumbs and wait for those we did launch to complete.
745 while (Irp
->AssociatedIrp
.IrpCount
!= IrpCount
) {
747 KeDelayExecutionThread (KernelMode
, FALSE
, &Fat30Milliseconds
);
750 IoCompleteRequest( Irp
, IO_DISK_INCREMENT
);
753 DebugTrace(-1, Dbg
, "FatPagingFileIo -> VOID\n", 0);
757 #if (NTDDI_VERSION >= NTDDI_WIN8)
761 IN PIRP_CONTEXT IrpContext
,
769 Charge appropriate process for the IO this IRP will cause.
773 IrpContext- The Irp Context
775 Irp - Supplies the requesting Irp.
777 ByteCount - The lengh of the operation.
786 PETHREAD OriginatingThread
= NULL
;
789 ULONGLONG BytesToRead
= 0;
790 ULONGLONG BytesToWrite
= 0;
793 // Here we attempt to charge the IO back to the originating process.
794 // - These checks are intended to cover following cases:
795 // o Buffered sync reads
796 // o Unbuffered sync read
797 // o Inline metadata reads
798 // o memory mapped reads (in-line faulting of data)
801 if (IrpContext
->MajorFunction
== IRP_MJ_READ
) {
804 BytesToRead
= ByteCount
;
806 if ((Irp
->Tail
.Overlay
.Thread
!= NULL
) &&
807 !IoIsSystemThread( Irp
->Tail
.Overlay
.Thread
)) {
809 OriginatingThread
= Irp
->Tail
.Overlay
.Thread
;
811 } else if (!IoIsSystemThread( PsGetCurrentThread() )) {
813 OriginatingThread
= PsGetCurrentThread();
816 // We couldn't find a non-system entity, so this should be charged to system.
817 // Do so only if we are top level.
818 // If we are not top-level then the read was initiated by someone like Cc (read ahead)
819 // who should have already accounted for this IO.
822 } else if (IoIsSystemThread( PsGetCurrentThread() ) &&
823 (IoGetTopLevelIrp() == Irp
)) {
825 OriginatingThread
= PsGetCurrentThread();
829 // Charge the write to Originating process.
830 // Intended to cover the following writes:
831 // - Unbuffered sync write
832 // - unbuffered async write
834 // If we re not top-level, then it should already have been accounted for
835 // somewhere else (Cc).
838 } else if (IrpContext
->MajorFunction
== IRP_MJ_WRITE
) {
841 BytesToWrite
= ByteCount
;
843 if (IoGetTopLevelIrp() == Irp
) {
845 if ((Irp
->Tail
.Overlay
.Thread
!= NULL
) &&
846 !IoIsSystemThread( Irp
->Tail
.Overlay
.Thread
)) {
848 OriginatingThread
= Irp
->Tail
.Overlay
.Thread
;
852 OriginatingThread
= PsGetCurrentThread();
856 // For mapped page writes
859 } else if (IoGetTopLevelIrp() == (PIRP
)FSRTL_MOD_WRITE_TOP_LEVEL_IRP
) {
861 OriginatingThread
= PsGetCurrentThread();
865 if (OriginatingThread
!= NULL
) {
867 PsUpdateDiskCounters( PsGetThreadProcess( OriginatingThread
),
880 _Requires_lock_held_(_Global_critical_region_
)
883 IN PIRP_CONTEXT IrpContext
,
886 IN ULONG StartingVbo
,
888 IN ULONG UserByteCount
,
895 This routine performs the non-cached disk io described in its parameters.
896 The choice of a single run is made if possible, otherwise multiple runs
901 IrpContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
903 Irp - Supplies the requesting Irp.
905 FcbOrDcb - Supplies the file to act on.
907 StartingVbo - The starting point for the operation.
909 ByteCount - The lengh of the operation.
911 UserByteCount - The last byte the user can see, rest to be zeroed.
913 StreamFlags - flag to indicate special attributes for a NonCachedIo.
924 // Declare some local variables for enumeration through the
925 // runs of the file, and an array to store parameters for
934 BOOLEAN NextIsAllocated
;
938 BOOLEAN LastIsAllocated
;
948 ULONG OriginalByteCount
;
952 IO_RUN StackIoRuns
[FAT_MAX_IO_RUNS_ON_STACK
];
958 UNREFERENCED_PARAMETER( StreamFlags
);
960 DebugTrace(+1, Dbg
, "FatNonCachedIo\n", 0);
961 DebugTrace( 0, Dbg
, "Irp = %p\n", Irp
);
962 DebugTrace( 0, Dbg
, "MajorFunction = %08lx\n", IrpContext
->MajorFunction
);
963 DebugTrace( 0, Dbg
, "FcbOrDcb = %p\n", FcbOrDcb
);
964 DebugTrace( 0, Dbg
, "StartingVbo = %08lx\n", StartingVbo
);
965 DebugTrace( 0, Dbg
, "ByteCount = %08lx\n", ByteCount
);
967 if (!FlagOn(Irp
->Flags
, IRP_PAGING_IO
)) {
969 PFILE_SYSTEM_STATISTICS Stats
=
970 &FcbOrDcb
->Vcb
->Statistics
[KeGetCurrentProcessorNumber() % FatData
.NumberProcessors
];
972 if (IrpContext
->MajorFunction
== IRP_MJ_READ
) {
973 Stats
->Fat
.NonCachedReads
+= 1;
974 Stats
->Fat
.NonCachedReadBytes
+= ByteCount
;
976 Stats
->Fat
.NonCachedWrites
+= 1;
977 Stats
->Fat
.NonCachedWriteBytes
+= ByteCount
;
982 // Initialize some locals.
987 OriginalByteCount
= ByteCount
;
989 Wait
= BooleanFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
991 #if (NTDDI_VERSION >= NTDDI_WIN8)
994 // Disk IO accounting
997 if (FatDiskAccountingEnabled
) {
999 FatUpdateDiskStats( IrpContext
,
1006 // For nonbuffered I/O, we need the buffer locked in all
1009 // This call may raise. If this call succeeds and a subsequent
1010 // condition is raised, the buffers are unlocked automatically
1011 // by the I/O system when the request is completed, via the
1012 // Irp->MdlAddress field.
1015 FatLockUserBuffer( IrpContext
,
1017 (IrpContext
->MajorFunction
== IRP_MJ_READ
) ?
1018 IoWriteAccess
: IoReadAccess
,
1024 // No zeroing for trailing sectors if requested.
1025 // Otherwise setup the required zeroing for read requests.
1029 if (UserByteCount
!= ByteCount
) {
1034 NT_ASSERT( ByteCount
> UserByteCount
);
1035 _Analysis_assume_(ByteCount
> UserByteCount
);
1037 Mdl
= IoAllocateMdl( (PUCHAR
) Irp
->UserBuffer
+ UserByteCount
,
1038 ByteCount
- UserByteCount
,
1045 FatRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1048 IoBuildPartialMdl( Irp
->MdlAddress
,
1050 (PUCHAR
) Irp
->UserBuffer
+ UserByteCount
,
1051 ByteCount
- UserByteCount
);
1053 IrpContext
->FatIoContext
->ZeroMdl
= Mdl
;
1056 // Map the MDL now so we can't fail at IO completion time. Note
1057 // that this will be only a single page.
1061 if (MmGetSystemAddressForMdlSafe( Mdl
, NormalPagePriority
| MdlMappingNoExecute
) == NULL
) {
1063 if (MmGetSystemAddressForMdlSafe( Mdl
, NormalPagePriority
) == NULL
) {
1066 FatRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1072 // Try to lookup the first run. If there is just a single run,
1073 // we may just be able to pass it on.
1076 FatLookupFileAllocation( IrpContext
,
1086 // We just added the allocation, thus there must be at least
1087 // one entry in the mcb corresponding to our write, ie.
1088 // NextIsAllocated must be true. If not, the pre-existing file
1089 // must have an allocation error.
1092 if ( !NextIsAllocated
) {
1094 FatPopUpFileCorrupt( IrpContext
, FcbOrDcb
);
1096 FatRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
1099 NT_ASSERT( NextByteCount
!= 0 );
1102 // If the request was not aligned correctly, read in the first
1108 // See if the write covers a single valid run, and if so pass
1109 // it on. We must bias this by the byte that is lost at the
1110 // end of the maximal file.
1113 if ( NextByteCount
>= ByteCount
- (EndOnMax
? 1 : 0)) {
1115 if (FlagOn(Irp
->Flags
, IRP_PAGING_IO
)) {
1116 CollectDiskIoStats(FcbOrDcb
->Vcb
, IrpContext
->MajorFunction
,
1117 FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_USER_IO
), 1);
1120 PFILE_SYSTEM_STATISTICS Stats
=
1121 &FcbOrDcb
->Vcb
->Statistics
[KeGetCurrentProcessorNumber() % FatData
.NumberProcessors
];
1123 if (IrpContext
->MajorFunction
== IRP_MJ_READ
) {
1124 Stats
->Fat
.NonCachedDiskReads
+= 1;
1126 Stats
->Fat
.NonCachedDiskWrites
+= 1;
1130 DebugTrace( 0, Dbg
, "Passing 1 Irp on to Disk Driver\n", 0 );
1132 FatSingleAsync( IrpContext
,
1141 // If there we can't wait, and there are more runs than we can handle,
1142 // we will have to post this request.
1145 FatLookupFileAllocation( IrpContext
,
1147 StartingVbo
+ ByteCount
- 1,
1155 // Since we already added the allocation for the whole
1156 // write, assert that we find runs until ByteCount == 0
1157 // Otherwise this file is corrupt.
1160 if ( !LastIsAllocated
) {
1162 FatPopUpFileCorrupt( IrpContext
, FcbOrDcb
);
1164 FatRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
1167 if (LastIndex
- FirstIndex
+ 1 > FAT_MAX_IO_RUNS_ON_STACK
) {
1169 IoRuns
= FsRtlAllocatePoolWithTag( PagedPool
,
1170 (LastIndex
- FirstIndex
+ 1) * sizeof(IO_RUN
),
1175 IoRuns
= StackIoRuns
;
1178 NT_ASSERT( LastIndex
!= FirstIndex
);
1180 CurrentIndex
= FirstIndex
;
1183 // Loop while there are still byte writes to satisfy.
1186 while (CurrentIndex
<= LastIndex
) {
1189 NT_ASSERT( NextByteCount
!= 0);
1190 NT_ASSERT( ByteCount
!= 0);
1193 // If next run is larger than we need, "ya get what you need".
1196 if (NextByteCount
> ByteCount
) {
1197 NextByteCount
= ByteCount
;
1201 // Now that we have properly bounded this piece of the
1202 // transfer, it is time to write it.
1204 // We remember each piece of a parallel run by saving the
1205 // essential information in the IoRuns array. The tranfers
1206 // are started up in parallel below.
1209 IoRuns
[NextRun
].Vbo
= StartingVbo
;
1210 IoRuns
[NextRun
].Lbo
= NextLbo
;
1211 IoRuns
[NextRun
].Offset
= BufferOffset
;
1212 IoRuns
[NextRun
].ByteCount
= NextByteCount
;
1216 // Now adjust everything for the next pass through the loop.
1219 StartingVbo
+= NextByteCount
;
1220 BufferOffset
+= NextByteCount
;
1221 ByteCount
-= NextByteCount
;
1224 // Try to lookup the next run (if we are not done).
1229 if ( CurrentIndex
<= LastIndex
) {
1231 NT_ASSERT( ByteCount
!= 0 );
1233 FatGetNextMcbEntry( FcbOrDcb
->Vcb
, &FcbOrDcb
->Mcb
,
1240 NT_ASSERT(NextVbo
== StartingVbo
);
1245 } // while ( CurrentIndex <= LastIndex )
1248 // Now set up the Irp->IoStatus. It will be modified by the
1249 // multi-completion routine in case of error or verify required.
1252 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1253 Irp
->IoStatus
.Information
= OriginalByteCount
;
1255 if (FlagOn(Irp
->Flags
, IRP_PAGING_IO
)) {
1256 CollectDiskIoStats(FcbOrDcb
->Vcb
, IrpContext
->MajorFunction
,
1257 FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_USER_IO
), NextRun
);
1261 // OK, now do the I/O.
1266 DebugTrace( 0, Dbg
, "Passing Multiple Irps on to Disk Driver\n", 0 );
1268 FatMultipleAsync( IrpContext
,
1276 if (IoRuns
!= StackIoRuns
) {
1278 ExFreePool( IoRuns
);
1285 DebugTrace(-1, Dbg
, "FatNonCachedIo -> STATUS_PENDING\n", 0);
1286 return STATUS_PENDING
;
1289 FatWaitSync( IrpContext
);
1292 DebugTrace(-1, Dbg
, "FatNonCachedIo -> 0x%08lx\n", Irp
->IoStatus
.Status
);
1293 return Irp
->IoStatus
.Status
;
1297 _Requires_lock_held_(_Global_critical_region_
)
1299 FatNonCachedNonAlignedRead (
1300 IN PIRP_CONTEXT IrpContext
,
1303 IN ULONG StartingVbo
,
1309 Routine Description:
1311 This routine performs the non-cached disk io described in its parameters.
1312 This routine differs from the above in that the range does not have to be
1313 sector aligned. This accomplished with the use of intermediate buffers.
1317 IrpContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
1319 Irp - Supplies the requesting Irp.
1321 FcbOrDcb - Supplies the file to act on.
1323 StartingVbo - The starting point for the operation.
1325 ByteCount - The lengh of the operation.
1335 // Declare some local variables for enumeration through the
1336 // runs of the file, and an array to store parameters for
1341 ULONG NextByteCount
;
1342 BOOLEAN NextIsAllocated
;
1346 ULONG OriginalByteCount
;
1347 ULONG OriginalStartingVbo
;
1352 PUCHAR DiskBuffer
= NULL
;
1356 PVOID SavedUserBuffer
;
1360 DebugTrace(+1, Dbg
, "FatNonCachedNonAlignedRead\n", 0);
1361 DebugTrace( 0, Dbg
, "Irp = %p\n", Irp
);
1362 DebugTrace( 0, Dbg
, "MajorFunction = %08lx\n", IrpContext
->MajorFunction
);
1363 DebugTrace( 0, Dbg
, "FcbOrDcb = %p\n", FcbOrDcb
);
1364 DebugTrace( 0, Dbg
, "StartingVbo = %08lx\n", StartingVbo
);
1365 DebugTrace( 0, Dbg
, "ByteCount = %08lx\n", ByteCount
);
1368 // Initialize some locals.
1371 OriginalByteCount
= ByteCount
;
1372 OriginalStartingVbo
= StartingVbo
;
1373 SectorSize
= FcbOrDcb
->Vcb
->Bpb
.BytesPerSector
;
1375 NT_ASSERT( FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) );
1378 // For nonbuffered I/O, we need the buffer locked in all
1381 // This call may raise. If this call succeeds and a subsequent
1382 // condition is raised, the buffers are unlocked automatically
1383 // by the I/O system when the request is completed, via the
1384 // Irp->MdlAddress field.
1387 FatLockUserBuffer( IrpContext
,
1392 UserBuffer
= FatMapUserBuffer( IrpContext
, Irp
);
1395 // Allocate the local buffer
1399 DiskBuffer
= FsRtlAllocatePoolWithTag( NonPagedPoolNxCacheAligned
,
1401 DiskBuffer
= FsRtlAllocatePoolWithTag( NonPagedPoolCacheAligned
,
1403 (ULONG
) ROUND_TO_PAGES( SectorSize
),
1407 // We use a try block here to ensure the buffer is freed, and to
1408 // fill in the correct byte count in the Iosb.Information field.
1414 // If the beginning of the request was not aligned correctly, read in
1415 // the first part first.
1418 if ( StartingVbo
& (SectorSize
- 1) ) {
1423 // Try to lookup the first run.
1426 FatLookupFileAllocation( IrpContext
,
1436 // We just added the allocation, thus there must be at least
1437 // one entry in the mcb corresponding to our write, ie.
1438 // NextIsAllocated must be true. If not, the pre-existing file
1439 // must have an allocation error.
1442 if ( !NextIsAllocated
) {
1444 FatPopUpFileCorrupt( IrpContext
, FcbOrDcb
);
1446 FatRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
1449 FatSingleNonAlignedSync( IrpContext
,
1452 NextLbo
& ~((LONG
)SectorSize
- 1),
1456 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
1458 try_return( NOTHING
);
1462 // Now copy the part of the first sector that we want to the user
1466 Hole
= StartingVbo
& (SectorSize
- 1);
1468 BytesToCopy
= ByteCount
>= SectorSize
- Hole
?
1469 SectorSize
- Hole
: ByteCount
;
1471 RtlCopyMemory( UserBuffer
, DiskBuffer
+ Hole
, BytesToCopy
);
1473 StartingVbo
+= BytesToCopy
;
1474 ByteCount
-= BytesToCopy
;
1476 if ( ByteCount
== 0 ) {
1478 try_return( NOTHING
);
1482 NT_ASSERT( (StartingVbo
& (SectorSize
- 1)) == 0 );
1485 // If there is a tail part that is not sector aligned, read it.
1488 if ( ByteCount
& (SectorSize
- 1) ) {
1492 LastSectorVbo
= StartingVbo
+ (ByteCount
& ~(SectorSize
- 1));
1495 // Try to lookup the last part of the requested range.
1498 FatLookupFileAllocation( IrpContext
,
1508 // We just added the allocation, thus there must be at least
1509 // one entry in the mcb corresponding to our write, ie.
1510 // NextIsAllocated must be true. If not, the pre-existing file
1511 // must have an allocation error.
1514 if ( !NextIsAllocated
) {
1516 FatPopUpFileCorrupt( IrpContext
, FcbOrDcb
);
1518 FatRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
1521 FatSingleNonAlignedSync( IrpContext
,
1528 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
1530 try_return( NOTHING
);
1534 // Now copy over the part of this last sector that we need.
1537 BytesToCopy
= ByteCount
& (SectorSize
- 1);
1539 UserBuffer
+= LastSectorVbo
- OriginalStartingVbo
;
1541 RtlCopyMemory( UserBuffer
, DiskBuffer
, BytesToCopy
);
1543 ByteCount
-= BytesToCopy
;
1545 if ( ByteCount
== 0 ) {
1547 try_return( NOTHING
);
1551 NT_ASSERT( ((StartingVbo
| ByteCount
) & (SectorSize
- 1)) == 0 );
1554 // Now build a Mdl describing the sector aligned balance of the transfer,
1555 // and put it in the Irp, and read that part.
1558 SavedMdl
= Irp
->MdlAddress
;
1559 Irp
->MdlAddress
= NULL
;
1561 SavedUserBuffer
= Irp
->UserBuffer
;
1563 Irp
->UserBuffer
= (PUCHAR
)MmGetMdlVirtualAddress( SavedMdl
) +
1564 (StartingVbo
- OriginalStartingVbo
);
1566 Mdl
= IoAllocateMdl( Irp
->UserBuffer
,
1574 Irp
->MdlAddress
= SavedMdl
;
1575 Irp
->UserBuffer
= SavedUserBuffer
;
1576 FatRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1579 IoBuildPartialMdl( SavedMdl
,
1585 // Try to read in the pages.
1590 FatNonCachedIo( IrpContext
,
1600 IoFreeMdl( Irp
->MdlAddress
);
1602 Irp
->MdlAddress
= SavedMdl
;
1603 Irp
->UserBuffer
= SavedUserBuffer
;
1610 ExFreePool( DiskBuffer
);
1612 if ( !_SEH2_AbnormalTermination() && NT_SUCCESS(Irp
->IoStatus
.Status
) ) {
1614 Irp
->IoStatus
.Information
= OriginalByteCount
;
1617 // We now flush the user's buffer to memory.
1620 KeFlushIoBuffers( Irp
->MdlAddress
, TRUE
, FALSE
);
1624 DebugTrace(-1, Dbg
, "FatNonCachedNonAlignedRead -> VOID\n", 0);
1631 IN PIRP_CONTEXT IrpContext
,
1634 IN ULONG MultipleIrpCount
,
1640 Routine Description:
1642 This routine first does the initial setup required of a Master IRP that is
1643 going to be completed using associated IRPs. This routine should not
1644 be used if only one async request is needed, instead the single read/write
1645 async routines should be called.
1647 A context parameter is initialized, to serve as a communications area
1648 between here and the common completion routine. This initialization
1649 includes allocation of a spinlock. The spinlock is deallocated in the
1650 FatWaitSync routine, so it is essential that the caller insure that
1651 this routine is always called under all circumstances following a call
1654 Next this routine reads or writes one or more contiguous sectors from
1655 a device asynchronously, and is used if there are multiple reads for a
1656 master IRP. A completion routine is used to synchronize with the
1657 completion of all of the I/O requests started by calls to this routine.
1659 Also, prior to calling this routine the caller must initialize the
1660 IoStatus field in the Context, with the correct success status and byte
1661 count which are expected if all of the parallel transfers complete
1662 successfully. After return this status will be unchanged if all requests
1663 were, in fact, successful. However, if one or more errors occur, the
1664 IoStatus will be modified to reflect the error status and byte count
1665 from the first run (by Vbo) which encountered an error. I/O status
1666 from all subsequent runs will not be indicated.
1670 IrpContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
1672 Vcb - Supplies the device to be read
1674 MasterIrp - Supplies the master Irp.
1676 MulitpleIrpCount - Supplies the number of multiple async requests
1677 that will be issued against the master irp.
1679 IoRuns - Supplies an array containing the Vbo, Lbo, BufferOffset, and
1680 ByteCount for all the runs to executed in parallel.
1690 PIO_STACK_LOCATION IrpSp
;
1693 PFAT_IO_CONTEXT Context
;
1695 BOOLEAN IsAWrite
= FALSE
;
1699 ULONG UnwindRunCount
= 0;
1701 BOOLEAN ExceptionExpected
= TRUE
;
1705 DebugTrace(+1, Dbg
, "FatMultipleAsync\n", 0);
1706 DebugTrace( 0, Dbg
, "MajorFunction = %08lx\n", IrpContext
->MajorFunction
);
1707 DebugTrace( 0, Dbg
, "Vcb = %p\n", Vcb
);
1708 DebugTrace( 0, Dbg
, "MasterIrp = %p\n", MasterIrp
);
1709 DebugTrace( 0, Dbg
, "MultipleIrpCount = %08lx\n", MultipleIrpCount
);
1710 DebugTrace( 0, Dbg
, "IoRuns = %08lx\n", IoRuns
);
1713 // If this I/O originating during FatVerifyVolume, bypass the
1717 if (Vcb
->VerifyThread
== KeGetCurrentThread()) {
1719 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY
);
1723 // Set up things according to whether this is truely async.
1726 Wait
= BooleanFlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1728 Context
= IrpContext
->FatIoContext
;
1731 // Finish initializing Context, for use in Read/Write Multiple Asynch.
1734 Context
->MasterIrp
= MasterIrp
;
1736 IrpSp
= IoGetCurrentIrpStackLocation( MasterIrp
);
1738 IsAWrite
= (IrpSp
->MajorFunction
== IRP_MJ_WRITE
);
1739 Length
= IrpSp
->Parameters
.Read
.Length
;
1745 // Itterate through the runs, doing everything that can fail
1748 for ( UnwindRunCount
= 0;
1749 UnwindRunCount
< MultipleIrpCount
;
1750 UnwindRunCount
++ ) {
1753 // Create an associated IRP, making sure there is one stack entry for
1757 IoRuns
[UnwindRunCount
].SavedIrp
= 0;
1759 Irp
= IoMakeAssociatedIrp( MasterIrp
,
1760 (CCHAR
)(Vcb
->TargetDeviceObject
->StackSize
+ 1) );
1764 FatRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1767 IoRuns
[UnwindRunCount
].SavedIrp
= Irp
;
1770 // Allocate and build a partial Mdl for the request.
1773 Mdl
= IoAllocateMdl( (PCHAR
)MasterIrp
->UserBuffer
+
1774 IoRuns
[UnwindRunCount
].Offset
,
1775 IoRuns
[UnwindRunCount
].ByteCount
,
1782 FatRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1789 NT_ASSERT( Mdl
== Irp
->MdlAddress
);
1791 IoBuildPartialMdl( MasterIrp
->MdlAddress
,
1793 (PCHAR
)MasterIrp
->UserBuffer
+
1794 IoRuns
[UnwindRunCount
].Offset
,
1795 IoRuns
[UnwindRunCount
].ByteCount
);
1798 // Get the first IRP stack location in the associated Irp
1801 IoSetNextIrpStackLocation( Irp
);
1802 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1805 // Setup the Stack location to describe our read.
1808 IrpSp
->MajorFunction
= IrpContext
->MajorFunction
;
1809 IrpSp
->Parameters
.Read
.Length
= IoRuns
[UnwindRunCount
].ByteCount
;
1810 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= IoRuns
[UnwindRunCount
].Vbo
;
1813 // Set up the completion routine address in our stack frame.
1816 IoSetCompletionRoutine( Irp
,
1818 &FatMultiSyncCompletionRoutine
:
1819 &FatMultiAsyncCompletionRoutine
,
1826 // Setup the next IRP stack location in the associated Irp for the disk
1827 // driver beneath us.
1830 IrpSp
= IoGetNextIrpStackLocation( Irp
);
1833 // Setup the Stack location to do a read from the disk driver.
1836 IrpSp
->MajorFunction
= IrpContext
->MajorFunction
;
1837 IrpSp
->Parameters
.Read
.Length
= IoRuns
[UnwindRunCount
].ByteCount
;
1838 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= IoRuns
[UnwindRunCount
].Lbo
;
1841 // If this Irp is the result of a WriteThough operation,
1842 // tell the device to write it through.
1845 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
)) {
1847 SetFlag( IrpSp
->Flags
, SL_WRITE_THROUGH
);
1851 // If this I/O requires override verify, bypass the verify logic.
1854 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY
)) {
1856 SetFlag( IrpSp
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
1861 // Now we no longer expect an exception. If the driver raises, we
1862 // must bugcheck, because we do not know how to recover from that
1866 ExceptionExpected
= FALSE
;
1869 // We only need to set the associated IRP count in the master irp to
1870 // make it a master IRP. But we set the count to one more than our
1871 // caller requested, because we do not want the I/O system to complete
1872 // the I/O. We also set our own count.
1875 Context
->IrpCount
= MultipleIrpCount
;
1876 MasterIrp
->AssociatedIrp
.IrpCount
= MultipleIrpCount
;
1880 MasterIrp
->AssociatedIrp
.IrpCount
+= 1;
1882 else if (FlagOn( Context
->Wait
.Async
.ResourceThreadId
, 3 )) {
1885 // For async requests if we acquired locks, transition the lock owners to an
1886 // object, since when we return this thread could go away before request
1887 // completion, and the resource package may try to boost priority.
1890 if (Context
->Wait
.Async
.Resource
!= NULL
) {
1892 ExSetResourceOwnerPointer( Context
->Wait
.Async
.Resource
,
1893 (PVOID
)Context
->Wait
.Async
.ResourceThreadId
);
1896 if (Context
->Wait
.Async
.Resource2
!= NULL
) {
1898 ExSetResourceOwnerPointer( Context
->Wait
.Async
.Resource2
,
1899 (PVOID
)Context
->Wait
.Async
.ResourceThreadId
);
1904 // Back up a copy of the IrpContext flags for later use in async completion.
1907 Context
->IrpContextFlags
= IrpContext
->Flags
;
1910 // Now that all the dangerous work is done, issue the read requests
1913 for (UnwindRunCount
= 0;
1914 UnwindRunCount
< MultipleIrpCount
;
1917 Irp
= IoRuns
[UnwindRunCount
].SavedIrp
;
1919 DebugDoit( FatIoCallDriverCount
+= 1);
1922 // If IoCallDriver returns an error, it has completed the Irp
1923 // and the error will be caught by our completion routines
1924 // and dealt with as a normal IO error.
1927 (VOID
)FatLowLevelReadWrite( IrpContext
,
1928 Vcb
->TargetDeviceObject
,
1934 // We just issued an IO to the storage stack, update the counters indicating so.
1937 if (FatDiskAccountingEnabled
) {
1939 FatUpdateIOCountersPCW( IsAWrite
, Length
);
1946 DebugUnwind( FatMultipleAsync
);
1949 // Only allocating the spinlock, making the associated Irps
1950 // and allocating the Mdls can fail.
1953 if ( _SEH2_AbnormalTermination() ) {
1956 // If the driver raised, we are hosed. He is not supposed to raise,
1957 // and it is impossible for us to figure out how to clean up.
1960 if (!ExceptionExpected
) {
1961 NT_ASSERT( ExceptionExpected
);
1963 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
1965 FatBugCheck( 0, 0, 0 );
1972 for (i
= 0; i
<= UnwindRunCount
; i
++) {
1974 if ( (Irp
= IoRuns
[i
].SavedIrp
) != NULL
) {
1976 if ( Irp
->MdlAddress
!= NULL
) {
1978 IoFreeMdl( Irp
->MdlAddress
);
1987 // And return to our caller
1990 DebugTrace(-1, Dbg
, "FatMultipleAsync -> VOID\n", 0);
1999 IN PIRP_CONTEXT IrpContext
,
2008 Routine Description:
2010 This routine reads or writes one or more contiguous sectors from a device
2011 asynchronously, and is used if there is only one read necessary to
2012 complete the IRP. It implements the read by simply filling
2013 in the next stack frame in the Irp, and passing it on. The transfer
2014 occurs to the single buffer originally specified in the user request.
2018 IrpContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
2020 Vcb - Supplies the device to read
2022 Lbo - Supplies the starting Logical Byte Offset to begin reading from
2024 ByteCount - Supplies the number of bytes to read from the device
2026 Irp - Supplies the master Irp to associated with the async
2036 PIO_STACK_LOCATION IrpSp
;
2037 PFAT_IO_CONTEXT Context
;
2039 BOOLEAN IsAWrite
= FALSE
;
2044 DebugTrace(+1, Dbg
, "FatSingleAsync\n", 0);
2045 DebugTrace( 0, Dbg
, "MajorFunction = %08lx\n", IrpContext
->MajorFunction
);
2046 DebugTrace( 0, Dbg
, "Vcb = %p\n", Vcb
);
2047 DebugTrace( 0, Dbg
, "Lbo = %08lx\n", Lbo
);
2048 DebugTrace( 0, Dbg
, "ByteCount = %08lx\n", ByteCount
);
2049 DebugTrace( 0, Dbg
, "Irp = %p\n", Irp
);
2052 // If this I/O originating during FatVerifyVolume, bypass the
2056 if (Vcb
->VerifyThread
== KeGetCurrentThread()) {
2058 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY
);
2062 // Set up the completion routine address in our stack frame.
2065 IoSetCompletionRoutine( Irp
,
2066 FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) ?
2067 &FatSingleSyncCompletionRoutine
:
2068 &FatSingleAsyncCompletionRoutine
,
2069 IrpContext
->FatIoContext
,
2075 // Setup the next IRP stack location in the associated Irp for the disk
2076 // driver beneath us.
2079 IrpSp
= IoGetNextIrpStackLocation( Irp
);
2082 // Setup the Stack location to do a read from the disk driver.
2085 IrpSp
->MajorFunction
= IrpContext
->MajorFunction
;
2086 IrpSp
->Parameters
.Read
.Length
= ByteCount
;
2087 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= Lbo
;
2090 IsAWrite
= (IrpSp
->MajorFunction
== IRP_MJ_WRITE
);
2094 // If this Irp is the result of a WriteThough operation,
2095 // tell the device to write it through.
2098 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
)) {
2100 SetFlag( IrpSp
->Flags
, SL_WRITE_THROUGH
);
2104 // If this I/O requires override verify, bypass the verify logic.
2107 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY
)) {
2109 SetFlag( IrpSp
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
2113 // For async requests if we acquired locks, transition the lock owners to an
2114 // object, since when we return this thread could go away before request
2115 // completion, and the resource package may try to boost priority.
2118 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) &&
2119 FlagOn( IrpContext
->FatIoContext
->Wait
.Async
.ResourceThreadId
, 3 )) {
2121 Context
= IrpContext
->FatIoContext
;
2123 if (Context
->Wait
.Async
.Resource
!= NULL
) {
2125 ExSetResourceOwnerPointer( Context
->Wait
.Async
.Resource
,
2126 (PVOID
)Context
->Wait
.Async
.ResourceThreadId
);
2129 if (Context
->Wait
.Async
.Resource2
!= NULL
) {
2131 ExSetResourceOwnerPointer( Context
->Wait
.Async
.Resource2
,
2132 (PVOID
)Context
->Wait
.Async
.ResourceThreadId
);
2137 // Back up a copy of the IrpContext flags for later use in async completion.
2140 IrpContext
->FatIoContext
->IrpContextFlags
= IrpContext
->Flags
;
2143 // Issue the read request
2146 DebugDoit( FatIoCallDriverCount
+= 1);
2149 // If IoCallDriver returns an error, it has completed the Irp
2150 // and the error will be caught by our completion routines
2151 // and dealt with as a normal IO error.
2154 (VOID
)FatLowLevelReadWrite( IrpContext
,
2155 Vcb
->TargetDeviceObject
,
2160 // We just issued an IO to the storage stack, update the counters indicating so.
2163 if (FatDiskAccountingEnabled
) {
2165 FatUpdateIOCountersPCW( IsAWrite
, ByteCount
);
2169 // And return to our caller
2172 DebugTrace(-1, Dbg
, "FatSingleAsync -> VOID\n", 0);
2179 FatSingleNonAlignedSync (
2180 IN PIRP_CONTEXT IrpContext
,
2190 Routine Description:
2192 This routine reads or writes one or more contiguous sectors from a device
2193 Synchronously, and does so to a buffer that must come from non paged
2194 pool. It saves a pointer to the Irp's original Mdl, and creates a new
2195 one describing the given buffer. It implements the read by simply filling
2196 in the next stack frame in the Irp, and passing it on. The transfer
2197 occurs to the single buffer originally specified in the user request.
2201 IrpContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
2203 Vcb - Supplies the device to read
2205 Buffer - Supplies a buffer from non-paged pool.
2207 Lbo - Supplies the starting Logical Byte Offset to begin reading from
2209 ByteCount - Supplies the number of bytes to read from the device
2211 Irp - Supplies the master Irp to associated with the async
2221 PIO_STACK_LOCATION IrpSp
;
2226 BOOLEAN IsAWrite
= FALSE
;
2231 DebugTrace(+1, Dbg
, "FatSingleNonAlignedAsync\n", 0);
2232 DebugTrace( 0, Dbg
, "MajorFunction = %08lx\n", IrpContext
->MajorFunction
);
2233 DebugTrace( 0, Dbg
, "Vcb = %p\n", Vcb
);
2234 DebugTrace( 0, Dbg
, "Buffer = %p\n", Buffer
);
2235 DebugTrace( 0, Dbg
, "Lbo = %08lx\n", Lbo
);
2236 DebugTrace( 0, Dbg
, "ByteCount = %08lx\n", ByteCount
);
2237 DebugTrace( 0, Dbg
, "Irp = %p\n", Irp
);
2240 // Create a new Mdl describing the buffer, saving the current one in the
2244 SavedMdl
= Irp
->MdlAddress
;
2246 Irp
->MdlAddress
= 0;
2248 Mdl
= IoAllocateMdl( Buffer
,
2256 Irp
->MdlAddress
= SavedMdl
;
2258 FatRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2262 // Lock the new Mdl in memory.
2267 MmProbeAndLockPages( Mdl
, KernelMode
, IoWriteAccess
);
2271 if ( _SEH2_AbnormalTermination() ) {
2274 Irp
->MdlAddress
= SavedMdl
;
2279 // Set up the completion routine address in our stack frame.
2282 IoSetCompletionRoutine( Irp
,
2283 &FatSingleSyncCompletionRoutine
,
2284 IrpContext
->FatIoContext
,
2290 // Setup the next IRP stack location in the associated Irp for the disk
2291 // driver beneath us.
2294 IrpSp
= IoGetNextIrpStackLocation( Irp
);
2297 // Setup the Stack location to do a read from the disk driver.
2300 IrpSp
->MajorFunction
= IrpContext
->MajorFunction
;
2301 IrpSp
->Parameters
.Read
.Length
= ByteCount
;
2302 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= Lbo
;
2305 IsAWrite
= (IrpSp
->MajorFunction
== IRP_MJ_WRITE
);
2309 // If this I/O originating during FatVerifyVolume, bypass the
2313 if (Vcb
->VerifyThread
== KeGetCurrentThread()) {
2315 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY
);
2319 // If this I/O requires override verify, bypass the verify logic.
2322 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY
)) {
2324 SetFlag( IrpSp
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
2328 // Issue the read request
2331 DebugDoit( FatIoCallDriverCount
+= 1);
2334 // If IoCallDriver returns an error, it has completed the Irp
2335 // and the error will be caught by our completion routines
2336 // and dealt with as a normal IO error.
2341 (VOID
)FatLowLevelReadWrite( IrpContext
,
2342 Vcb
->TargetDeviceObject
,
2346 FatWaitSync( IrpContext
);
2350 MmUnlockPages( Mdl
);
2352 Irp
->MdlAddress
= SavedMdl
;
2356 // We just issued an IO to the storage stack, update the counters indicating so.
2359 if (FatDiskAccountingEnabled
) {
2361 FatUpdateIOCountersPCW( IsAWrite
, ByteCount
);
2365 // And return to our caller
2368 DebugTrace(-1, Dbg
, "FatSingleNonAlignedSync -> VOID\n", 0);
2376 IN PIRP_CONTEXT IrpContext
2381 Routine Description:
2383 This routine waits for one or more previously started I/O requests
2384 from the above routines, by simply waiting on the event.
2397 DebugTrace(+1, Dbg
, "FatWaitSync, Context = %p\n", IrpContext
->FatIoContext
);
2399 KeWaitForSingleObject( &IrpContext
->FatIoContext
->Wait
.SyncEvent
,
2400 Executive
, KernelMode
, FALSE
, NULL
);
2402 KeClearEvent( &IrpContext
->FatIoContext
->Wait
.SyncEvent
);
2404 DebugTrace(-1, Dbg
, "FatWaitSync -> VOID\n", 0 );
2409 // Internal Support Routine
2414 FatMultiSyncCompletionRoutine (
2415 _In_ PDEVICE_OBJECT DeviceObject
,
2417 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
2422 Routine Description:
2424 This is the completion routine for all reads and writes started via
2425 FatRead/WriteMultipleAsynch. It must synchronize its operation for
2426 multiprocessor environments with itself on all other processors, via
2427 a spin lock found via the Context parameter.
2429 The completion routine has the following responsibilities:
2431 If the individual request was completed with an error, then
2432 this completion routine must see if this is the first error
2433 (essentially by Vbo), and if so it must correctly reduce the
2434 byte count and remember the error status in the Context.
2436 If the IrpCount goes to 1, then it sets the event in the Context
2437 parameter to signal the caller that all of the asynch requests
2442 DeviceObject - Pointer to the file system device object.
2444 Irp - Pointer to the associated Irp which is being completed. (This
2445 Irp will no longer be accessible after this routine returns.)
2447 Contxt - The context parameter which was specified for all of
2448 the multiple asynch I/O requests for this MasterIrp.
2452 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
2453 immediately complete the Master Irp without being in a race condition
2454 with the IoCompleteRequest thread trying to decrement the IrpCount in
2461 PFAT_IO_CONTEXT Context
= Contxt
;
2462 PIRP MasterIrp
= Context
->MasterIrp
;
2464 DebugTrace(+1, Dbg
, "FatMultiSyncCompletionRoutine, Context = %p\n", Context
);
2467 // If we got an error (or verify required), remember it in the Irp
2470 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
2473 if(!( NT_SUCCESS( FatBreakOnInterestingIoCompletion
) || Irp
->IoStatus
.Status
!= FatBreakOnInterestingIoCompletion
)) {
2478 #ifdef SYSCACHE_COMPILE
2479 DbgPrint( "FAT SYSCACHE: MultiSync (IRP %08x for Master %08x) -> %08x\n", Irp
, MasterIrp
, Irp
->IoStatus
);
2482 MasterIrp
->IoStatus
= Irp
->IoStatus
;
2485 NT_ASSERT( !(NT_SUCCESS( Irp
->IoStatus
.Status
) && Irp
->IoStatus
.Information
== 0 ));
2488 // We must do this here since IoCompleteRequest won't get a chance
2489 // on this associated Irp.
2492 IoFreeMdl( Irp
->MdlAddress
);
2495 if (InterlockedDecrement(&Context
->IrpCount
) == 0) {
2497 FatDoCompletionZero( MasterIrp
, Context
);
2498 KeSetEvent( &Context
->Wait
.SyncEvent
, 0, FALSE
);
2501 DebugTrace(-1, Dbg
, "FatMultiSyncCompletionRoutine -> SUCCESS\n", 0 );
2503 UNREFERENCED_PARAMETER( DeviceObject
);
2505 return STATUS_MORE_PROCESSING_REQUIRED
;
2510 // Internal Support Routine
2515 FatMultiAsyncCompletionRoutine (
2516 _In_ PDEVICE_OBJECT DeviceObject
,
2518 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
2523 Routine Description:
2525 This is the completion routine for all reads and writes started via
2526 FatRead/WriteMultipleAsynch. It must synchronize its operation for
2527 multiprocessor environments with itself on all other processors, via
2528 a spin lock found via the Context parameter.
2530 The completion routine has has the following responsibilities:
2532 If the individual request was completed with an error, then
2533 this completion routine must see if this is the first error
2534 (essentially by Vbo), and if so it must correctly reduce the
2535 byte count and remember the error status in the Context.
2537 If the IrpCount goes to 1, then it sets the event in the Context
2538 parameter to signal the caller that all of the asynch requests
2543 DeviceObject - Pointer to the file system device object.
2545 Irp - Pointer to the associated Irp which is being completed. (This
2546 Irp will no longer be accessible after this routine returns.)
2548 Contxt - The context parameter which was specified for all of
2549 the multiple asynch I/O requests for this MasterIrp.
2553 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
2554 immediately complete the Master Irp without being in a race condition
2555 with the IoCompleteRequest thread trying to decrement the IrpCount in
2561 NTSTATUS Status
= STATUS_SUCCESS
;
2562 PFAT_IO_CONTEXT Context
= Contxt
;
2563 PIRP MasterIrp
= Context
->MasterIrp
;
2564 BOOLEAN PostRequest
= FALSE
;
2566 DebugTrace(+1, Dbg
, "FatMultiAsyncCompletionRoutine, Context = %p\n", Context
);
2569 // If we got an error (or verify required), remember it in the Irp
2572 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
2575 if (!( NT_SUCCESS( FatBreakOnInterestingIoCompletion
) || Irp
->IoStatus
.Status
!= FatBreakOnInterestingIoCompletion
)) {
2580 #ifdef SYSCACHE_COMPILE
2581 DbgPrint( "FAT SYSCACHE: MultiAsync (IRP %08x for Master %08x) -> %08x\n", Irp
, MasterIrp
, Irp
->IoStatus
);
2584 MasterIrp
->IoStatus
= Irp
->IoStatus
;
2588 NT_ASSERT( !(NT_SUCCESS( Irp
->IoStatus
.Status
) && Irp
->IoStatus
.Information
== 0 ));
2590 if (InterlockedDecrement(&Context
->IrpCount
) == 0) {
2592 FatDoCompletionZero( MasterIrp
, Context
);
2594 if (NT_SUCCESS(MasterIrp
->IoStatus
.Status
)) {
2596 MasterIrp
->IoStatus
.Information
=
2597 Context
->Wait
.Async
.RequestedByteCount
;
2599 NT_ASSERT(MasterIrp
->IoStatus
.Information
!= 0);
2602 // Now if this wasn't PagingIo, set either the read or write bit.
2605 if (!FlagOn(MasterIrp
->Flags
, IRP_PAGING_IO
)) {
2607 SetFlag( Context
->Wait
.Async
.FileObject
->Flags
,
2608 IoGetCurrentIrpStackLocation(MasterIrp
)->MajorFunction
== IRP_MJ_READ
?
2609 FO_FILE_FAST_IO_READ
: FO_FILE_MODIFIED
);
2615 // Post STATUS_VERIFY_REQUIRED failures. Only post top level IRPs, because recursive I/Os
2616 // cannot process volume verification.
2619 if (!FlagOn(Context
->IrpContextFlags
, IRP_CONTEXT_FLAG_RECURSIVE_CALL
) &&
2620 (MasterIrp
->IoStatus
.Status
== STATUS_VERIFY_REQUIRED
)) {
2627 // If this was a special async write, decrement the count. Set the
2628 // event if this was the final outstanding I/O for the file. We will
2629 // also want to queue an APC to deal with any error conditionions.
2631 _Analysis_assume_(!(Context
->Wait
.Async
.NonPagedFcb
) &&
2632 (ExInterlockedAddUlong( &Context
->Wait
.Async
.NonPagedFcb
->OutstandingAsyncWrites
,
2634 &FatData
.GeneralSpinLock
) != 1));
2635 if ((Context
->Wait
.Async
.NonPagedFcb
) &&
2636 (ExInterlockedAddUlong( &Context
->Wait
.Async
.NonPagedFcb
->OutstandingAsyncWrites
,
2638 &FatData
.GeneralSpinLock
) == 1)) {
2640 KeSetEvent( Context
->Wait
.Async
.NonPagedFcb
->OutstandingAsyncEvent
, 0, FALSE
);
2644 // Now release the resources.
2647 if (Context
->Wait
.Async
.Resource
!= NULL
) {
2649 ExReleaseResourceForThreadLite( Context
->Wait
.Async
.Resource
,
2650 Context
->Wait
.Async
.ResourceThreadId
);
2653 if (Context
->Wait
.Async
.Resource2
!= NULL
) {
2655 ExReleaseResourceForThreadLite( Context
->Wait
.Async
.Resource2
,
2656 Context
->Wait
.Async
.ResourceThreadId
);
2660 // Mark the master Irp pending
2663 IoMarkIrpPending( MasterIrp
);
2666 // and finally, free the context record.
2669 ExFreePool( Context
);
2673 PIRP_CONTEXT IrpContext
= NULL
;
2677 IrpContext
= FatCreateIrpContext(Irp
, TRUE
);
2678 ClearFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_RECURSIVE_CALL
);
2679 FatFsdPostRequest( IrpContext
, Irp
);
2680 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2682 } _SEH2_EXCEPT( FatExceptionFilter(NULL
, _SEH2_GetExceptionInformation()) ) {
2685 // If we failed to post the IRP, we just have to return the failure
2694 DebugTrace(-1, Dbg
, "FatMultiAsyncCompletionRoutine -> SUCCESS\n", 0 );
2696 UNREFERENCED_PARAMETER( DeviceObject
);
2703 FatPagingFileErrorHandler (
2705 IN PKEVENT Event OPTIONAL
2710 Routine Description:
2712 This routine attempts to guarantee that the media is marked dirty
2713 with the surface test bit if a paging file IO fails.
2715 The work done here has several basic problems
2717 1) when paging file writes start failing, this is a good sign
2718 that the rest of the system is about to fall down around us
2720 2) it has no forward progress guarantee
2722 With Whistler, it is actually quite intentional that we're rejiggering
2723 the paging file write path to make forward progress at all times. This
2724 means that the cases where it *does* fail, we're truly seeing media errors
2725 and this is probably going to mean the paging file is going to stop working
2728 It'd be nice to make this guarantee progress. It would need
2730 1) a guaranteed worker thread which can only be used by items which
2731 will make forward progress (i.e., not block out this one)
2733 2) the virtual volume file's pages containing the boot sector and
2734 1st FAT entry would have to be pinned resident and have a guaranteed
2737 3) mark volume would have to have a stashed irp/mdl and roll the write
2738 irp, or use a generalized mechanism to guarantee issue of the irp
2740 4) the lower stack would have to guarantee progress
2742 Of these, 1 and 4 may actually exist shortly.
2746 Irp - Pointer to the associated Irp which is being failed.
2748 Event - Pointer to optional event to be signalled instead of completing
2753 Returns STATUS_MORE_PROCESSING_REQUIRED if we managed to queue off the workitem,
2754 STATUS_SUCCESS otherwise.
2762 // If this was a media error, we want to chkdsk /r the next time we boot.
2765 if (FsRtlIsTotalDeviceFailure(Irp
->IoStatus
.Status
)) {
2767 Status
= STATUS_SUCCESS
;
2771 PCLEAN_AND_DIRTY_VOLUME_PACKET Packet
;
2774 // We are going to try to mark the volume needing recover.
2775 // If we can't get pool, oh well....
2779 Packet
= ExAllocatePoolWithTag(NonPagedPoolNx
, sizeof(CLEAN_AND_DIRTY_VOLUME_PACKET
), ' taF');
2781 Packet
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CLEAN_AND_DIRTY_VOLUME_PACKET
), ' taF');
2786 Packet
->Vcb
= &((PVOLUME_DEVICE_OBJECT
)IoGetCurrentIrpStackLocation(Irp
)->DeviceObject
)->Vcb
;
2788 Packet
->Event
= Event
;
2790 ExInitializeWorkItem( &Packet
->Item
,
2791 &FatFspMarkVolumeDirtyWithRecover
,
2795 #pragma prefast( suppress:28159, "prefast indicates this is obsolete, but it is ok for fastfat to use it" )
2797 ExQueueWorkItem( &Packet
->Item
, CriticalWorkQueue
);
2799 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2803 Status
= STATUS_SUCCESS
;
2812 // Internal Support Routine
2817 FatPagingFileCompletionRoutineCatch (
2818 _In_ PDEVICE_OBJECT DeviceObject
,
2820 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
2825 Routine Description:
2827 This is the completion routine for all reads and writes started via
2828 FatPagingFileIo that reuse the master irp (that we have to catch
2829 on the way back). It is always invoked.
2831 The completion routine has has the following responsibility:
2833 If the error implies a media problem, it enqueues a
2834 worker item to write out the dirty bit so that the next
2835 time we run we will do a autochk /r. This is not forward
2836 progress guaranteed at the moment.
2838 Clean up the Mdl used for this partial request.
2840 Note that if the Irp is failing, the error code is already where
2845 DeviceObject - Pointer to the file system device object.
2847 Irp - Pointer to the associated Irp which is being completed. (This
2848 Irp will no longer be accessible after this routine returns.)
2850 MasterIrp - Pointer to the master Irp.
2854 Always returns STATUS_MORE_PROCESSING_REQUIRED.
2859 PFAT_PAGING_FILE_CONTEXT Context
= (PFAT_PAGING_FILE_CONTEXT
) Contxt
;
2861 UNREFERENCED_PARAMETER( DeviceObject
);
2863 DebugTrace(+1, Dbg
, "FatPagingFileCompletionRoutineCatch, Context = %p\n", Context
);
2866 // Cleanup the existing Mdl, perhaps by returning the reserve.
2869 if (Irp
->MdlAddress
== FatReserveMdl
) {
2871 MmPrepareMdlForReuse( Irp
->MdlAddress
);
2872 KeSetEvent( &FatReserveEvent
, 0, FALSE
);
2876 IoFreeMdl( Irp
->MdlAddress
);
2880 // Restore the original Mdl.
2883 Irp
->MdlAddress
= Context
->RestoreMdl
;
2885 DebugTrace(-1, Dbg
, "FatPagingFileCompletionRoutine => (done)\n", 0 );
2888 // If the IRP is succeeding or the failure handler did not post off the
2889 // completion, we're done and should set the event to let the master
2890 // know the IRP is his again.
2893 if (NT_SUCCESS( Irp
->IoStatus
.Status
) ||
2894 FatPagingFileErrorHandler( Irp
, &Context
->Event
) == STATUS_SUCCESS
) {
2896 KeSetEvent( &Context
->Event
, 0, FALSE
);
2899 return STATUS_MORE_PROCESSING_REQUIRED
;
2905 // Internal Support Routine
2910 FatPagingFileCompletionRoutine (
2911 _In_ PDEVICE_OBJECT DeviceObject
,
2913 _In_reads_opt_(_Inexpressible_("varies")) PVOID MasterIrp
2918 Routine Description:
2920 This is the completion routine for all reads and writes started via
2921 FatPagingFileIo. It should only be invoked on error or cancel.
2923 The completion routine has has the following responsibility:
2925 Since the individual request was completed with an error,
2926 this completion routine must stuff it into the master irp.
2928 If the error implies a media problem, it also enqueues a
2929 worker item to write out the dirty bit so that the next
2930 time we run we will do a autochk /r
2934 DeviceObject - Pointer to the file system device object.
2936 Irp - Pointer to the associated Irp which is being completed. (This
2937 Irp will no longer be accessible after this routine returns.)
2939 MasterIrp - Pointer to the master Irp.
2943 Always returns STATUS_SUCCESS.
2948 DebugTrace(+1, Dbg
, "FatPagingFileCompletionRoutine, MasterIrp = %p\n", MasterIrp
);
2951 // If we got an error (or verify required), remember it in the Irp
2954 NT_ASSERT( !NT_SUCCESS( Irp
->IoStatus
.Status
));
2957 // If we were invoked with an assoicated Irp, copy the error over.
2960 if (Irp
!= MasterIrp
) {
2962 ((PIRP
)MasterIrp
)->IoStatus
= Irp
->IoStatus
;
2965 DebugTrace(-1, Dbg
, "FatPagingFileCompletionRoutine => (done)\n", 0 );
2967 UNREFERENCED_PARAMETER( DeviceObject
);
2969 return FatPagingFileErrorHandler( Irp
, NULL
);
2974 // Internal Support Routine
2979 FatSpecialSyncCompletionRoutine (
2980 _In_ PDEVICE_OBJECT DeviceObject
,
2982 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
2987 Routine Description:
2989 This is the completion routine for a special set of sub irps
2990 that have to work at APC level.
2992 The completion routine has has the following responsibilities:
2994 It sets the event passed as the context to signal that the
2997 By doing this, the caller will be released before final APC
2998 completion with knowledge that the IRP is finished. Final
2999 completion will occur at an indeterminate time after this
3000 occurs, and by using this completion routine the caller expects
3001 to not have any output or status returned. A junk user Iosb
3002 should be used to capture the status without forcing Io to take
3003 an exception on NULL.
3007 DeviceObject - Pointer to the file system device object.
3009 Irp - Pointer to the Irp for this request. (This Irp will no longer
3010 be accessible after this routine returns.)
3012 Contxt - The context parameter which was specified in the call to
3013 FatRead/WriteSingleAsynch.
3017 Currently always returns STATUS_SUCCESS.
3022 PFAT_SYNC_CONTEXT SyncContext
= (PFAT_SYNC_CONTEXT
)Contxt
;
3024 UNREFERENCED_PARAMETER( Irp
);
3026 DebugTrace(+1, Dbg
, "FatSpecialSyncCompletionRoutine, Context = %p\n", Contxt
);
3028 SyncContext
->Iosb
= Irp
->IoStatus
;
3030 KeSetEvent( &SyncContext
->Event
, 0, FALSE
);
3032 DebugTrace(-1, Dbg
, "FatSpecialSyncCompletionRoutine -> STATUS_SUCCESS\n", 0 );
3034 UNREFERENCED_PARAMETER( DeviceObject
);
3036 return STATUS_SUCCESS
;
3041 // Internal Support Routine
3046 FatSingleSyncCompletionRoutine (
3047 _In_ PDEVICE_OBJECT DeviceObject
,
3049 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
3054 Routine Description:
3056 This is the completion routine for all reads and writes started via
3057 FatRead/WriteSingleAsynch.
3059 The completion routine has has the following responsibilities:
3061 Copy the I/O status from the Irp to the Context, since the Irp
3062 will no longer be accessible.
3064 It sets the event in the Context parameter to signal the caller
3065 that all of the asynch requests are done.
3069 DeviceObject - Pointer to the file system device object.
3071 Irp - Pointer to the Irp for this request. (This Irp will no longer
3072 be accessible after this routine returns.)
3074 Contxt - The context parameter which was specified in the call to
3075 FatRead/WriteSingleAsynch.
3079 Currently always returns STATUS_SUCCESS.
3084 PFAT_IO_CONTEXT Context
= Contxt
;
3086 DebugTrace(+1, Dbg
, "FatSingleSyncCompletionRoutine, Context = %p\n", Context
);
3088 FatDoCompletionZero( Irp
, Context
);
3090 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
3093 if(!( NT_SUCCESS( FatBreakOnInterestingIoCompletion
) || Irp
->IoStatus
.Status
!= FatBreakOnInterestingIoCompletion
)) {
3100 NT_ASSERT( !(NT_SUCCESS( Irp
->IoStatus
.Status
) && Irp
->IoStatus
.Information
== 0 ));
3102 KeSetEvent( &Context
->Wait
.SyncEvent
, 0, FALSE
);
3104 DebugTrace(-1, Dbg
, "FatSingleSyncCompletionRoutine -> STATUS_MORE_PROCESSING_REQUIRED\n", 0 );
3106 UNREFERENCED_PARAMETER( DeviceObject
);
3108 return STATUS_MORE_PROCESSING_REQUIRED
;
3113 // Internal Support Routine
3118 FatSingleAsyncCompletionRoutine (
3119 _In_ PDEVICE_OBJECT DeviceObject
,
3121 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
3126 Routine Description:
3128 This is the completion routine for all reads and writes started via
3129 FatRead/WriteSingleAsynch.
3131 The completion routine has has the following responsibilities:
3133 Copy the I/O status from the Irp to the Context, since the Irp
3134 will no longer be accessible.
3136 It sets the event in the Context parameter to signal the caller
3137 that all of the asynch requests are done.
3141 DeviceObject - Pointer to the file system device object.
3143 Irp - Pointer to the Irp for this request. (This Irp will no longer
3144 be accessible after this routine returns.)
3146 Contxt - The context parameter which was specified in the call to
3147 FatRead/WriteSingleAsynch.
3151 Currently always returns STATUS_SUCCESS.
3156 NTSTATUS Status
= STATUS_SUCCESS
;
3158 PFAT_IO_CONTEXT Context
= Contxt
;
3159 BOOLEAN PostRequest
= FALSE
;
3161 DebugTrace(+1, Dbg
, "FatSingleAsyncCompletionRoutine, Context = %p\n", Context
);
3164 // Fill in the information field correctedly if this worked.
3167 FatDoCompletionZero( Irp
, Context
);
3169 if (NT_SUCCESS(Irp
->IoStatus
.Status
)) {
3171 NT_ASSERT( Irp
->IoStatus
.Information
!= 0 );
3172 Irp
->IoStatus
.Information
= Context
->Wait
.Async
.RequestedByteCount
;
3173 NT_ASSERT( Irp
->IoStatus
.Information
!= 0 );
3176 // Now if this wasn't PagingIo, set either the read or write bit.
3179 if (!FlagOn(Irp
->Flags
, IRP_PAGING_IO
)) {
3181 SetFlag( Context
->Wait
.Async
.FileObject
->Flags
,
3182 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
== IRP_MJ_READ
?
3183 FO_FILE_FAST_IO_READ
: FO_FILE_MODIFIED
);
3189 if(!( NT_SUCCESS( FatBreakOnInterestingIoCompletion
) || Irp
->IoStatus
.Status
!= FatBreakOnInterestingIoCompletion
)) {
3194 #ifdef SYSCACHE_COMPILE
3195 DbgPrint( "FAT SYSCACHE: SingleAsync (IRP %08x) -> %08x\n", Irp
, Irp
->IoStatus
);
3199 // Post STATUS_VERIFY_REQUIRED failures. Only post top level IRPs, because recursive I/Os
3200 // cannot process volume verification.
3203 if (!FlagOn(Context
->IrpContextFlags
, IRP_CONTEXT_FLAG_RECURSIVE_CALL
) &&
3204 (Irp
->IoStatus
.Status
== STATUS_VERIFY_REQUIRED
)) {
3211 // If this was a special async write, decrement the count. Set the
3212 // event if this was the final outstanding I/O for the file. We will
3213 // also want to queue an APC to deal with any error conditionions.
3215 _Analysis_assume_(!(Context
->Wait
.Async
.NonPagedFcb
) &&
3216 (ExInterlockedAddUlong( &Context
->Wait
.Async
.NonPagedFcb
->OutstandingAsyncWrites
,
3218 &FatData
.GeneralSpinLock
) != 1));
3220 if ((Context
->Wait
.Async
.NonPagedFcb
) &&
3221 (ExInterlockedAddUlong( &Context
->Wait
.Async
.NonPagedFcb
->OutstandingAsyncWrites
,
3223 &FatData
.GeneralSpinLock
) == 1)) {
3225 KeSetEvent( Context
->Wait
.Async
.NonPagedFcb
->OutstandingAsyncEvent
, 0, FALSE
);
3229 // Now release the resources
3232 if (Context
->Wait
.Async
.Resource
!= NULL
) {
3234 ExReleaseResourceForThreadLite( Context
->Wait
.Async
.Resource
,
3235 Context
->Wait
.Async
.ResourceThreadId
);
3238 if (Context
->Wait
.Async
.Resource2
!= NULL
) {
3240 ExReleaseResourceForThreadLite( Context
->Wait
.Async
.Resource2
,
3241 Context
->Wait
.Async
.ResourceThreadId
);
3245 // Mark the Irp pending
3248 IoMarkIrpPending( Irp
);
3251 // and finally, free the context record.
3254 ExFreePool( Context
);
3258 PIRP_CONTEXT IrpContext
= NULL
;
3262 IrpContext
= FatCreateIrpContext(Irp
, TRUE
);
3263 ClearFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_RECURSIVE_CALL
);
3264 FatFsdPostRequest( IrpContext
, Irp
);
3265 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
3267 } _SEH2_EXCEPT( FatExceptionFilter(NULL
, _SEH2_GetExceptionInformation()) ) {
3270 // If we failed to post the IRP, we just have to return the failure
3279 DebugTrace(-1, Dbg
, "FatSingleAsyncCompletionRoutine -> STATUS_MORE_PROCESSING_REQUIRED\n", 0 );
3281 UNREFERENCED_PARAMETER( DeviceObject
);
3289 IN PIRP_CONTEXT IrpContext
,
3291 IN LOCK_OPERATION Operation
,
3292 IN ULONG BufferLength
3297 Routine Description:
3299 This routine locks the specified buffer for the specified type of
3300 access. The file system requires this routine since it does not
3301 ask the I/O system to lock its buffers for direct I/O. This routine
3302 may only be called from the Fsd while still in the user context.
3304 Note that this is the *input/output* buffer.
3308 Irp - Pointer to the Irp for which the buffer is to be locked.
3310 Operation - IoWriteAccess for read operations, or IoReadAccess for
3313 BufferLength - Length of user buffer.
3326 if (Irp
->MdlAddress
== NULL
) {
3329 // Allocate the Mdl, and Raise if we fail.
3332 Mdl
= IoAllocateMdl( Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
3336 FatRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
3340 // Now probe the buffer described by the Irp. If we get an exception,
3341 // deallocate the Mdl and return the appropriate "expected" status.
3346 MmProbeAndLockPages( Mdl
,
3350 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
3354 Status
= _SEH2_GetExceptionCode();
3357 Irp
->MdlAddress
= NULL
;
3359 FatRaiseStatus( IrpContext
,
3360 FsRtlIsNtstatusExpected(Status
) ? Status
: STATUS_INVALID_USER_BUFFER
);
3364 UNREFERENCED_PARAMETER( IrpContext
);
3370 IN PIRP_CONTEXT IrpContext
,
3376 Routine Description:
3378 This routine conditionally maps the user buffer for the current I/O
3379 request in the specified mode. If the buffer is already mapped, it
3380 just returns its address.
3382 Note that this is the *input/output* buffer.
3386 Irp - Pointer to the Irp for the request.
3395 UNREFERENCED_PARAMETER( IrpContext
);
3400 // If there is no Mdl, then we must be in the Fsd, and we can simply
3401 // return the UserBuffer field from the Irp.
3404 if (Irp
->MdlAddress
== NULL
) {
3406 return Irp
->UserBuffer
;
3411 PVOID Address
= MmGetSystemAddressForMdlSafe( Irp
->MdlAddress
, NormalPagePriority
| MdlMappingNoExecute
);
3413 PVOID Address
= MmGetSystemAddressForMdlSafe( Irp
->MdlAddress
, NormalPagePriority
);
3416 if (Address
== NULL
) {
3418 ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES
);
3427 FatBufferUserBuffer (
3428 IN PIRP_CONTEXT IrpContext
,
3430 IN ULONG BufferLength
3435 Routine Description:
3437 This routine conditionally buffers the user buffer for the current I/O
3438 request. If the buffer is already buffered, it just returns its address.
3440 Note that this is the *input* buffer.
3444 Irp - Pointer to the Irp for the request.
3446 BufferLength - Length of user buffer.
3457 UNREFERENCED_PARAMETER( IrpContext
);
3462 // Handle the no buffer case.
3465 if (BufferLength
== 0) {
3471 // If there is no system buffer we must have been supplied an Mdl
3472 // describing the users input buffer, which we will now snapshot.
3475 if (Irp
->AssociatedIrp
.SystemBuffer
== NULL
) {
3477 UserBuffer
= FatMapUserBuffer( IrpContext
, Irp
);
3480 Irp
->AssociatedIrp
.SystemBuffer
= FsRtlAllocatePoolWithQuotaTag( NonPagedPoolNx
,
3482 Irp
->AssociatedIrp
.SystemBuffer
= FsRtlAllocatePoolWithQuotaTag( NonPagedPool
,
3485 TAG_IO_USER_BUFFER
);
3488 // Set the flags so that the completion code knows to deallocate the
3492 Irp
->Flags
|= (IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
);
3496 RtlCopyMemory( Irp
->AssociatedIrp
.SystemBuffer
,
3500 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
3504 Status
= _SEH2_GetExceptionCode();
3505 FatRaiseStatus( IrpContext
,
3506 FsRtlIsNtstatusExpected(Status
) ? Status
: STATUS_INVALID_USER_BUFFER
);
3510 return Irp
->AssociatedIrp
.SystemBuffer
;
3515 FatToggleMediaEjectDisable (
3516 IN PIRP_CONTEXT IrpContext
,
3518 IN BOOLEAN PreventRemoval
3523 Routine Description:
3525 The routine either enables or disables the eject button on removable
3530 Vcb - Descibes the volume to operate on
3532 PreventRemoval - TRUE if we should disable the media eject button. FALSE
3533 if we want to enable it.
3537 Status of the operation.
3545 FAT_SYNC_CONTEXT SyncContext
;
3546 PREVENT_MEDIA_REMOVAL Prevent
;
3548 UNREFERENCED_PARAMETER( IrpContext
);
3551 // If PreventRemoval is the same as VCB_STATE_FLAG_REMOVAL_PREVENTED,
3552 // no-op this call, otherwise toggle the state of the flag.
3555 KeAcquireSpinLock( &FatData
.GeneralSpinLock
, &SavedIrql
);
3557 if ((PreventRemoval
^
3558 BooleanFlagOn(Vcb
->VcbState
, VCB_STATE_FLAG_REMOVAL_PREVENTED
)) == 0) {
3560 KeReleaseSpinLock( &FatData
.GeneralSpinLock
, SavedIrql
);
3562 return STATUS_SUCCESS
;
3566 Vcb
->VcbState
^= VCB_STATE_FLAG_REMOVAL_PREVENTED
;
3568 KeReleaseSpinLock( &FatData
.GeneralSpinLock
, SavedIrql
);
3571 Prevent
.PreventMediaRemoval
= PreventRemoval
;
3573 KeInitializeEvent( &SyncContext
.Event
, NotificationEvent
, FALSE
);
3576 // We build this IRP using a junk Iosb that will receive the final
3577 // completion status since we won't be around for it.
3579 // We fill in the UserIosb manually below,
3580 // So passing NULL for the final parameter is ok in this special case.
3583 #pragma warning(suppress: 6387)
3585 Irp
= IoBuildDeviceIoControlRequest( IOCTL_DISK_MEDIA_REMOVAL
,
3586 Vcb
->TargetDeviceObject
,
3588 sizeof(PREVENT_MEDIA_REMOVAL
),
3595 if ( Irp
!= NULL
) {
3598 // Use our special completion routine which will remove the requirement that
3599 // the caller must be below APC level. All it tells us is that the Irp got
3600 // back, but will not tell us if it was succesful or not. We don't care,
3601 // and there is of course no fallback if the attempt to prevent removal
3602 // doesn't work for some mysterious reason.
3604 // Normally, all IO is done at passive level. However, MM needs to be able
3605 // to issue IO with fast mutexes locked down, which raises us to APC. The
3606 // overlying IRP is set up to complete in yet another magical fashion even
3607 // though APCs are disabled, and any IRPage we do in these cases has to do
3608 // the same. Marking media dirty (and toggling eject state) is one.
3611 Irp
->UserIosb
= &Irp
->IoStatus
;
3613 IoSetCompletionRoutine( Irp
,
3614 FatSpecialSyncCompletionRoutine
,
3620 Status
= IoCallDriver( Vcb
->TargetDeviceObject
, Irp
);
3622 if (Status
== STATUS_PENDING
) {
3624 (VOID
) KeWaitForSingleObject( &SyncContext
.Event
,
3630 Status
= SyncContext
.Iosb
.Status
;
3636 return STATUS_INSUFFICIENT_RESOURCES
;
3641 FatPerformDevIoCtrl (
3642 IN PIRP_CONTEXT IrpContext
,
3643 IN ULONG IoControlCode
,
3644 IN PDEVICE_OBJECT Device
,
3645 IN PVOID InputBuffer OPTIONAL
,
3646 IN ULONG InputBufferLength
,
3647 OUT PVOID OutputBuffer OPTIONAL
,
3648 IN ULONG OutputBufferLength
,
3649 IN BOOLEAN InternalDeviceIoControl
,
3650 IN BOOLEAN OverrideVerify
,
3651 OUT PIO_STATUS_BLOCK Iosb OPTIONAL
3656 Routine Description:
3658 This routine is called to perform DevIoCtrl functions internally within
3659 the filesystem. We take the status from the driver and return it to our
3664 IoControlCode - Code to send to driver.
3666 Device - This is the device to send the request to.
3668 OutPutBuffer - Pointer to output buffer.
3670 OutputBufferLength - Length of output buffer above.
3672 InternalDeviceIoControl - Indicates if this is an internal or external
3675 OverrideVerify - Indicates if we should tell the driver not to return
3676 STATUS_VERIFY_REQUIRED for mount and verify.
3678 Iosb - If specified, we return the results of the operation here.
3682 NTSTATUS - Status returned by next lower driver.
3690 IO_STATUS_BLOCK LocalIosb
;
3691 PIO_STATUS_BLOCK IosbToUse
= &LocalIosb
;
3695 UNREFERENCED_PARAMETER( IrpContext
);
3698 // Check if the user gave us an Iosb.
3701 if (ARGUMENT_PRESENT( Iosb
)) {
3706 IosbToUse
->Status
= 0;
3707 IosbToUse
->Information
= 0;
3709 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
3711 Irp
= IoBuildDeviceIoControlRequest( IoControlCode
,
3717 InternalDeviceIoControl
,
3723 return STATUS_INSUFFICIENT_RESOURCES
;
3726 if (OverrideVerify
) {
3728 SetFlag( IoGetNextIrpStackLocation( Irp
)->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
3731 Status
= IoCallDriver( Device
, Irp
);
3734 // We check for device not ready by first checking Status
3735 // and then if status pending was returned, the Iosb status
3739 if (Status
== STATUS_PENDING
) {
3741 (VOID
) KeWaitForSingleObject( &Event
,
3745 (PLARGE_INTEGER
)NULL
);
3747 Status
= IosbToUse
->Status
;
3755 __in PIRP_CONTEXT IrpContext
,
3760 Routine Description:
3762 Create an efficient mdl that describe a given length of zeros. We'll only
3763 use a one page buffer and make a mdl that maps all the pages back to the single
3764 physical page. We'll default to a smaller size buffer down to 1 PAGE if memory
3765 is tight. The caller should check the Mdl->ByteCount to see the true size
3769 Length - The desired length of the zero buffer. We may return less than this
3773 a MDL if successful / NULL if not
3779 ULONG SavedByteCount
;
3783 UNREFERENCED_PARAMETER( IrpContext
);
3786 // Spin down trying to get an MDL which can describe our operation.
3791 ZeroMdl
= IoAllocateMdl( FatData
.ZeroPage
, Length
, FALSE
, FALSE
, NULL
);
3794 // Throttle ourselves to what we've physically allocated. Note that
3795 // we could have started with an odd multiple of this number. If we
3796 // tried for exactly that size and failed, we're toast.
3799 if (ZeroMdl
|| (Length
<= PAGE_SIZE
)) {
3805 // Fallback by half and round down to a page multiple.
3808 ASSERT( IrpContext
->Vcb
->Bpb
.BytesPerSector
<= PAGE_SIZE
);
3809 Length
= BlockAlignTruncate( Length
/ 2, PAGE_SIZE
);
3810 if (Length
< PAGE_SIZE
) {
3815 if (ZeroMdl
== NULL
) {
3820 // If we have throttled all the way down, stop and just build a
3821 // simple MDL describing our previous allocation.
3824 if (Length
== PAGE_SIZE
) {
3826 MmBuildMdlForNonPagedPool( ZeroMdl
);
3831 // Now we will temporarily lock the allocated pages
3832 // only, and then replicate the page frame numbers through
3833 // the entire Mdl to keep writing the same pages of zeros.
3835 // It would be nice if Mm exported a way for us to not have
3836 // to pull the Mdl apart and rebuild it ourselves, but this
3837 // is so bizzare a purpose as to be tolerable.
3840 SavedByteCount
= ZeroMdl
->ByteCount
;
3841 ZeroMdl
->ByteCount
= PAGE_SIZE
;
3842 MmBuildMdlForNonPagedPool( ZeroMdl
);
3844 ZeroMdl
->MdlFlags
&= ~MDL_SOURCE_IS_NONPAGED_POOL
;
3845 ZeroMdl
->MdlFlags
|= MDL_PAGES_LOCKED
;
3846 ZeroMdl
->MappedSystemVa
= NULL
;
3847 ZeroMdl
->StartVa
= NULL
;
3848 ZeroMdl
->ByteCount
= SavedByteCount
;
3849 Page
= MmGetMdlPfnArray( ZeroMdl
);
3850 for (i
= 1; i
< (ADDRESS_AND_SIZE_TO_SPAN_PAGES( 0, SavedByteCount
)); i
++) {
3851 *(Page
+ i
) = *(Page
);