Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1652 lines
45 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. Read.c
  5. Abstract:
  6. This module implements the File Read routine for Read called by the
  7. dispatch driver.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. David Goebel [DavidGoe] 28-Feb-1991
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "FatProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (FAT_BUG_CHECK_READ)
  19. //
  20. // The local debug trace level
  21. //
  22. #define Dbg (DEBUG_TRACE_READ)
  23. //
  24. // Define stack overflow read threshhold. For the x86 we'll use a smaller
  25. // threshold than for a risc platform.
  26. //
  27. // Empirically, the limit is a result of the (large) amount of stack
  28. // neccesary to throw an exception.
  29. //
  30. #if defined(_M_IX86)
  31. #define OVERFLOW_READ_THRESHHOLD (0xE00)
  32. #else
  33. #define OVERFLOW_READ_THRESHHOLD (0x1000)
  34. #endif // defined(_M_IX86)
  35. //
  36. // The following procedures handles read stack overflow operations.
  37. //
  38. VOID
  39. FatStackOverflowRead (
  40. IN PVOID Context,
  41. IN PKEVENT Event
  42. );
  43. NTSTATUS
  44. FatPostStackOverflowRead (
  45. IN PIRP_CONTEXT IrpContext,
  46. IN PIRP Irp,
  47. IN PFCB Fcb
  48. );
  49. VOID
  50. FatOverflowPagingFileRead (
  51. IN PVOID Context,
  52. IN PKEVENT Event
  53. );
  54. //
  55. // VOID
  56. // SafeZeroMemory (
  57. // IN PUCHAR At,
  58. // IN ULONG ByteCount
  59. // );
  60. //
  61. //
  62. // This macro just puts a nice little try-except around RtlZeroMemory
  63. //
  64. #define SafeZeroMemory(AT,BYTE_COUNT) { \
  65. try { \
  66. RtlZeroMemory((AT), (BYTE_COUNT)); \
  67. } except(EXCEPTION_EXECUTE_HANDLER) { \
  68. FatRaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER ); \
  69. } \
  70. }
  71. //
  72. // Macro to increment appropriate performance counters.
  73. //
  74. #define CollectReadStats(VCB,OPEN_TYPE,BYTE_COUNT) { \
  75. PFILESYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()].Common; \
  76. if (((OPEN_TYPE) == UserFileOpen)) { \
  77. Stats->UserFileReads += 1; \
  78. Stats->UserFileReadBytes += (ULONG)(BYTE_COUNT); \
  79. } else if (((OPEN_TYPE) == VirtualVolumeFile || ((OPEN_TYPE) == DirectoryFile))) { \
  80. Stats->MetaDataReads += 1; \
  81. Stats->MetaDataReadBytes += (ULONG)(BYTE_COUNT); \
  82. } \
  83. }
  84. #ifdef ALLOC_PRAGMA
  85. #pragma alloc_text(PAGE, FatStackOverflowRead)
  86. #pragma alloc_text(PAGE, FatPostStackOverflowRead)
  87. #pragma alloc_text(PAGE, FatCommonRead)
  88. #endif
  89. NTSTATUS
  90. FatFsdRead (
  91. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  92. IN PIRP Irp
  93. )
  94. /*++
  95. Routine Description:
  96. This is the driver entry to the common read routine for NtReadFile calls.
  97. For synchronous requests, the CommonRead is called with Wait == TRUE,
  98. which means the request will always be completed in the current thread,
  99. and never passed to the Fsp. If it is not a synchronous request,
  100. CommonRead is called with Wait == FALSE, which means the request
  101. will be passed to the Fsp only if there is a need to block.
  102. Arguments:
  103. VolumeDeviceObject - Supplies the volume device object where the
  104. file being Read exists
  105. Irp - Supplies the Irp being processed
  106. Return Value:
  107. NTSTATUS - The FSD status for the IRP
  108. --*/
  109. {
  110. PFCB Fcb;
  111. NTSTATUS Status;
  112. PIRP_CONTEXT IrpContext = NULL;
  113. BOOLEAN TopLevel;
  114. DebugTrace(+1, Dbg, "FatFsdRead\n", 0);
  115. //
  116. // Call the common Read routine, with blocking allowed if synchronous
  117. //
  118. FsRtlEnterFileSystem();
  119. //
  120. // We are first going to do a quick check for paging file IO. Since this
  121. // is a fast path, we must replicate the check for the fsdo.
  122. //
  123. if (!FatDeviceIsFatFsdo( IoGetCurrentIrpStackLocation(Irp)->DeviceObject)) {
  124. Fcb = (PFCB)(IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext);
  125. if ((NodeType(Fcb) == FAT_NTC_FCB) &&
  126. FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
  127. //
  128. // Do the usual STATUS_PENDING things.
  129. //
  130. IoMarkIrpPending( Irp );
  131. //
  132. // If there is not enough stack to do this read, then post this
  133. // read to the overflow queue.
  134. //
  135. if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) {
  136. KEVENT Event;
  137. PAGING_FILE_OVERFLOW_PACKET Packet;
  138. Packet.Irp = Irp;
  139. Packet.Fcb = Fcb;
  140. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  141. FsRtlPostPagingFileStackOverflow( &Packet, &Event, FatOverflowPagingFileRead );
  142. //
  143. // And wait for the worker thread to complete the item
  144. //
  145. (VOID) KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
  146. } else {
  147. //
  148. // Perform the actual IO, it will be completed when the io finishes.
  149. //
  150. FatPagingFileIo( Irp, Fcb );
  151. }
  152. FsRtlExitFileSystem();
  153. return STATUS_PENDING;
  154. }
  155. }
  156. try {
  157. TopLevel = FatIsIrpTopLevel( Irp );
  158. IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
  159. //
  160. // If this is an Mdl complete request, don't go through
  161. // common read.
  162. //
  163. if ( FlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE) ) {
  164. DebugTrace(0, Dbg, "Calling FatCompleteMdl\n", 0 );
  165. try_return( Status = FatCompleteMdl( IrpContext, Irp ));
  166. }
  167. //
  168. // Check if we have enough stack space to process this request. If there
  169. // isn't enough then we will pass the request off to the stack overflow thread.
  170. //
  171. if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) {
  172. DebugTrace(0, Dbg, "Passing StackOverflowRead off\n", 0 );
  173. try_return( Status = FatPostStackOverflowRead( IrpContext, Irp, Fcb ) );
  174. }
  175. Status = FatCommonRead( IrpContext, Irp );
  176. try_exit: NOTHING;
  177. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  178. //
  179. // We had some trouble trying to perform the requested
  180. // operation, so we'll abort the I/O request with
  181. // the error status that we get back from the
  182. // execption code
  183. //
  184. Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
  185. }
  186. if (TopLevel) { IoSetTopLevelIrp( NULL ); }
  187. FsRtlExitFileSystem();
  188. //
  189. // And return to our caller
  190. //
  191. DebugTrace(-1, Dbg, "FatFsdRead -> %08lx\n", Status);
  192. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  193. return Status;
  194. }
  195. //
  196. // Internal support routine
  197. //
  198. NTSTATUS
  199. FatPostStackOverflowRead (
  200. IN PIRP_CONTEXT IrpContext,
  201. IN PIRP Irp,
  202. IN PFCB Fcb
  203. )
  204. /*++
  205. Routine Description:
  206. This routine posts a read request that could not be processed by
  207. the fsp thread because of stack overflow potential.
  208. Arguments:
  209. Irp - Supplies the request to process.
  210. Fcb - Supplies the file.
  211. Return Value:
  212. STATUS_PENDING.
  213. --*/
  214. {
  215. KEVENT Event;
  216. PERESOURCE Resource;
  217. PVCB Vcb;
  218. DebugTrace(0, Dbg, "Getting too close to stack limit pass request to Fsp\n", 0 );
  219. //
  220. // Initialize an event and get shared on the resource we will
  221. // be later using the common read.
  222. //
  223. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  224. //
  225. // Preacquire the resource the read path will require so we know the
  226. // worker thread can proceed without waiting.
  227. //
  228. if (FlagOn(Irp->Flags, IRP_PAGING_IO) && (Fcb->Header.PagingIoResource != NULL)) {
  229. Resource = Fcb->Header.PagingIoResource;
  230. } else {
  231. Resource = Fcb->Header.Resource;
  232. }
  233. //
  234. // If there are no resources assodicated with the file (case: the virtual
  235. // volume file), it is OK. No resources will be acquired on the other side
  236. // as well.
  237. //
  238. if (Resource) {
  239. ExAcquireResourceSharedLite( Resource, TRUE );
  240. }
  241. if (NodeType( Fcb ) == FAT_NTC_VCB) {
  242. Vcb = (PVCB) Fcb;
  243. } else {
  244. Vcb = Fcb->Vcb;
  245. }
  246. try {
  247. //
  248. // Make the Irp just like a regular post request and
  249. // then send the Irp to the special overflow thread.
  250. // After the post we will wait for the stack overflow
  251. // read routine to set the event that indicates we can
  252. // now release the scb resource and return.
  253. //
  254. FatPrePostIrp( IrpContext, Irp );
  255. //
  256. // If this read is the result of a verify, we have to
  257. // tell the overflow read routne to temporarily
  258. // hijack the Vcb->VerifyThread field so that reads
  259. // can go through.
  260. //
  261. if (Vcb->VerifyThread == KeGetCurrentThread()) {
  262. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ);
  263. }
  264. FsRtlPostStackOverflow( IrpContext, &Event, FatStackOverflowRead );
  265. //
  266. // And wait for the worker thread to complete the item
  267. //
  268. KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
  269. } finally {
  270. if (Resource) {
  271. ExReleaseResourceLite( Resource );
  272. }
  273. }
  274. return STATUS_PENDING;
  275. }
  276. //
  277. // Internal support routine
  278. //
  279. VOID
  280. FatStackOverflowRead (
  281. IN PVOID Context,
  282. IN PKEVENT Event
  283. )
  284. /*++
  285. Routine Description:
  286. This routine processes a read request that could not be processed by
  287. the fsp thread because of stack overflow potential.
  288. Arguments:
  289. Context - Supplies the IrpContext being processed
  290. Event - Supplies the event to be signaled when we are done processing this
  291. request.
  292. Return Value:
  293. None.
  294. --*/
  295. {
  296. PIRP_CONTEXT IrpContext = Context;
  297. PKTHREAD SavedVerifyThread = NULL;
  298. PVCB Vcb;
  299. //
  300. // Make it now look like we can wait for I/O to complete
  301. //
  302. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  303. //
  304. // If this read was as the result of a verify we have to fake out the
  305. // the Vcb->VerifyThread field.
  306. //
  307. if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) {
  308. PFCB Fcb = (PFCB)IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->
  309. FileObject->FsContext;
  310. if (NodeType( Fcb ) == FAT_NTC_VCB) {
  311. Vcb = (PVCB) Fcb;
  312. } else {
  313. Vcb = Fcb->Vcb;
  314. }
  315. ASSERT( Vcb->VerifyThread != NULL );
  316. SavedVerifyThread = Vcb->VerifyThread;
  317. Vcb->VerifyThread = KeGetCurrentThread();
  318. }
  319. //
  320. // Do the read operation protected by a try-except clause
  321. //
  322. try {
  323. (VOID) FatCommonRead( IrpContext, IrpContext->OriginatingIrp );
  324. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  325. NTSTATUS ExceptionCode;
  326. //
  327. // We had some trouble trying to perform the requested
  328. // operation, so we'll abort the I/O request with
  329. // the error status that we get back from the
  330. // execption code
  331. //
  332. ExceptionCode = GetExceptionCode();
  333. if (ExceptionCode == STATUS_FILE_DELETED) {
  334. IrpContext->ExceptionStatus = ExceptionCode = STATUS_END_OF_FILE;
  335. IrpContext->OriginatingIrp->IoStatus.Information = 0;
  336. }
  337. (VOID) FatProcessException( IrpContext, IrpContext->OriginatingIrp, ExceptionCode );
  338. }
  339. //
  340. // Restore the original VerifyVolumeThread
  341. //
  342. if (SavedVerifyThread != NULL) {
  343. ASSERT( Vcb->VerifyThread == KeGetCurrentThread() );
  344. Vcb->VerifyThread = SavedVerifyThread;
  345. }
  346. //
  347. // Set the stack overflow item's event to tell the original
  348. // thread that we're done.
  349. //
  350. KeSetEvent( Event, 0, FALSE );
  351. }
  352. NTSTATUS
  353. FatCommonRead (
  354. IN PIRP_CONTEXT IrpContext,
  355. IN PIRP Irp
  356. )
  357. /*++
  358. Routine Description:
  359. This is the common read routine for NtReadFile, called from both
  360. the Fsd, or from the Fsp if a request could not be completed without
  361. blocking in the Fsd. This routine has no code where it determines
  362. whether it is running in the Fsd or Fsp. Instead, its actions are
  363. conditionalized by the Wait input parameter, which determines whether
  364. it is allowed to block or not. If a blocking condition is encountered
  365. with Wait == FALSE, however, the request is posted to the Fsp, who
  366. always calls with WAIT == TRUE.
  367. Arguments:
  368. Irp - Supplies the Irp to process
  369. Return Value:
  370. NTSTATUS - The return status for the operation
  371. --*/
  372. {
  373. PVCB Vcb;
  374. PFCB FcbOrDcb;
  375. PCCB Ccb;
  376. VBO StartingVbo;
  377. ULONG ByteCount;
  378. ULONG RequestedByteCount;
  379. PIO_STACK_LOCATION IrpSp;
  380. PFILE_OBJECT FileObject;
  381. TYPE_OF_OPEN TypeOfOpen;
  382. BOOLEAN PostIrp = FALSE;
  383. BOOLEAN OplockPostIrp = FALSE;
  384. BOOLEAN FcbOrDcbAcquired = FALSE;
  385. BOOLEAN Wait;
  386. BOOLEAN PagingIo;
  387. BOOLEAN NonCachedIo;
  388. BOOLEAN SynchronousIo;
  389. NTSTATUS Status;
  390. FAT_IO_CONTEXT StackFatIoContext;
  391. //
  392. // A system buffer is only used if we have to access the
  393. // buffer directly from the Fsp to clear a portion or to
  394. // do a synchronous I/O, or a cached transfer. It is
  395. // possible that our caller may have already mapped a
  396. // system buffer, in which case we must remember this so
  397. // we do not unmap it on the way out.
  398. //
  399. PVOID SystemBuffer = NULL;
  400. LARGE_INTEGER StartingByte;
  401. //
  402. // Get current Irp stack location.
  403. //
  404. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  405. FileObject = IrpSp->FileObject;
  406. //
  407. // Initialize the appropriate local variables.
  408. //
  409. Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
  410. PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
  411. NonCachedIo = BooleanFlagOn(Irp->Flags,IRP_NOCACHE);
  412. SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
  413. DebugTrace(+1, Dbg, "CommonRead\n", 0);
  414. DebugTrace( 0, Dbg, " Irp = %8lx\n", Irp);
  415. DebugTrace( 0, Dbg, " ->ByteCount = %8lx\n", IrpSp->Parameters.Read.Length);
  416. DebugTrace( 0, Dbg, " ->ByteOffset.LowPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.LowPart);
  417. DebugTrace( 0, Dbg, " ->ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.HighPart);
  418. //
  419. // Extract starting Vbo and offset.
  420. //
  421. StartingByte = IrpSp->Parameters.Read.ByteOffset;
  422. StartingVbo = StartingByte.LowPart;
  423. ByteCount = IrpSp->Parameters.Read.Length;
  424. RequestedByteCount = ByteCount;
  425. //
  426. // Check for a null request, and return immediately
  427. //
  428. if (ByteCount == 0) {
  429. Irp->IoStatus.Information = 0;
  430. FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  431. return STATUS_SUCCESS;
  432. }
  433. //
  434. // Extract the nature of the read from the file object, and case on it
  435. //
  436. TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &FcbOrDcb, &Ccb);
  437. ASSERT( Vcb != NULL );
  438. //
  439. // Save callers who try to do cached IO to the raw volume from themselves.
  440. //
  441. if (TypeOfOpen == UserVolumeOpen) {
  442. NonCachedIo = TRUE;
  443. }
  444. ASSERT(!(NonCachedIo == FALSE && TypeOfOpen == VirtualVolumeFile));
  445. //
  446. // Collect interesting statistics. The FLAG_USER_IO bit will indicate
  447. // what type of io we're doing in the FatNonCachedIo function.
  448. //
  449. if (PagingIo) {
  450. CollectReadStats(Vcb, TypeOfOpen, ByteCount);
  451. if (TypeOfOpen == UserFileOpen) {
  452. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
  453. } else {
  454. ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
  455. }
  456. }
  457. ASSERT(!FlagOn( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT ));
  458. //
  459. // Allocate if necessary and initialize a FAT_IO_CONTEXT block for
  460. // all non cached Io. For synchronous Io we use stack storage,
  461. // otherwise we allocate pool.
  462. //
  463. if (NonCachedIo) {
  464. if (IrpContext->FatIoContext == NULL) {
  465. if (!Wait) {
  466. IrpContext->FatIoContext =
  467. FsRtlAllocatePoolWithTag( NonPagedPool,
  468. sizeof(FAT_IO_CONTEXT),
  469. TAG_FAT_IO_CONTEXT );
  470. } else {
  471. IrpContext->FatIoContext = &StackFatIoContext;
  472. SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT );
  473. }
  474. }
  475. RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );
  476. if (Wait) {
  477. KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
  478. NotificationEvent,
  479. FALSE );
  480. } else {
  481. IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
  482. ExGetCurrentResourceThread();
  483. IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
  484. ByteCount;
  485. IrpContext->FatIoContext->Wait.Async.FileObject = FileObject;
  486. }
  487. }
  488. //
  489. // These two cases correspond to either a general opened volume, ie.
  490. // open ("a:"), or a read of the volume file (boot sector + fat(s))
  491. //
  492. if ((TypeOfOpen == VirtualVolumeFile) ||
  493. (TypeOfOpen == UserVolumeOpen)) {
  494. LBO StartingLbo;
  495. StartingLbo = StartingByte.QuadPart;
  496. DebugTrace(0, Dbg, "Type of read is User Volume or virtual volume file\n", 0);
  497. if (TypeOfOpen == UserVolumeOpen) {
  498. //
  499. // Verify that the volume for this handle is still valid
  500. //
  501. //
  502. // Verify that the volume for this handle is still valid, permitting
  503. // operations to proceed on dismounted volumes via the handle which
  504. // performed the dismount.
  505. //
  506. if (!FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT )) {
  507. FatQuickVerifyVcb( IrpContext, Vcb );
  508. }
  509. if (!FlagOn( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE )) {
  510. (VOID)ExAcquireResourceExclusiveLite( &Vcb->Resource, TRUE );
  511. try {
  512. //
  513. // If the volume isn't locked, flush it.
  514. //
  515. if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
  516. FatFlushVolume( IrpContext, Vcb, Flush );
  517. }
  518. } finally {
  519. ExReleaseResourceLite( &Vcb->Resource );
  520. }
  521. SetFlag( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE );
  522. }
  523. if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) {
  524. LBO VolumeSize;
  525. //
  526. // Make sure we don't try to read past end of volume,
  527. // reducing the byte count if necessary.
  528. //
  529. VolumeSize = (LBO) Vcb->Bpb.BytesPerSector *
  530. (Vcb->Bpb.Sectors != 0 ? Vcb->Bpb.Sectors :
  531. Vcb->Bpb.LargeSectors);
  532. if (StartingLbo >= VolumeSize) {
  533. Irp->IoStatus.Information = 0;
  534. FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE );
  535. return STATUS_END_OF_FILE;
  536. }
  537. if (ByteCount > VolumeSize - StartingLbo) {
  538. ByteCount = RequestedByteCount = (ULONG) (VolumeSize - StartingLbo);
  539. //
  540. // For async reads we had set the byte count in the FatIoContext
  541. // above, so fix that here.
  542. //
  543. if (!Wait) {
  544. IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
  545. ByteCount;
  546. }
  547. }
  548. }
  549. //
  550. // For DASD we have to probe and lock the user's buffer
  551. //
  552. FatLockUserBuffer( IrpContext, Irp, IoWriteAccess, ByteCount );
  553. } else {
  554. //
  555. // Virtual volume file open -- increment performance counters.
  556. //
  557. Vcb->Statistics[KeGetCurrentProcessorNumber()].Common.MetaDataDiskReads += 1;
  558. }
  559. //
  560. // Read the data and wait for the results
  561. //
  562. FatSingleAsync( IrpContext,
  563. Vcb,
  564. StartingLbo,
  565. ByteCount,
  566. Irp );
  567. if (!Wait) {
  568. //
  569. // We, nor anybody else, need the IrpContext any more.
  570. //
  571. IrpContext->FatIoContext = NULL;
  572. FatDeleteIrpContext( IrpContext );
  573. DebugTrace(-1, Dbg, "FatNonCachedIo -> STATUS_PENDING\n", 0);
  574. return STATUS_PENDING;
  575. }
  576. FatWaitSync( IrpContext );
  577. //
  578. // If the call didn't succeed, raise the error status
  579. //
  580. if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
  581. ASSERT( KeGetCurrentThread() != Vcb->VerifyThread || Status != STATUS_VERIFY_REQUIRED );
  582. FatNormalizeAndRaiseStatus( IrpContext, Status );
  583. }
  584. //
  585. // Update the current file position
  586. //
  587. if (SynchronousIo && !PagingIo) {
  588. FileObject->CurrentByteOffset.QuadPart =
  589. StartingLbo + Irp->IoStatus.Information;
  590. }
  591. DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", Status );
  592. FatCompleteRequest( IrpContext, Irp, Status );
  593. return Status;
  594. }
  595. //
  596. // At this point we know there is an Fcb/Dcb.
  597. //
  598. ASSERT( FcbOrDcb != NULL );
  599. //
  600. // Check for a non-zero high part offset
  601. //
  602. if ( StartingByte.HighPart != 0 ) {
  603. Irp->IoStatus.Information = 0;
  604. FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE );
  605. return STATUS_END_OF_FILE;
  606. }
  607. //
  608. // Use a try-finally to free Fcb/Dcb and buffers on the way out.
  609. //
  610. try {
  611. //
  612. // This case corresponds to a normal user read file.
  613. //
  614. if ( TypeOfOpen == UserFileOpen) {
  615. ULONG FileSize;
  616. ULONG ValidDataLength;
  617. DebugTrace(0, Dbg, "Type of read is user file open\n", 0);
  618. //
  619. // If this is a noncached transfer and is not a paging I/O, and
  620. // the file has a data section, then we will do a flush here
  621. // to avoid stale data problems. Note that we must flush before
  622. // acquiring the Fcb shared since the write may try to acquire
  623. // it exclusive.
  624. //
  625. if (!PagingIo && NonCachedIo
  626. &&
  627. (FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
  628. #ifndef REDUCE_SYNCHRONIZATION
  629. if (!FatAcquireExclusiveFcb( IrpContext, FcbOrDcb )) {
  630. try_return( PostIrp = TRUE );
  631. }
  632. ExAcquireResourceSharedLite( FcbOrDcb->Header.PagingIoResource, TRUE);
  633. #endif //REDUCE_SYNCHRONIZATION
  634. CcFlushCache( FileObject->SectionObjectPointer,
  635. &StartingByte,
  636. ByteCount,
  637. &Irp->IoStatus );
  638. #ifndef REDUCE_SYNCHRONIZATION
  639. ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
  640. FatReleaseFcb( IrpContext, FcbOrDcb );
  641. #endif //REDUCE_SYNCHRONIZATION
  642. if (!NT_SUCCESS( Irp->IoStatus.Status)) {
  643. try_return( Irp->IoStatus.Status );
  644. }
  645. #ifndef REDUCE_SYNCHRONIZATION
  646. ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
  647. ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
  648. #endif //REDUCE_SYNCHRONIZATION
  649. }
  650. //
  651. // We need shared access to the Fcb/Dcb before proceeding.
  652. //
  653. if ( PagingIo ) {
  654. if (!ExAcquireResourceSharedLite( FcbOrDcb->Header.PagingIoResource,
  655. Wait )) {
  656. DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %08lx shared without waiting\n", FcbOrDcb );
  657. try_return( PostIrp = TRUE );
  658. }
  659. if (!Wait) {
  660. IrpContext->FatIoContext->Wait.Async.Resource =
  661. FcbOrDcb->Header.PagingIoResource;
  662. }
  663. } else {
  664. //
  665. // If this is async I/O, we will wait if there is an
  666. // exclusive waiter.
  667. //
  668. if (!Wait && NonCachedIo) {
  669. if (!FatAcquireSharedFcbWaitForEx( IrpContext, FcbOrDcb )) {
  670. DebugTrace( 0,
  671. Dbg,
  672. "Cannot acquire FcbOrDcb = %08lx shared without waiting\n",
  673. FcbOrDcb );
  674. try_return( PostIrp = TRUE );
  675. }
  676. IrpContext->FatIoContext->Wait.Async.Resource =
  677. FcbOrDcb->Header.Resource;
  678. } else {
  679. if (!FatAcquireSharedFcb( IrpContext, FcbOrDcb )) {
  680. DebugTrace( 0,
  681. Dbg,
  682. "Cannot acquire FcbOrDcb = %08lx shared without waiting\n",
  683. FcbOrDcb );
  684. try_return( PostIrp = TRUE );
  685. }
  686. }
  687. }
  688. FcbOrDcbAcquired = TRUE;
  689. //
  690. // Make sure the FcbOrDcb is still good
  691. //
  692. FatVerifyFcb( IrpContext, FcbOrDcb );
  693. //
  694. // We now check whether we can proceed based on the state of
  695. // the file oplocks.
  696. //
  697. if (!PagingIo) {
  698. Status = FsRtlCheckOplock( &FcbOrDcb->Specific.Fcb.Oplock,
  699. Irp,
  700. IrpContext,
  701. FatOplockComplete,
  702. FatPrePostIrp );
  703. if (Status != STATUS_SUCCESS) {
  704. OplockPostIrp = TRUE;
  705. PostIrp = TRUE;
  706. try_return( NOTHING );
  707. }
  708. //
  709. // Reset the flag indicating if Fast I/O is possible since the oplock
  710. // check could have broken existing (conflicting) oplocks.
  711. //
  712. FcbOrDcb->Header.IsFastIoPossible = FatIsFastIoPossible( FcbOrDcb );
  713. //
  714. // We have to check for read access according to the current
  715. // state of the file locks, and set FileSize from the Fcb.
  716. //
  717. if (!PagingIo &&
  718. !FsRtlCheckLockForReadAccess( &FcbOrDcb->Specific.Fcb.FileLock,
  719. Irp )) {
  720. try_return( Status = STATUS_FILE_LOCK_CONFLICT );
  721. }
  722. }
  723. //
  724. // Pick up our sizes and check/trim the IO.
  725. //
  726. FileSize = FcbOrDcb->Header.FileSize.LowPart;
  727. ValidDataLength = FcbOrDcb->Header.ValidDataLength.LowPart;
  728. //
  729. // If the read starts beyond End of File, return EOF.
  730. //
  731. if (StartingVbo >= FileSize) {
  732. DebugTrace( 0, Dbg, "End of File\n", 0 );
  733. try_return ( Status = STATUS_END_OF_FILE );
  734. }
  735. //
  736. // If the read extends beyond EOF, truncate the read
  737. //
  738. if (ByteCount > FileSize - StartingVbo) {
  739. ByteCount = RequestedByteCount = FileSize - StartingVbo;
  740. if (NonCachedIo && !Wait) {
  741. IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
  742. RequestedByteCount;
  743. }
  744. }
  745. //
  746. // HANDLE THE NON-CACHED CASE
  747. //
  748. if ( NonCachedIo ) {
  749. ULONG SectorSize;
  750. ULONG BytesToRead;
  751. DebugTrace(0, Dbg, "Non cached read.\n", 0);
  752. //
  753. // Get the sector size
  754. //
  755. SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
  756. //
  757. // Start by zeroing any part of the read after Valid Data
  758. //
  759. if (ValidDataLength < FcbOrDcb->ValidDataToDisk) {
  760. ValidDataLength = FcbOrDcb->ValidDataToDisk;
  761. }
  762. if ( StartingVbo + ByteCount > ValidDataLength ) {
  763. SystemBuffer = FatMapUserBuffer( IrpContext, Irp );
  764. if (StartingVbo < ValidDataLength) {
  765. ULONG ZeroingOffset;
  766. //
  767. // Now zero out the user's request sector aligned beyond
  768. // vdl. We will handle the straddling sector at completion
  769. // time via the bytecount reduction which immediately
  770. // follows this check.
  771. //
  772. // Note that we used to post in this case for async requests.
  773. // Note also that if the request was wholly beyond VDL that
  774. // we did not post, therefore this is consistent. Synchronous
  775. // zeroing is fine for async requests.
  776. //
  777. ZeroingOffset = ((ValidDataLength - StartingVbo) + (SectorSize - 1))
  778. & ~(SectorSize - 1);
  779. //
  780. // If the offset is at or above the byte count, no harm: just means
  781. // that the read ends in the last sector and the zeroing will be
  782. // done at completion.
  783. //
  784. if (ByteCount > ZeroingOffset) {
  785. SafeZeroMemory( (PUCHAR) SystemBuffer + ZeroingOffset,
  786. ByteCount - ZeroingOffset);
  787. }
  788. } else {
  789. //
  790. // All we have to do now is sit here and zero the
  791. // user's buffer, no reading is required.
  792. //
  793. SafeZeroMemory( (PUCHAR)SystemBuffer, ByteCount );
  794. Irp->IoStatus.Information = ByteCount;
  795. try_return ( Status = STATUS_SUCCESS );
  796. }
  797. }
  798. //
  799. // Reduce the byte count to actually read if it extends beyond
  800. // Valid Data Length
  801. //
  802. ByteCount = (ValidDataLength - StartingVbo < ByteCount) ?
  803. ValidDataLength - StartingVbo : ByteCount;
  804. //
  805. // Round up to a sector boundary, and remember that if we are
  806. // reading extra bytes we will zero them out during completion.
  807. //
  808. BytesToRead = (ByteCount + (SectorSize - 1))
  809. & ~(SectorSize - 1);
  810. //
  811. // Just to help alleviate confusion. At this point:
  812. //
  813. // RequestedByteCount - is the number of bytes originally
  814. // taken from the Irp, but constrained
  815. // to filesize.
  816. //
  817. // ByteCount - is RequestedByteCount constrained to
  818. // ValidDataLength.
  819. //
  820. // BytesToRead - is ByteCount rounded up to sector
  821. // boundry. This is the number of bytes
  822. // that we must physically read.
  823. //
  824. //
  825. // If this request is not properly aligned, or extending
  826. // to a sector boundary would overflow the buffer, send it off
  827. // on a special-case path.
  828. //
  829. if ( (StartingVbo & (SectorSize - 1)) ||
  830. (BytesToRead > IrpSp->Parameters.Read.Length) ) {
  831. //
  832. // If we can't wait, we must post this.
  833. //
  834. if (!Wait) {
  835. try_return( PostIrp = TRUE );
  836. }
  837. //
  838. // Do the physical read
  839. //
  840. FatNonCachedNonAlignedRead( IrpContext,
  841. Irp,
  842. FcbOrDcb,
  843. StartingVbo,
  844. ByteCount );
  845. //
  846. // Set BytesToRead to ByteCount to satify the following ASSERT.
  847. //
  848. BytesToRead = ByteCount;
  849. } else {
  850. //
  851. // Perform the actual IO
  852. //
  853. if (FatNonCachedIo( IrpContext,
  854. Irp,
  855. FcbOrDcb,
  856. StartingVbo,
  857. BytesToRead,
  858. ByteCount ) == STATUS_PENDING) {
  859. IrpContext->FatIoContext = NULL;
  860. Irp = NULL;
  861. try_return( Status = STATUS_PENDING );
  862. }
  863. }
  864. //
  865. // If the call didn't succeed, raise the error status
  866. //
  867. if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
  868. ASSERT( KeGetCurrentThread() != Vcb->VerifyThread || Status != STATUS_VERIFY_REQUIRED );
  869. FatNormalizeAndRaiseStatus( IrpContext, Status );
  870. } else {
  871. //
  872. // Else set the Irp information field to reflect the
  873. // entire desired read.
  874. //
  875. ASSERT( Irp->IoStatus.Information == BytesToRead );
  876. Irp->IoStatus.Information = RequestedByteCount;
  877. }
  878. //
  879. // The transfer is complete.
  880. //
  881. try_return( Status );
  882. } // if No Intermediate Buffering
  883. //
  884. // HANDLE CACHED CASE
  885. //
  886. else {
  887. //
  888. // We delay setting up the file cache until now, in case the
  889. // caller never does any I/O to the file, and thus
  890. // FileObject->PrivateCacheMap == NULL.
  891. //
  892. if (FileObject->PrivateCacheMap == NULL) {
  893. DebugTrace(0, Dbg, "Initialize cache mapping.\n", 0);
  894. //
  895. // Get the file allocation size, and if it is less than
  896. // the file size, raise file corrupt error.
  897. //
  898. if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
  899. FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
  900. }
  901. if ( FileSize > FcbOrDcb->Header.AllocationSize.LowPart ) {
  902. FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
  903. FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  904. }
  905. //
  906. // Now initialize the cache map.
  907. //
  908. CcInitializeCacheMap( FileObject,
  909. (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize,
  910. FALSE,
  911. &FatData.CacheManagerCallbacks,
  912. FcbOrDcb );
  913. CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY );
  914. }
  915. //
  916. // DO A NORMAL CACHED READ, if the MDL bit is not set,
  917. //
  918. DebugTrace(0, Dbg, "Cached read.\n", 0);
  919. if (!FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
  920. //
  921. // Get hold of the user's buffer.
  922. //
  923. SystemBuffer = FatMapUserBuffer( IrpContext, Irp );
  924. //
  925. // Now try to do the copy.
  926. //
  927. if (!CcCopyRead( FileObject,
  928. &StartingByte,
  929. ByteCount,
  930. Wait,
  931. SystemBuffer,
  932. &Irp->IoStatus )) {
  933. DebugTrace( 0, Dbg, "Cached Read could not wait\n", 0 );
  934. try_return( PostIrp = TRUE );
  935. }
  936. Status = Irp->IoStatus.Status;
  937. ASSERT( NT_SUCCESS( Status ));
  938. try_return( Status );
  939. }
  940. //
  941. // HANDLE A MDL READ
  942. //
  943. else {
  944. DebugTrace(0, Dbg, "MDL read.\n", 0);
  945. ASSERT( Wait );
  946. CcMdlRead( FileObject,
  947. &StartingByte,
  948. ByteCount,
  949. &Irp->MdlAddress,
  950. &Irp->IoStatus );
  951. Status = Irp->IoStatus.Status;
  952. ASSERT( NT_SUCCESS( Status ));
  953. try_return( Status );
  954. }
  955. }
  956. }
  957. //
  958. // These two cases correspond to a system read directory file and
  959. // ea file.
  960. //
  961. if (( TypeOfOpen == DirectoryFile ) || ( TypeOfOpen == EaFile)) {
  962. ULONG SectorSize;
  963. DebugTrace(0, Dbg, "Read Directory or Ea file.\n", 0);
  964. //
  965. // For the noncached case, assert that everything is sector
  966. // alligned.
  967. //
  968. SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
  969. //
  970. // We make several assumptions about these two types of files.
  971. // Make sure all of them are true.
  972. //
  973. ASSERT( NonCachedIo && PagingIo );
  974. ASSERT( ((StartingVbo | ByteCount) & (SectorSize - 1)) == 0 );
  975. //
  976. // These calls must allways be within the allocation size
  977. //
  978. if (StartingVbo >= FcbOrDcb->Header.AllocationSize.LowPart) {
  979. DebugTrace( 0, Dbg, "PagingIo dirent started beyond EOF.\n", 0 );
  980. Irp->IoStatus.Information = 0;
  981. try_return( Status = STATUS_SUCCESS );
  982. }
  983. if ( StartingVbo + ByteCount > FcbOrDcb->Header.AllocationSize.LowPart ) {
  984. DebugTrace( 0, Dbg, "PagingIo dirent extending beyond EOF.\n", 0 );
  985. ByteCount = FcbOrDcb->Header.AllocationSize.LowPart - StartingVbo;
  986. }
  987. //
  988. // Perform the actual IO
  989. //
  990. if (FatNonCachedIo( IrpContext,
  991. Irp,
  992. FcbOrDcb,
  993. StartingVbo,
  994. ByteCount,
  995. ByteCount ) == STATUS_PENDING) {
  996. IrpContext->FatIoContext = NULL;
  997. Irp = NULL;
  998. try_return( Status = STATUS_PENDING );
  999. }
  1000. //
  1001. // If the call didn't succeed, raise the error status
  1002. //
  1003. if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
  1004. ASSERT( KeGetCurrentThread() != Vcb->VerifyThread || Status != STATUS_VERIFY_REQUIRED );
  1005. FatNormalizeAndRaiseStatus( IrpContext, Status );
  1006. } else {
  1007. ASSERT( Irp->IoStatus.Information == ByteCount );
  1008. }
  1009. try_return( Status );
  1010. }
  1011. //
  1012. // This is the case of a user who openned a directory. No reading is
  1013. // allowed.
  1014. //
  1015. if ( TypeOfOpen == UserDirectoryOpen ) {
  1016. DebugTrace( 0, Dbg, "CommonRead -> STATUS_INVALID_PARAMETER\n", 0);
  1017. try_return( Status = STATUS_INVALID_PARAMETER );
  1018. }
  1019. //
  1020. // If we get this far, something really serious is wrong.
  1021. //
  1022. DebugDump("Illegal TypeOfOpen\n", 0, FcbOrDcb );
  1023. FatBugCheck( TypeOfOpen, (ULONG_PTR) FcbOrDcb, 0 );
  1024. try_exit: NOTHING;
  1025. //
  1026. // If the request was not posted and there's an Irp, deal with it.
  1027. //
  1028. if ( Irp ) {
  1029. if ( !PostIrp ) {
  1030. ULONG ActualBytesRead;
  1031. DebugTrace( 0, Dbg, "Completing request with status = %08lx\n",
  1032. Status);
  1033. DebugTrace( 0, Dbg, " Information = %08lx\n",
  1034. Irp->IoStatus.Information);
  1035. //
  1036. // Record the total number of bytes actually read
  1037. //
  1038. ActualBytesRead = (ULONG)Irp->IoStatus.Information;
  1039. //
  1040. // If the file was opened for Synchronous IO, update the current
  1041. // file position.
  1042. //
  1043. if (SynchronousIo && !PagingIo) {
  1044. FileObject->CurrentByteOffset.LowPart =
  1045. StartingVbo + ActualBytesRead;
  1046. }
  1047. //
  1048. // If this was not PagingIo, mark that the last access
  1049. // time on the dirent needs to be updated on close.
  1050. //
  1051. if (NT_SUCCESS(Status) && !PagingIo) {
  1052. SetFlag( FileObject->Flags, FO_FILE_FAST_IO_READ );
  1053. }
  1054. } else {
  1055. DebugTrace( 0, Dbg, "Passing request to Fsp\n", 0 );
  1056. if (!OplockPostIrp) {
  1057. Status = FatFsdPostRequest( IrpContext, Irp );
  1058. }
  1059. }
  1060. }
  1061. } finally {
  1062. DebugUnwind( FatCommonRead );
  1063. //
  1064. // If the FcbOrDcb has been acquired, release it.
  1065. //
  1066. if (FcbOrDcbAcquired && Irp) {
  1067. if ( PagingIo ) {
  1068. ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
  1069. } else {
  1070. FatReleaseFcb( NULL, FcbOrDcb );
  1071. }
  1072. }
  1073. //
  1074. // Complete the request if we didn't post it and no exception
  1075. //
  1076. // Note that FatCompleteRequest does the right thing if either
  1077. // IrpContext or Irp are NULL
  1078. //
  1079. if (!PostIrp) {
  1080. //
  1081. // If we had a stack io context, we have to make sure the contents
  1082. // are cleaned up before we leave.
  1083. //
  1084. // At present with zero mdls, this will only really happen on exceptional
  1085. // termination where we failed to dispatch the IO. Cleanup of zero mdls
  1086. // normally occurs during completion, but when we bail we must make sure
  1087. // the cleanup occurs here or the fatiocontext will go out of scope.
  1088. //
  1089. // If the operation was posted, cleanup occured there.
  1090. //
  1091. if (FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) {
  1092. if (IrpContext->FatIoContext->ZeroMdl) {
  1093. IoFreeMdl( IrpContext->FatIoContext->ZeroMdl );
  1094. }
  1095. ClearFlag(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT);
  1096. IrpContext->FatIoContext = NULL;
  1097. }
  1098. if (!AbnormalTermination()) {
  1099. FatCompleteRequest( IrpContext, Irp, Status );
  1100. }
  1101. }
  1102. DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", Status );
  1103. }
  1104. return Status;
  1105. }
  1106. //
  1107. // Local support routine
  1108. //
  1109. VOID
  1110. FatOverflowPagingFileRead (
  1111. IN PVOID Context,
  1112. IN PKEVENT Event
  1113. )
  1114. /*++
  1115. Routine Description:
  1116. The routine simply call FatPagingFileIo. It is invoked in cases when
  1117. there was not enough stack space to perform the pagefault in the
  1118. original thread. It is also responsible for freeing the packet pool.
  1119. Arguments:
  1120. Irp - Supplies the Irp being processed
  1121. Fcb - Supplies the paging file Fcb, since we have it handy.
  1122. Return Value:
  1123. VOID
  1124. --*/
  1125. {
  1126. PPAGING_FILE_OVERFLOW_PACKET Packet = Context;
  1127. FatPagingFileIo( Packet->Irp, Packet->Fcb );
  1128. //
  1129. // Set the stack overflow item's event to tell the original
  1130. // thread that we're done.
  1131. //
  1132. KeSetEvent( Event, 0, FALSE );
  1133. return;
  1134. }