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)
_Function_class_(DRIVER_DISPATCH)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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