xref: /reactos/drivers/filesystems/fastfat/read.c (revision 4572aad1)
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     Read.c
8 
9 Abstract:
10 
11     This module implements the File Read routine for Read 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_READ)
24 
25 //
26 //  The local debug trace level
27 //
28 
29 #define Dbg                              (DEBUG_TRACE_READ)
30 
31 //
32 //  Define stack overflow read threshhold.  For the x86 we'll use a smaller
33 //  threshold than for a risc platform.
34 //
35 //  Empirically, the limit is a result of the (large) amount of stack
36 //  neccesary to throw an exception.
37 //
38 
39 #if defined(_M_IX86)
40 #define OVERFLOW_READ_THRESHHOLD         (0xE00)
41 #else
42 #define OVERFLOW_READ_THRESHHOLD         (0x1000)
43 #endif // defined(_M_IX86)
44 
45 
46 //
47 //  The following procedures handles read stack overflow operations.
48 //
49 
50 _Requires_lock_held_(_Global_critical_region_)
51 VOID
52 NTAPI
53 FatStackOverflowRead (
54     IN PVOID Context,
55     IN PKEVENT Event
56     );
57 
58 _Requires_lock_held_(_Global_critical_region_)
59 NTSTATUS
60 FatPostStackOverflowRead (
61     IN PIRP_CONTEXT IrpContext,
62     IN PIRP Irp,
63     IN PFCB Fcb
64     );
65 
66 VOID
67 NTAPI
68 FatOverflowPagingFileRead (
69     IN PVOID Context,
70     IN PKEVENT Event
71     );
72 
73 //
74 //  VOID
75 //  SafeZeroMemory (
76 //      IN PUCHAR At,
77 //      IN ULONG ByteCount
78 //      );
79 //
80 
81 //
82 //  This macro just puts a nice little try-except around RtlZeroMemory
83 //
84 
85 #define SafeZeroMemory(AT,BYTE_COUNT) {                            \
86     _SEH2_TRY {                                                    \
87         RtlZeroMemory((AT), (BYTE_COUNT));                         \
88     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                    \
89          FatRaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER ); \
90     } _SEH2_END                                                    \
91 }
92 
93 //
94 //  Macro to increment appropriate performance counters.
95 //
96 
97 #define CollectReadStats(VCB,OPEN_TYPE,BYTE_COUNT) {                                         \
98     PFILESYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors].Common; \
99     if (((OPEN_TYPE) == UserFileOpen)) {                                                     \
100         Stats->UserFileReads += 1;                                                           \
101         Stats->UserFileReadBytes += (ULONG)(BYTE_COUNT);                                     \
102     } else if (((OPEN_TYPE) == VirtualVolumeFile || ((OPEN_TYPE) == DirectoryFile))) {       \
103         Stats->MetaDataReads += 1;                                                           \
104         Stats->MetaDataReadBytes += (ULONG)(BYTE_COUNT);                                     \
105     }                                                                                        \
106 }
107 
108 
109 #ifdef ALLOC_PRAGMA
110 #pragma alloc_text(PAGE, FatStackOverflowRead)
111 #pragma alloc_text(PAGE, FatPostStackOverflowRead)
112 #pragma alloc_text(PAGE, FatCommonRead)
113 #endif
114 
115 
116 _Function_class_(IRP_MJ_READ)
117 _Function_class_(DRIVER_DISPATCH)
118 NTSTATUS
119 NTAPI
120 FatFsdRead (
121     _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
122     _Inout_ PIRP Irp
123     )
124 
125 /*++
126 
127 Routine Description:
128 
129     This is the driver entry to the common read routine for NtReadFile calls.
130     For synchronous requests, the CommonRead is called with Wait == TRUE,
131     which means the request will always be completed in the current thread,
132     and never passed to the Fsp.  If it is not a synchronous request,
133     CommonRead is called with Wait == FALSE, which means the request
134     will be passed to the Fsp only if there is a need to block.
135 
136 Arguments:
137 
138     VolumeDeviceObject - Supplies the volume device object where the
139         file being Read exists
140 
141     Irp - Supplies the Irp being processed
142 
143 Return Value:
144 
145     NTSTATUS - The FSD status for the IRP
146 
147 --*/
148 
149 {
150     PFCB Fcb = NULL;
151     NTSTATUS Status;
152     PIRP_CONTEXT IrpContext = NULL;
153 
154     BOOLEAN TopLevel = FALSE;
155 
156     DebugTrace(+1, Dbg, "FatFsdRead\n", 0);
157 
158     //
159     //  Call the common Read routine, with blocking allowed if synchronous
160     //
161 
162     FsRtlEnterFileSystem();
163 
164     //
165     //  We are first going to do a quick check for paging file IO.  Since this
166     //  is a fast path, we must replicate the check for the fsdo.
167     //
168 
169     if (!FatDeviceIsFatFsdo( IoGetCurrentIrpStackLocation(Irp)->DeviceObject))  {
170 
171         Fcb = (PFCB)(IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext);
172 
173         if ((NodeType(Fcb) == FAT_NTC_FCB) &&
174             FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
175 
176             //
177             //  Do the usual STATUS_PENDING things.
178             //
179 
180             IoMarkIrpPending( Irp );
181 
182             //
183             //  If there is not enough stack to do this read, then post this
184             //  read to the overflow queue.
185             //
186 
187             if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) {
188 
189                 KEVENT Event;
190                 PAGING_FILE_OVERFLOW_PACKET Packet;
191 
192                 Packet.Irp = Irp;
193                 Packet.Fcb = Fcb;
194 
195                 KeInitializeEvent( &Event, NotificationEvent, FALSE );
196 
197                 FsRtlPostPagingFileStackOverflow( &Packet, &Event, FatOverflowPagingFileRead );
198 
199                 //
200                 //  And wait for the worker thread to complete the item
201                 //
202 
203                 (VOID) KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
204 
205             } else {
206 
207                 //
208                 //  Perform the actual IO, it will be completed when the io finishes.
209                 //
210 
211                 FatPagingFileIo( Irp, Fcb );
212             }
213 
214             FsRtlExitFileSystem();
215 
216             return STATUS_PENDING;
217         }
218     }
219 
220     _SEH2_TRY {
221 
222         TopLevel = FatIsIrpTopLevel( Irp );
223 
224         IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
225 
226         //
227         //  If this is an Mdl complete request, don't go through
228         //  common read.
229         //
230 
231         if ( FlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE) ) {
232 
233             DebugTrace(0, Dbg, "Calling FatCompleteMdl\n", 0 );
234             try_return( Status = FatCompleteMdl( IrpContext, Irp ));
235         }
236 
237         //
238         //  Check if we have enough stack space to process this request.  If there
239         //  isn't enough then we will pass the request off to the stack overflow thread.
240         //
241 
242         if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) {
243 
244             DebugTrace(0, Dbg, "Passing StackOverflowRead off\n", 0 );
245             try_return( Status = FatPostStackOverflowRead( IrpContext, Irp, Fcb ) );
246         }
247 
248         Status = FatCommonRead( IrpContext, Irp );
249 
250     try_exit: NOTHING;
251     } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
252 
253         //
254         //  We had some trouble trying to perform the requested
255         //  operation, so we'll abort the I/O request with
256         //  the error status that we get back from the
257         //  execption code
258         //
259 
260         Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
261     } _SEH2_END;
262 
263     if (TopLevel) { IoSetTopLevelIrp( NULL ); }
264 
265     FsRtlExitFileSystem();
266 
267     //
268     //  And return to our caller
269     //
270 
271     DebugTrace(-1, Dbg, "FatFsdRead -> %08lx\n", Status);
272 
273     UNREFERENCED_PARAMETER( VolumeDeviceObject );
274 
275     return Status;
276 }
277 
278 
279 //
280 //  Internal support routine
281 //
282 
283 _Requires_lock_held_(_Global_critical_region_)
284 NTSTATUS
285 FatPostStackOverflowRead (
286     IN PIRP_CONTEXT IrpContext,
287     IN PIRP Irp,
288     IN PFCB Fcb
289     )
290 
291 /*++
292 
293 Routine Description:
294 
295     This routine posts a read request that could not be processed by
296     the fsp thread because of stack overflow potential.
297 
298 Arguments:
299 
300     Irp - Supplies the request to process.
301 
302     Fcb - Supplies the file.
303 
304 Return Value:
305 
306     STATUS_PENDING.
307 
308 --*/
309 
310 {
311     KEVENT Event;
312     PERESOURCE Resource;
313     PVCB Vcb;
314 
315     PAGED_CODE();
316 
317     DebugTrace(0, Dbg, "Getting too close to stack limit pass request to Fsp\n", 0 );
318 
319     //
320     //  Initialize an event and get shared on the resource we will
321     //  be later using the common read.
322     //
323 
324     KeInitializeEvent( &Event, NotificationEvent, FALSE );
325 
326     //
327     //  Preacquire the resource the read path will require so we know the
328     //  worker thread can proceed without waiting.
329     //
330 
331     if (FlagOn(Irp->Flags, IRP_PAGING_IO) && (Fcb->Header.PagingIoResource != NULL)) {
332 
333         Resource = Fcb->Header.PagingIoResource;
334 
335     } else {
336 
337         Resource = Fcb->Header.Resource;
338     }
339 
340     //
341     //  If there are no resources assodicated with the file (case: the virtual
342     //  volume file), it is OK.  No resources will be acquired on the other side
343     //  as well.
344     //
345 
346     if (Resource) {
347 
348         ExAcquireResourceSharedLite( Resource, TRUE );
349     }
350 
351     if (NodeType( Fcb ) == FAT_NTC_VCB) {
352 
353         Vcb = (PVCB) Fcb;
354 
355     } else {
356 
357         Vcb = Fcb->Vcb;
358     }
359 
360     _SEH2_TRY {
361 
362         //
363         //  Make the Irp just like a regular post request and
364         //  then send the Irp to the special overflow thread.
365         //  After the post we will wait for the stack overflow
366         //  read routine to set the event that indicates we can
367         //  now release the scb resource and return.
368         //
369 
370         FatPrePostIrp( IrpContext, Irp );
371 
372         //
373         //  If this read is the result of a verify, we have to
374         //  tell the overflow read routne to temporarily
375         //  hijack the Vcb->VerifyThread field so that reads
376         //  can go through.
377         //
378 
379         if (Vcb->VerifyThread == KeGetCurrentThread()) {
380 
381             SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ);
382         }
383 
384         FsRtlPostStackOverflow( IrpContext, &Event, FatStackOverflowRead );
385 
386         //
387         //  And wait for the worker thread to complete the item
388         //
389 
390         KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
391 
392     } _SEH2_FINALLY {
393 
394         if (Resource) {
395 
396             ExReleaseResourceLite( Resource );
397         }
398     } _SEH2_END;
399 
400     return STATUS_PENDING;
401 }
402 
403 
404 //
405 //  Internal support routine
406 //
407 
408 _Requires_lock_held_(_Global_critical_region_)
409 VOID
410 NTAPI
411 FatStackOverflowRead (
412     IN PVOID Context,
413     IN PKEVENT Event
414     )
415 
416 /*++
417 
418 Routine Description:
419 
420     This routine processes a read request that could not be processed by
421     the fsp thread because of stack overflow potential.
422 
423 Arguments:
424 
425     Context - Supplies the IrpContext being processed
426 
427     Event - Supplies the event to be signaled when we are done processing this
428         request.
429 
430 Return Value:
431 
432     None.
433 
434 --*/
435 
436 {
437     PIRP_CONTEXT IrpContext = Context;
438     PKTHREAD SavedVerifyThread = NULL;
439     PVCB Vcb = NULL;
440 
441     PAGED_CODE();
442 
443     //
444     //  Make it now look like we can wait for I/O to complete
445     //
446 
447     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
448 
449     //
450     //  If this read was as the result of a verify we have to fake out the
451     //  the Vcb->VerifyThread field.
452     //
453 
454     if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) {
455 
456         PFCB Fcb = (PFCB)IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->
457                     FileObject->FsContext;
458 
459         if (NodeType( Fcb ) == FAT_NTC_VCB) {
460 
461             Vcb = (PVCB) Fcb;
462 
463         } else {
464 
465             Vcb = Fcb->Vcb;
466         }
467 
468         NT_ASSERT( Vcb->VerifyThread != NULL );
469         SavedVerifyThread = Vcb->VerifyThread;
470         Vcb->VerifyThread = KeGetCurrentThread();
471     }
472 
473     //
474     //  Do the read operation protected by a try-except clause
475     //
476 
477     _SEH2_TRY {
478 
479         (VOID) FatCommonRead( IrpContext, IrpContext->OriginatingIrp );
480 
481     } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
482 
483         NTSTATUS ExceptionCode;
484 
485         //
486         //  We had some trouble trying to perform the requested
487         //  operation, so we'll abort the I/O request with
488         //  the error status that we get back from the
489         //  execption code
490         //
491 
492         ExceptionCode = _SEH2_GetExceptionCode();
493 
494         if (ExceptionCode == STATUS_FILE_DELETED) {
495 
496             IrpContext->ExceptionStatus = ExceptionCode = STATUS_END_OF_FILE;
497             IrpContext->OriginatingIrp->IoStatus.Information = 0;
498         }
499 
500         (VOID) FatProcessException( IrpContext, IrpContext->OriginatingIrp, ExceptionCode );
501     } _SEH2_END;
502 
503     //
504     //  Restore the original VerifyVolumeThread
505     //
506 
507     if (SavedVerifyThread != NULL) {
508 
509         NT_ASSERT( Vcb->VerifyThread == KeGetCurrentThread() );
510         Vcb->VerifyThread = SavedVerifyThread;
511     }
512 
513     //
514     //  Set the stack overflow item's event to tell the original
515     //  thread that we're done.
516     //
517 
518     KeSetEvent( Event, 0, FALSE );
519 }
520 
521 
522 _Requires_lock_held_(_Global_critical_region_)
523 NTSTATUS
524 FatCommonRead (
525     IN PIRP_CONTEXT IrpContext,
526     IN PIRP Irp
527     )
528 
529 /*++
530 
531 Routine Description:
532 
533     This is the common read routine for NtReadFile, called from both
534     the Fsd, or from the Fsp if a request could not be completed without
535     blocking in the Fsd.  This routine has no code where it determines
536     whether it is running in the Fsd or Fsp.  Instead, its actions are
537     conditionalized by the Wait input parameter, which determines whether
538     it is allowed to block or not.  If a blocking condition is encountered
539     with Wait == FALSE, however, the request is posted to the Fsp, who
540     always calls with WAIT == TRUE.
541 
542 Arguments:
543 
544     Irp - Supplies the Irp to process
545 
546 Return Value:
547 
548     NTSTATUS - The return status for the operation
549 
550 --*/
551 
552 {
553     PVCB Vcb;
554     PFCB FcbOrDcb;
555     PCCB Ccb;
556 
557     VBO StartingVbo;
558     ULONG ByteCount;
559     ULONG RequestedByteCount;
560 
561     PIO_STACK_LOCATION IrpSp;
562     PFILE_OBJECT FileObject;
563     TYPE_OF_OPEN TypeOfOpen;
564 
565     BOOLEAN PostIrp = FALSE;
566     BOOLEAN OplockPostIrp = FALSE;
567 
568     BOOLEAN FcbOrDcbAcquired = FALSE;
569 
570     BOOLEAN Wait;
571     BOOLEAN PagingIo;
572     BOOLEAN NonCachedIo;
573     BOOLEAN SynchronousIo;
574 
575 
576     NTSTATUS Status = STATUS_SUCCESS;
577 
578     FAT_IO_CONTEXT StackFatIoContext;
579 
580     //
581     // A system buffer is only used if we have to access the
582     // buffer directly from the Fsp to clear a portion or to
583     // do a synchronous I/O, or a cached transfer.  It is
584     // possible that our caller may have already mapped a
585     // system buffer, in which case we must remember this so
586     // we do not unmap it on the way out.
587     //
588 
589     PVOID SystemBuffer = NULL;
590 
591     LARGE_INTEGER StartingByte;
592 
593     PAGED_CODE();
594 
595     //
596     // Get current Irp stack location.
597     //
598 
599     IrpSp = IoGetCurrentIrpStackLocation( Irp );
600     FileObject = IrpSp->FileObject;
601 
602     //
603     // Initialize the appropriate local variables.
604     //
605 
606     Wait          = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
607     PagingIo      = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
608     NonCachedIo   = BooleanFlagOn(Irp->Flags,IRP_NOCACHE);
609     SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
610 
611     DebugTrace(+1, Dbg, "CommonRead\n", 0);
612     DebugTrace( 0, Dbg, "  Irp                   = %p\n", Irp);
613     DebugTrace( 0, Dbg, "  ->ByteCount           = %8lx\n", IrpSp->Parameters.Read.Length);
614     DebugTrace( 0, Dbg, "  ->ByteOffset.LowPart  = %8lx\n", IrpSp->Parameters.Read.ByteOffset.LowPart);
615     DebugTrace( 0, Dbg, "  ->ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.HighPart);
616 
617     //
618     //  Extract starting Vbo and offset.
619     //
620 
621     StartingByte = IrpSp->Parameters.Read.ByteOffset;
622 
623     StartingVbo = StartingByte.LowPart;
624 
625     ByteCount = IrpSp->Parameters.Read.Length;
626     RequestedByteCount = ByteCount;
627 
628     //
629     //  Check for a null request, and return immediately
630     //
631 
632     if (ByteCount == 0) {
633 
634         Irp->IoStatus.Information = 0;
635         FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
636         return STATUS_SUCCESS;
637     }
638 
639     //
640     // Extract the nature of the read from the file object, and case on it
641     //
642 
643     TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &FcbOrDcb, &Ccb);
644 
645     NT_ASSERT( Vcb != NULL );
646 
647     //
648     //  Save callers who try to do cached IO to the raw volume from themselves.
649     //
650 
651     if (TypeOfOpen == UserVolumeOpen) {
652 
653         NonCachedIo = TRUE;
654     }
655 
656     NT_ASSERT(!(NonCachedIo == FALSE && TypeOfOpen == VirtualVolumeFile));
657 
658     //
659     // Collect interesting statistics.  The FLAG_USER_IO bit will indicate
660     // what type of io we're doing in the FatNonCachedIo function.
661     //
662 
663     if (PagingIo) {
664         CollectReadStats(Vcb, TypeOfOpen, ByteCount);
665 
666         if (TypeOfOpen == UserFileOpen) {
667             SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
668         } else {
669             ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
670         }
671     }
672 
673     NT_ASSERT(!FlagOn( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT ));
674 
675     //
676     //  Allocate if necessary and initialize a FAT_IO_CONTEXT block for
677     //  all non cached Io.  For synchronous Io we use stack storage,
678     //  otherwise we allocate pool.
679     //
680 
681     if (NonCachedIo) {
682 
683         if (IrpContext->FatIoContext == NULL) {
684 
685             if (!Wait) {
686 
687                 IrpContext->FatIoContext =
688                     FsRtlAllocatePoolWithTag( NonPagedPoolNx,
689                                               sizeof(FAT_IO_CONTEXT),
690                                               TAG_FAT_IO_CONTEXT );
691 
692             } else {
693 
694                 IrpContext->FatIoContext = &StackFatIoContext;
695 
696                 SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT );
697             }
698         }
699 
700         RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );
701 
702         if (Wait) {
703 
704             KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
705                                NotificationEvent,
706                                FALSE );
707 
708         } else {
709 
710             if (PagingIo) {
711 
712                 IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
713                     ExGetCurrentResourceThread();
714 
715             } else {
716 
717                 IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
718                         ((ULONG_PTR)IrpContext->FatIoContext) | 3;
719             }
720 
721             IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
722                 ByteCount;
723 
724             IrpContext->FatIoContext->Wait.Async.FileObject = FileObject;
725         }
726 
727     }
728 
729 
730     //
731     // These two cases correspond to either a general opened volume, ie.
732     // open ("a:"), or a read of the volume file (boot sector + fat(s))
733     //
734 
735     if ((TypeOfOpen == VirtualVolumeFile) ||
736         (TypeOfOpen == UserVolumeOpen)) {
737 
738         LBO StartingLbo;
739 
740         StartingLbo = StartingByte.QuadPart;
741 
742         DebugTrace(0, Dbg, "Type of read is User Volume or virtual volume file\n", 0);
743 
744         if (TypeOfOpen == UserVolumeOpen) {
745 
746             //
747             //  Verify that the volume for this handle is still valid
748             //
749 
750             //
751             //  Verify that the volume for this handle is still valid, permitting
752             //  operations to proceed on dismounted volumes via the handle which
753             //  performed the dismount.
754             //
755 
756             if (!FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT | CCB_FLAG_SENT_FORMAT_UNIT )) {
757 
758                 FatQuickVerifyVcb( IrpContext, Vcb );
759             }
760 
761             //
762             //  If the caller previously sent a format unit command, then we will allow
763             //  their read/write requests to ignore the verify flag on the device, since some
764             //  devices send a media change event after format unit, but we don't want to
765             //  process it yet since we're probably in the process of formatting the
766             //  media.
767             //
768 
769             if (FlagOn( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT )) {
770 
771                 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY );
772             }
773 
774             if (!FlagOn( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE )) {
775 
776                 (VOID)ExAcquireResourceExclusiveLite( &Vcb->Resource, TRUE );
777 
778                 _SEH2_TRY {
779 
780                     //
781                     //  If the volume isn't locked, flush it.
782                     //
783 
784                     if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
785 
786                         FatFlushVolume( IrpContext, Vcb, Flush );
787                     }
788 
789                 } _SEH2_FINALLY {
790 
791                     ExReleaseResourceLite( &Vcb->Resource );
792                 } _SEH2_END;
793 
794                 SetFlag( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE );
795             }
796 
797             if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) {
798 
799                 LBO VolumeSize;
800 
801                 //
802                 //  Make sure we don't try to read past end of volume,
803                 //  reducing the byte count if necessary.
804                 //
805 
806                 VolumeSize = (LBO) Vcb->Bpb.BytesPerSector *
807                              (Vcb->Bpb.Sectors != 0 ? Vcb->Bpb.Sectors :
808                                                       Vcb->Bpb.LargeSectors);
809 
810                 if (StartingLbo >= VolumeSize) {
811                     Irp->IoStatus.Information = 0;
812                     FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE );
813                     return STATUS_END_OF_FILE;
814                 }
815 
816                 if (ByteCount > VolumeSize - StartingLbo) {
817 
818                     ByteCount = RequestedByteCount = (ULONG) (VolumeSize - StartingLbo);
819 
820                     //
821                     //  For async reads we had set the byte count in the FatIoContext
822                     //  above, so fix that here.
823                     //
824 
825                     if (!Wait) {
826 
827                         IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
828                             ByteCount;
829                     }
830                 }
831             }
832 
833             //
834             //  For DASD we have to probe and lock the user's buffer
835             //
836 
837             FatLockUserBuffer( IrpContext, Irp, IoWriteAccess, ByteCount );
838 
839 
840         } else {
841 
842             //
843             //  Virtual volume file open -- increment performance counters.
844             //
845 
846             Vcb->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors].Common.MetaDataDiskReads += 1;
847 
848         }
849 
850         //
851         //  Read the data and wait for the results
852         //
853 
854         FatSingleAsync( IrpContext,
855                         Vcb,
856                         StartingLbo,
857                         ByteCount,
858                         Irp );
859 
860 #if (NTDDI_VERSION >= NTDDI_WIN8)
861 
862         //
863         //  Account for DASD Ios
864         //
865 
866         if (FatDiskAccountingEnabled) {
867 
868             PETHREAD ThreadIssuingIo = PsGetCurrentThread();
869 
870             PsUpdateDiskCounters( PsGetThreadProcess( ThreadIssuingIo ),
871                                   ByteCount,
872                                   0,
873                                   1,
874                                   0,
875                                   0 );
876         }
877 
878 #endif
879 
880         if (!Wait) {
881 
882             //
883             //  We, nor anybody else, need the IrpContext any more.
884             //
885 
886             IrpContext->FatIoContext = NULL;
887 
888             FatDeleteIrpContext( IrpContext );
889 
890             DebugTrace(-1, Dbg, "FatNonCachedIo -> STATUS_PENDING\n", 0);
891 
892             return STATUS_PENDING;
893         }
894 
895         FatWaitSync( IrpContext );
896 
897         //
898         //  If the call didn't succeed, raise the error status
899         //
900 
901         if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
902 
903             NT_ASSERT( KeGetCurrentThread() != Vcb->VerifyThread || Status != STATUS_VERIFY_REQUIRED );
904             FatNormalizeAndRaiseStatus( IrpContext, Status );
905         }
906 
907         //
908         //  Update the current file position
909         //
910 
911         if (SynchronousIo && !PagingIo) {
912             FileObject->CurrentByteOffset.QuadPart =
913                 StartingLbo + Irp->IoStatus.Information;
914         }
915 
916         DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", Status );
917 
918         FatCompleteRequest( IrpContext, Irp, Status );
919         return Status;
920     }
921 
922     //
923     //  At this point we know there is an Fcb/Dcb.
924     //
925 
926     NT_ASSERT( FcbOrDcb != NULL );
927 
928     //
929     //  Check for a non-zero high part offset
930     //
931 
932     if ( StartingByte.HighPart != 0 ) {
933 
934         Irp->IoStatus.Information = 0;
935         FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE );
936         return STATUS_END_OF_FILE;
937     }
938 
939     //
940     //  Use a try-finally to free Fcb/Dcb and buffers on the way out.
941     //
942 
943     _SEH2_TRY {
944 
945         //
946         // This case corresponds to a normal user read file.
947         //
948 
949         if ( TypeOfOpen == UserFileOpen
950             ) {
951 
952             ULONG FileSize;
953             ULONG ValidDataLength;
954 
955             DebugTrace(0, Dbg, "Type of read is user file open\n", 0);
956 
957             //
958             //  If this is a noncached transfer and is not a paging I/O, and
959             //  the file has a data section, then we will do a flush here
960             //  to avoid stale data problems.  Note that we must flush before
961             //  acquiring the Fcb shared since the write may try to acquire
962             //  it exclusive.
963             //
964 
965             if (!PagingIo && NonCachedIo
966 
967                     &&
968 
969                 (FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
970 
971                 IO_STATUS_BLOCK IoStatus = {0};
972 
973 #ifndef REDUCE_SYNCHRONIZATION
974                 if (!FatAcquireExclusiveFcb( IrpContext, FcbOrDcb )) {
975 
976                     try_return( PostIrp = TRUE );
977                 }
978 
979                 ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
980 #endif //REDUCE_SYNCHRONIZATION
981 
982                 CcFlushCache( FileObject->SectionObjectPointer,
983                               &StartingByte,
984                               ByteCount,
985                               &IoStatus );
986 
987 #ifndef REDUCE_SYNCHRONIZATION
988                 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
989                 FatReleaseFcb( IrpContext, FcbOrDcb );
990 #endif //REDUCE_SYNCHRONIZATION
991 
992                 if (!NT_SUCCESS( IoStatus.Status)) {
993 
994                     try_return( IoStatus.Status );
995                 }
996 
997 #ifndef REDUCE_SYNCHRONIZATION
998                 ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
999                 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
1000 #endif //REDUCE_SYNCHRONIZATION
1001             }
1002 
1003             //
1004             // We need shared access to the Fcb/Dcb before proceeding.
1005             //
1006 
1007             if ( PagingIo ) {
1008 
1009                 if (!ExAcquireResourceSharedLite( FcbOrDcb->Header.PagingIoResource,
1010                                                   TRUE )) {
1011 
1012                     DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %p shared without waiting\n", FcbOrDcb );
1013 
1014                     try_return( PostIrp = TRUE );
1015                 }
1016 
1017                 if (!Wait) {
1018 
1019                     IrpContext->FatIoContext->Wait.Async.Resource =
1020                         FcbOrDcb->Header.PagingIoResource;
1021                 }
1022 
1023             } else {
1024 
1025                 //
1026                 //  If this is async I/O, we will wait if there is an
1027                 //  exclusive waiter.
1028                 //
1029 
1030                 if (!Wait && NonCachedIo) {
1031 
1032                     if (!FatAcquireSharedFcbWaitForEx( IrpContext, FcbOrDcb )) {
1033 
1034                         DebugTrace( 0,
1035                                     Dbg,
1036                                     "Cannot acquire FcbOrDcb = %p shared without waiting\n",
1037                                     FcbOrDcb );
1038 
1039                         try_return( PostIrp = TRUE );
1040                     }
1041 
1042                     IrpContext->FatIoContext->Wait.Async.Resource =
1043                         FcbOrDcb->Header.Resource;
1044 
1045                 } else {
1046 
1047                     if (!FatAcquireSharedFcb( IrpContext, FcbOrDcb )) {
1048 
1049                         DebugTrace( 0,
1050                                     Dbg,
1051                                     "Cannot acquire FcbOrDcb = %p shared without waiting\n",
1052                                     FcbOrDcb );
1053 
1054                         try_return( PostIrp = TRUE );
1055                     }
1056                 }
1057             }
1058 
1059             FcbOrDcbAcquired = TRUE;
1060 
1061             //
1062             //  Make sure the FcbOrDcb is still good
1063             //
1064 
1065             FatVerifyFcb( IrpContext, FcbOrDcb );
1066 
1067             //
1068             //  We now check whether we can proceed based on the state of
1069             //  the file oplocks.
1070             //
1071 
1072             if (!PagingIo) {
1073 
1074                 Status = FsRtlCheckOplock( FatGetFcbOplock(FcbOrDcb),
1075                                            Irp,
1076                                            IrpContext,
1077                                            FatOplockComplete,
1078                                            FatPrePostIrp );
1079 
1080                 if (Status != STATUS_SUCCESS) {
1081 
1082                     OplockPostIrp = TRUE;
1083                     PostIrp = TRUE;
1084                     try_return( NOTHING );
1085                 }
1086 
1087                 //
1088                 //  Reset the flag indicating if Fast I/O is possible since the oplock
1089                 //  check could have broken existing (conflicting) oplocks.
1090                 //
1091 
1092                 FcbOrDcb->Header.IsFastIoPossible = FatIsFastIoPossible( FcbOrDcb );
1093 
1094                 //
1095                 // We have to check for read access according to the current
1096                 // state of the file locks, and set FileSize from the Fcb.
1097                 //
1098 
1099                 if (!PagingIo &&
1100                     !FsRtlCheckLockForReadAccess( &FcbOrDcb->Specific.Fcb.FileLock,
1101                                                   Irp )) {
1102 
1103                     try_return( Status = STATUS_FILE_LOCK_CONFLICT );
1104                 }
1105             }
1106 
1107             //
1108             //  Pick up our sizes and check/trim the IO.
1109             //
1110 
1111             FileSize = FcbOrDcb->Header.FileSize.LowPart;
1112             ValidDataLength = FcbOrDcb->Header.ValidDataLength.LowPart;
1113 
1114             //
1115             // If the read starts beyond End of File, return EOF.
1116             //
1117 
1118             if (StartingVbo >= FileSize) {
1119 
1120                 DebugTrace( 0, Dbg, "End of File\n", 0 );
1121 
1122                 try_return ( Status = STATUS_END_OF_FILE );
1123             }
1124 
1125             //
1126             //  If the read extends beyond EOF, truncate the read
1127             //
1128 
1129             if (ByteCount > FileSize - StartingVbo) {
1130 
1131                 ByteCount = RequestedByteCount = FileSize - StartingVbo;
1132 
1133                 if (NonCachedIo && !Wait) {
1134 
1135                     IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
1136                         RequestedByteCount;
1137 
1138                 }
1139             }
1140 
1141             //
1142             // HANDLE THE NON-CACHED CASE
1143             //
1144 
1145             if ( NonCachedIo ) {
1146 
1147                 ULONG SectorSize;
1148                 ULONG BytesToRead;
1149 
1150                 DebugTrace(0, Dbg, "Non cached read.\n", 0);
1151 
1152                 //
1153                 //  Get the sector size
1154                 //
1155 
1156                 SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
1157 
1158                 //
1159                 //  Start by zeroing any part of the read after Valid Data
1160                 //
1161 
1162                 if (ValidDataLength < FcbOrDcb->ValidDataToDisk) {
1163 
1164                     ValidDataLength = FcbOrDcb->ValidDataToDisk;
1165                 }
1166 
1167 
1168                 if ( StartingVbo + ByteCount > ValidDataLength ) {
1169 
1170                     SystemBuffer = FatMapUserBuffer( IrpContext, Irp );
1171 
1172                     if (StartingVbo < ValidDataLength) {
1173 
1174                         ULONG ZeroingOffset;
1175 
1176                         //
1177                         //  Now zero out the user's request sector aligned beyond
1178                         //  vdl.  We will handle the straddling sector at completion
1179                         //  time via the bytecount reduction which immediately
1180                         //  follows this check.
1181                         //
1182                         //  Note that we used to post in this case for async requests.
1183                         //  Note also that if the request was wholly beyond VDL that
1184                         //  we did not post, therefore this is consistent.  Synchronous
1185                         //  zeroing is fine for async requests.
1186                         //
1187 
1188                         ZeroingOffset = ((ValidDataLength - StartingVbo) + (SectorSize - 1))
1189                                                                         & ~(SectorSize - 1);
1190 
1191                         //
1192                         //  If the offset is at or above the byte count, no harm: just means
1193                         //  that the read ends in the last sector and the zeroing will be
1194                         //  done at completion.
1195                         //
1196 
1197                         if (ByteCount > ZeroingOffset) {
1198 
1199                             SafeZeroMemory( (PUCHAR) SystemBuffer + ZeroingOffset,
1200                                             ByteCount - ZeroingOffset);
1201 
1202                         }
1203 
1204                     } else {
1205 
1206                         //
1207                         //  All we have to do now is sit here and zero the
1208                         //  user's buffer, no reading is required.
1209                         //
1210 
1211                         SafeZeroMemory( (PUCHAR)SystemBuffer, ByteCount );
1212 
1213                         Irp->IoStatus.Information = ByteCount;
1214 
1215 
1216                         try_return ( Status = STATUS_SUCCESS );
1217                     }
1218                 }
1219 
1220 
1221                 //
1222                 //  Reduce the byte count to actually read if it extends beyond
1223                 //  Valid Data Length
1224                 //
1225 
1226                 ByteCount = (ValidDataLength - StartingVbo < ByteCount) ?
1227                              ValidDataLength - StartingVbo : ByteCount;
1228 
1229                 //
1230                 //  Round up to a sector boundary, and remember that if we are
1231                 //  reading extra bytes we will zero them out during completion.
1232                 //
1233 
1234                 BytesToRead = (ByteCount + (SectorSize - 1))
1235                                         & ~(SectorSize - 1);
1236 
1237                 //
1238                 //  Just to help alleviate confusion.  At this point:
1239                 //
1240                 //  RequestedByteCount - is the number of bytes originally
1241                 //                       taken from the Irp, but constrained
1242                 //                       to filesize.
1243                 //
1244                 //  ByteCount -          is RequestedByteCount constrained to
1245                 //                       ValidDataLength.
1246                 //
1247                 //  BytesToRead -        is ByteCount rounded up to sector
1248                 //                       boundry.  This is the number of bytes
1249                 //                       that we must physically read.
1250                 //
1251 
1252                 //
1253                 //  If this request is not properly aligned, or extending
1254                 //  to a sector boundary would overflow the buffer, send it off
1255                 //  on a special-case path.
1256                 //
1257 
1258                 if ( (StartingVbo & (SectorSize - 1)) ||
1259                      (BytesToRead > IrpSp->Parameters.Read.Length) ) {
1260 
1261                     //
1262                     //  If we can't wait, we must post this.
1263                     //
1264 
1265                     if (!Wait) {
1266 
1267                         try_return( PostIrp = TRUE );
1268                     }
1269 
1270                     //
1271                     //  Do the physical read
1272                     //
1273 
1274                     FatNonCachedNonAlignedRead( IrpContext,
1275                                                 Irp,
1276                                                 FcbOrDcb,
1277                                                 StartingVbo,
1278                                                 ByteCount );
1279 
1280                     //
1281                     //  Set BytesToRead to ByteCount to satify the following ASSERT.
1282                     //
1283 
1284 #ifdef _MSC_VER
1285 #pragma prefast( suppress:28931, "needed for debug build" )
1286 #endif
1287                     BytesToRead = ByteCount;
1288 
1289                 } else {
1290 
1291                     //
1292                     //  Perform the actual IO
1293                     //
1294 
1295 
1296                     if (FatNonCachedIo( IrpContext,
1297                                         Irp,
1298                                         FcbOrDcb,
1299                                         StartingVbo,
1300                                         BytesToRead,
1301                                         ByteCount,
1302                                         0) == STATUS_PENDING) {
1303 
1304 
1305                         IrpContext->FatIoContext = NULL;
1306 
1307                         Irp = NULL;
1308 
1309                         try_return( Status = STATUS_PENDING );
1310                     }
1311                 }
1312 
1313                 //
1314                 //  If the call didn't succeed, raise the error status
1315                 //
1316 
1317                 if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
1318 
1319                     NT_ASSERT( KeGetCurrentThread() != Vcb->VerifyThread || Status != STATUS_VERIFY_REQUIRED );
1320                     FatNormalizeAndRaiseStatus( IrpContext, Status );
1321 
1322                 } else {
1323 
1324                     //
1325                     //  Else set the Irp information field to reflect the
1326                     //  entire desired read.
1327                     //
1328 
1329                     NT_ASSERT( Irp->IoStatus.Information == BytesToRead );
1330 
1331                     Irp->IoStatus.Information = RequestedByteCount;
1332                 }
1333 
1334                 //
1335                 // The transfer is complete.
1336                 //
1337 
1338                 try_return( Status );
1339 
1340             }   // if No Intermediate Buffering
1341 
1342 
1343             //
1344             // HANDLE CACHED CASE
1345             //
1346 
1347             else {
1348 
1349                 //
1350                 // We delay setting up the file cache until now, in case the
1351                 // caller never does any I/O to the file, and thus
1352                 // FileObject->PrivateCacheMap == NULL.
1353                 //
1354 
1355                 if (FileObject->PrivateCacheMap == NULL) {
1356 
1357                     DebugTrace(0, Dbg, "Initialize cache mapping.\n", 0);
1358 
1359                     //
1360                     //  Get the file allocation size, and if it is less than
1361                     //  the file size, raise file corrupt error.
1362                     //
1363 
1364                     if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
1365 
1366                         FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
1367                     }
1368 
1369                     if ( FileSize > FcbOrDcb->Header.AllocationSize.LowPart ) {
1370 
1371                         FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
1372 
1373                         FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
1374                     }
1375 
1376                     //
1377                     //  Now initialize the cache map.
1378                     //
1379 
1380                     FatInitializeCacheMap( FileObject,
1381                                            (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize,
1382                                            FALSE,
1383                                            &FatData.CacheManagerCallbacks,
1384                                            FcbOrDcb );
1385 
1386                     CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY );
1387                 }
1388 
1389 
1390                 //
1391                 // DO A NORMAL CACHED READ, if the MDL bit is not set,
1392                 //
1393 
1394                 DebugTrace(0, Dbg, "Cached read.\n", 0);
1395 
1396                 if (!FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
1397 
1398                     //
1399                     //  Get hold of the user's buffer.
1400                     //
1401 
1402                     SystemBuffer = FatMapUserBuffer( IrpContext, Irp );
1403 
1404                     //
1405                     // Now try to do the copy.
1406                     //
1407 
1408 #if (NTDDI_VERSION >= NTDDI_WIN8)
1409                     if (!CcCopyReadEx( FileObject,
1410                                        &StartingByte,
1411                                        ByteCount,
1412                                        Wait,
1413                                        SystemBuffer,
1414                                        &Irp->IoStatus,
1415                                        Irp->Tail.Overlay.Thread )) {
1416 #else
1417                     if (!CcCopyRead( FileObject,
1418                                      &StartingByte,
1419                                      ByteCount,
1420                                      Wait,
1421                                      SystemBuffer,
1422                                      &Irp->IoStatus )) {
1423 #endif
1424 
1425                         DebugTrace( 0, Dbg, "Cached Read could not wait\n", 0 );
1426 
1427                         try_return( PostIrp = TRUE );
1428                     }
1429 
1430                     Status = Irp->IoStatus.Status;
1431 
1432                     NT_ASSERT( NT_SUCCESS( Status ));
1433 
1434                     try_return( Status );
1435                 }
1436 
1437 
1438                 //
1439                 //  HANDLE A MDL READ
1440                 //
1441 
1442                 else {
1443 
1444                     DebugTrace(0, Dbg, "MDL read.\n", 0);
1445 
1446                     NT_ASSERT( Wait );
1447 
1448                     CcMdlRead( FileObject,
1449                                &StartingByte,
1450                                ByteCount,
1451                                &Irp->MdlAddress,
1452                                &Irp->IoStatus );
1453 
1454                     Status = Irp->IoStatus.Status;
1455 
1456                     NT_ASSERT( NT_SUCCESS( Status ));
1457 
1458                     try_return( Status );
1459                 }
1460             }
1461         }
1462 
1463         //
1464         //  These cases correspond to a system read directory file or
1465         //  ea file.
1466         //
1467 
1468         if (( TypeOfOpen == DirectoryFile ) || ( TypeOfOpen == EaFile)
1469             ) {
1470 
1471             ULONG SectorSize;
1472 
1473 
1474 #if FASTFATDBG
1475             if ( TypeOfOpen == DirectoryFile ) {
1476                 DebugTrace(0, Dbg, "Type of read is directoryfile\n", 0);
1477             } else if ( TypeOfOpen == EaFile) {
1478                 DebugTrace(0, Dbg, "Type of read is eafile\n", 0);
1479             }
1480 
1481 #endif
1482 
1483             //
1484             //  For the noncached case, assert that everything is sector
1485             //  alligned.
1486             //
1487 
1488 #ifdef _MSC_VER
1489 #pragma prefast( suppress:28931, "needed for debug build" )
1490 #endif
1491             SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
1492 
1493             //
1494             //  We make several assumptions about these two types of files.
1495             //  Make sure all of them are true.
1496             //
1497 
1498             NT_ASSERT( NonCachedIo && PagingIo );
1499             NT_ASSERT( ((StartingVbo | ByteCount) & (SectorSize - 1)) == 0 );
1500 
1501 
1502                 //
1503                 //  These calls must allways be within the allocation size
1504                 //
1505 
1506                 if (StartingVbo >= FcbOrDcb->Header.AllocationSize.LowPart) {
1507 
1508                     DebugTrace( 0, Dbg, "PagingIo dirent started beyond EOF.\n", 0 );
1509 
1510                     Irp->IoStatus.Information = 0;
1511 
1512                     try_return( Status = STATUS_SUCCESS );
1513                 }
1514 
1515                 if ( StartingVbo + ByteCount > FcbOrDcb->Header.AllocationSize.LowPart ) {
1516 
1517                     DebugTrace( 0, Dbg, "PagingIo dirent extending beyond EOF.\n", 0 );
1518                     ByteCount = FcbOrDcb->Header.AllocationSize.LowPart - StartingVbo;
1519                 }
1520 
1521 
1522             //
1523             //  Perform the actual IO
1524             //
1525 
1526             if (FatNonCachedIo( IrpContext,
1527                                 Irp,
1528                                 FcbOrDcb,
1529                                 StartingVbo,
1530                                 ByteCount,
1531                                 ByteCount,
1532                                 0 ) == STATUS_PENDING) {
1533 
1534                 IrpContext->FatIoContext = NULL;
1535 
1536                 Irp = NULL;
1537 
1538                 try_return( Status = STATUS_PENDING );
1539             }
1540 
1541             //
1542             //  If the call didn't succeed, raise the error status
1543             //
1544 
1545             if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
1546 
1547                 NT_ASSERT( KeGetCurrentThread() != Vcb->VerifyThread || Status != STATUS_VERIFY_REQUIRED );
1548                 FatNormalizeAndRaiseStatus( IrpContext, Status );
1549 
1550             } else {
1551 
1552                 NT_ASSERT( Irp->IoStatus.Information == ByteCount );
1553             }
1554 
1555             try_return( Status );
1556         }
1557 
1558         //
1559         // This is the case of a user who openned a directory. No reading is
1560         // allowed.
1561         //
1562 
1563         if ( TypeOfOpen == UserDirectoryOpen ) {
1564 
1565             DebugTrace( 0, Dbg, "CommonRead -> STATUS_INVALID_PARAMETER\n", 0);
1566 
1567             try_return( Status = STATUS_INVALID_PARAMETER );
1568         }
1569 
1570         //
1571         //  If we get this far, something really serious is wrong.
1572         //
1573 
1574         DebugDump("Illegal TypeOfOpen\n", 0, FcbOrDcb );
1575 
1576 #ifdef _MSC_VER
1577 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
1578 #endif
1579         FatBugCheck( TypeOfOpen, (ULONG_PTR) FcbOrDcb, 0 );
1580 
1581     try_exit: NOTHING;
1582 
1583         //
1584         //  If the request was not posted and there's an Irp, deal with it.
1585         //
1586 
1587         if ( Irp ) {
1588 
1589             if ( !PostIrp ) {
1590 
1591                 ULONG ActualBytesRead;
1592 
1593                 DebugTrace( 0, Dbg, "Completing request with status = %08lx\n",
1594                             Status);
1595 
1596                 DebugTrace( 0, Dbg, "                   Information = %08lx\n",
1597                             Irp->IoStatus.Information);
1598 
1599                 //
1600                 //  Record the total number of bytes actually read
1601                 //
1602 
1603                 ActualBytesRead = (ULONG)Irp->IoStatus.Information;
1604 
1605                 //
1606                 //  If the file was opened for Synchronous IO, update the current
1607                 //  file position.
1608                 //
1609 
1610                 if (SynchronousIo && !PagingIo) {
1611 
1612                     FileObject->CurrentByteOffset.LowPart =
1613                          StartingVbo + (NT_ERROR( Status ) ? 0 : ActualBytesRead);
1614                 }
1615 
1616                 //
1617                 //  If this was not PagingIo, mark that the last access
1618                 //  time on the dirent needs to be updated on close.
1619                 //
1620 
1621                 if (NT_SUCCESS(Status) && !PagingIo) {
1622 
1623                     SetFlag( FileObject->Flags, FO_FILE_FAST_IO_READ );
1624                 }
1625 
1626             } else {
1627 
1628                 DebugTrace( 0, Dbg, "Passing request to Fsp\n", 0 );
1629 
1630                 if (!OplockPostIrp) {
1631 
1632                     Status = FatFsdPostRequest( IrpContext, Irp );
1633                 }
1634             }
1635         }
1636 
1637     } _SEH2_FINALLY {
1638 
1639         DebugUnwind( FatCommonRead );
1640 
1641         //
1642         // If the FcbOrDcb has been acquired, release it.
1643         //
1644 
1645         if (FcbOrDcbAcquired && Irp) {
1646 
1647             if ( PagingIo ) {
1648 
1649                 ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
1650 
1651             } else {
1652 
1653                 FatReleaseFcb( NULL, FcbOrDcb );
1654             }
1655         }
1656 
1657         //
1658         //  Complete the request if we didn't post it and no exception
1659         //
1660         //  Note that FatCompleteRequest does the right thing if either
1661         //  IrpContext or Irp are NULL
1662         //
1663 
1664         if (!PostIrp) {
1665 
1666             //
1667             //  If we had a stack io context, we have to make sure the contents
1668             //  are cleaned up before we leave.
1669             //
1670             //  At present with zero mdls, this will only really happen on exceptional
1671             //  termination where we failed to dispatch the IO. Cleanup of zero mdls
1672             //  normally occurs during completion, but when we bail we must make sure
1673             //  the cleanup occurs here or the fatiocontext will go out of scope.
1674             //
1675             //  If the operation was posted, cleanup occured there.
1676             //
1677 
1678             if (FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) {
1679 
1680                 if (IrpContext->FatIoContext->ZeroMdl) {
1681                     IoFreeMdl( IrpContext->FatIoContext->ZeroMdl );
1682                 }
1683 
1684                 ClearFlag(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT);
1685                 IrpContext->FatIoContext = NULL;
1686             }
1687 
1688             if (!_SEH2_AbnormalTermination()) {
1689 
1690                 FatCompleteRequest( IrpContext, Irp, Status );
1691             }
1692         }
1693 
1694         DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", Status );
1695     } _SEH2_END;
1696 
1697     return Status;
1698 }
1699 
1700 //
1701 //  Local support routine
1702 //
1703 
1704 VOID
1705 NTAPI
1706 FatOverflowPagingFileRead (
1707     IN PVOID Context,
1708     IN PKEVENT Event
1709     )
1710 
1711 /*++
1712 
1713 Routine Description:
1714 
1715     The routine simply call FatPagingFileIo.  It is invoked in cases when
1716     there was not enough stack space to perform the pagefault in the
1717     original thread.  It is also responsible for freeing the packet pool.
1718 
1719 Arguments:
1720 
1721     Irp - Supplies the Irp being processed
1722 
1723     Fcb - Supplies the paging file Fcb, since we have it handy.
1724 
1725 Return Value:
1726 
1727     VOID
1728 
1729 --*/
1730 
1731 {
1732     PPAGING_FILE_OVERFLOW_PACKET Packet = Context;
1733 
1734     FatPagingFileIo( Packet->Irp, Packet->Fcb );
1735 
1736     //
1737     //  Set the stack overflow item's event to tell the original
1738     //  thread that we're done.
1739     //
1740 
1741     KeSetEvent( Event, 0, FALSE );
1742 
1743     return;
1744 }
1745 
1746 
1747 
1748