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