Leaked source code of windows server 2003
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.

2445 lines
81 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. Read.c
  5. Abstract:
  6. This module implements the File Read routine for Ntfs called by the
  7. dispatch driver.
  8. Author:
  9. Brian Andrew BrianAn 15-Aug-1991
  10. Revision History:
  11. --*/
  12. #include "NtfsProc.h"
  13. #include "lockorder.h"
  14. //
  15. // The local debug trace level
  16. //
  17. #define Dbg (DEBUG_TRACE_READ)
  18. #ifdef NTFS_RWC_DEBUG
  19. PRWC_HISTORY_ENTRY
  20. NtfsGetHistoryEntry (
  21. IN PSCB Scb
  22. );
  23. BOOLEAN NtfsBreakOnConflict = TRUE;
  24. #endif
  25. //
  26. // Define stack overflow read threshhold.
  27. //
  28. #ifdef _X86_
  29. #if DBG
  30. #define OVERFLOW_READ_THRESHHOLD (0xD00)
  31. #else
  32. #define OVERFLOW_READ_THRESHHOLD (0xA00)
  33. #endif
  34. #else
  35. #define OVERFLOW_READ_THRESHHOLD (0x1000)
  36. #endif // _X86_
  37. //
  38. // Local procedure prototypes
  39. //
  40. //
  41. // The following procedure is used to handling read stack overflow operations.
  42. //
  43. VOID
  44. NtfsStackOverflowRead (
  45. IN PVOID Context,
  46. IN PKEVENT Event
  47. );
  48. VOID
  49. NtfsNonCachedResidentRead (
  50. IN PIRP_CONTEXT IrpContext,
  51. IN PIRP Irp,
  52. IN PSCB Scb,
  53. IN ULONG StartingVbo,
  54. IN ULONG ByteCount
  55. );
  56. #define CollectReadStats(VCB,OPEN_TYPE,SCB,FCB,BYTE_COUNT) { \
  57. PFILE_SYSTEM_STATISTICS FsStats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()]; \
  58. if (!FlagOn( (FCB)->FcbState, FCB_STATE_SYSTEM_FILE)) { \
  59. if (NtfsIsTypeCodeUserData( (SCB)->AttributeTypeCode )) { \
  60. FsStats->Common.UserFileReads += 1; \
  61. FsStats->Common.UserFileReadBytes += (ULONG)(BYTE_COUNT); \
  62. } else { \
  63. FsStats->Ntfs.UserIndexReads += 1; \
  64. FsStats->Ntfs.UserIndexReadBytes += (ULONG)(BYTE_COUNT); \
  65. } \
  66. } else { \
  67. if ((SCB) != (VCB)->LogFileScb) { \
  68. FsStats->Common.MetaDataReads += 1; \
  69. FsStats->Common.MetaDataReadBytes += (ULONG)(BYTE_COUNT); \
  70. } else { \
  71. FsStats->Ntfs.LogFileReads += 1; \
  72. FsStats->Ntfs.LogFileReadBytes += (ULONG)(BYTE_COUNT); \
  73. } \
  74. \
  75. if ((SCB) == (VCB)->MftScb) { \
  76. FsStats->Ntfs.MftReads += 1; \
  77. FsStats->Ntfs.MftReadBytes += (ULONG)(BYTE_COUNT); \
  78. } else if ((SCB) == (VCB)->RootIndexScb) { \
  79. FsStats->Ntfs.RootIndexReads += 1; \
  80. FsStats->Ntfs.RootIndexReadBytes += (ULONG)(BYTE_COUNT); \
  81. } else if ((SCB) == (VCB)->BitmapScb) { \
  82. FsStats->Ntfs.BitmapReads += 1; \
  83. FsStats->Ntfs.BitmapReadBytes += (ULONG)(BYTE_COUNT); \
  84. } else if ((SCB) == (VCB)->MftBitmapScb) { \
  85. FsStats->Ntfs.MftBitmapReads += 1; \
  86. FsStats->Ntfs.MftBitmapReadBytes += (ULONG)(BYTE_COUNT); \
  87. } \
  88. } \
  89. }
  90. NTSTATUS
  91. NtfsFsdRead (
  92. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  93. IN PIRP Irp
  94. )
  95. /*++
  96. Routine Description:
  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. IrpContext - If present this an IrpContext put on the caller's stack
  104. to avoid having to allocate it from pool.
  105. Irp - Supplies the Irp being processed
  106. Return Value:
  107. NTSTATUS - The FSD status for the IRP
  108. --*/
  109. {
  110. TOP_LEVEL_CONTEXT TopLevelContext;
  111. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  112. NTSTATUS Status = STATUS_SUCCESS;
  113. PIRP_CONTEXT IrpContext = NULL;
  114. ULONG RetryCount = 0;
  115. ASSERT_IRP( Irp );
  116. DebugTrace( +1, Dbg, ("NtfsFsdRead\n") );
  117. //
  118. // Call the common Read routine
  119. //
  120. FsRtlEnterFileSystem();
  121. //
  122. // Always make the reads appear to be top level. As long as we don't have
  123. // log file full we won't post these requests. This will prevent paging
  124. // reads from trying to attach to uninitialized top level requests.
  125. //
  126. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, TRUE, TRUE );
  127. ASSERT( ThreadTopLevelContext == &TopLevelContext );
  128. do {
  129. try {
  130. //
  131. // We are either initiating this request or retrying it.
  132. //
  133. if (IrpContext == NULL) {
  134. //
  135. // Allocate the Irp and update the top level storage. For synchronous
  136. // paging io allocate the irp on the stack
  137. //
  138. if (CanFsdWait( Irp ) && FlagOn( Irp->Flags, IRP_PAGING_IO )) {
  139. //
  140. // AllocateFromStack is only called in the first pass of the
  141. // loop. Once the IrpContext exists we don't call this again.
  142. //
  143. IrpContext = (PIRP_CONTEXT) NtfsAllocateFromStack( sizeof( IRP_CONTEXT ));
  144. }
  145. NtfsInitializeIrpContext( Irp, CanFsdWait( Irp ), &IrpContext );
  146. if (ThreadTopLevelContext->ScbBeingHotFixed != NULL) {
  147. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_HOTFIX_UNDERWAY );
  148. }
  149. //
  150. // Initialize the thread top level structure, if needed.
  151. //
  152. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  153. } else if (Status == STATUS_LOG_FILE_FULL) {
  154. NtfsCheckpointForLogFileFull( IrpContext );
  155. }
  156. //
  157. // If this is an Mdl complete request, don't go through
  158. // common read.
  159. //
  160. ASSERT( !FlagOn( IrpContext->MinorFunction, IRP_MN_DPC ) );
  161. if (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE )) {
  162. DebugTrace( 0, Dbg, ("Calling NtfsCompleteMdl\n") );
  163. Status = NtfsCompleteMdl( IrpContext, Irp );
  164. //
  165. // Check if we have enough stack space to process this request. If there
  166. // isn't enough then we will create a new thread to process this single
  167. // request
  168. //
  169. } else if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) {
  170. KEVENT Event;
  171. PFILE_OBJECT FileObject;
  172. TYPE_OF_OPEN TypeOfOpen;
  173. PVCB Vcb;
  174. PFCB Fcb;
  175. PSCB Scb;
  176. PCCB Ccb;
  177. PERESOURCE Resource;
  178. DebugTrace( 0, Dbg, ("Getting too close to stack limit pass request to Fsp\n") );
  179. //
  180. // Decode the file object to get the Scb
  181. //
  182. FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
  183. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  184. if ((TypeOfOpen != UserFileOpen) &&
  185. (TypeOfOpen != StreamFileOpen) &&
  186. (TypeOfOpen != UserVolumeOpen)) {
  187. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  188. Status = STATUS_INVALID_DEVICE_REQUEST;
  189. break;
  190. }
  191. //
  192. // We cannot post any compressed reads, because that would interfere
  193. // with our reserved buffer strategy. We may currently own
  194. // NtfsReservedBufferResource, and it is important for our read to
  195. // be able to get a buffer.
  196. //
  197. ASSERT( (Scb->CompressionUnit == 0) ||
  198. !ExIsResourceAcquiredExclusiveLite(&NtfsReservedBufferResource) );
  199. //
  200. // To avoid deadlocks we only should post recursive paging file and mft requests
  201. // o.w we might need to do lockups for example and reacquire the main in a diff. thread
  202. // from where it was preacquired
  203. //
  204. // ASSERT( (Scb == Vcb->MftScb) || (FlagOn( Scb->Fcb->FcbState, FCB_STATE_PAGING_FILE )) );
  205. //
  206. // Allocate an event and get shared on the scb. We won't grab the
  207. // Scb for the paging file path or for non-cached io for our
  208. // system files.
  209. //
  210. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  211. if ((FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )
  212. && FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) ||
  213. (NtfsLeqMftRef( &Fcb->FileReference, &VolumeFileReference ))) {
  214. //
  215. // There is nothing to release in this case.
  216. //
  217. Resource = NULL;
  218. } else {
  219. NtfsAcquireResourceShared( IrpContext, Scb, TRUE );
  220. Resource = Fcb->Resource;
  221. }
  222. try {
  223. //
  224. // Make the Irp just like a regular post request and
  225. // then send the Irp to the special overflow thread.
  226. // After the post we will wait for the stack overflow
  227. // read routine to set the event that indicates we can
  228. // now release the scb resource and return.
  229. //
  230. NtfsPrePostIrp( IrpContext, Irp );
  231. if (FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE ) &&
  232. FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) {
  233. FsRtlPostPagingFileStackOverflow( IrpContext, &Event, NtfsStackOverflowRead );
  234. } else {
  235. FsRtlPostStackOverflow( IrpContext, &Event, NtfsStackOverflowRead );
  236. }
  237. //
  238. // And wait for the worker thread to complete the item
  239. //
  240. (VOID) KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
  241. Status = STATUS_PENDING;
  242. } finally {
  243. if (Resource != NULL) {
  244. NtfsReleaseResource( IrpContext, Scb );
  245. }
  246. }
  247. //
  248. // Identify read requests which can't wait and post them to the
  249. // Fsp.
  250. //
  251. } else {
  252. #ifdef COMPRESS_ON_WRITE
  253. //
  254. // Capture the auxiliary buffer and clear its address if it
  255. // is not supposed to be deleted by the I/O system on I/O completion.
  256. //
  257. if (Irp->Tail.Overlay.AuxiliaryBuffer != NULL) {
  258. IrpContext->Union.AuxiliaryBuffer =
  259. (PFSRTL_AUXILIARY_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
  260. if (!FlagOn(IrpContext->Union.AuxiliaryBuffer->Flags,
  261. FSRTL_AUXILIARY_FLAG_DEALLOCATE)) {
  262. Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  263. }
  264. }
  265. #endif
  266. Status = NtfsCommonRead( IrpContext, Irp, TRUE );
  267. }
  268. break;
  269. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  270. NTSTATUS ExceptionCode;
  271. //
  272. // We had some trouble trying to perform the requested
  273. // operation, so we'll abort the I/O request with
  274. // the error status that we get back from the
  275. // exception code
  276. //
  277. ExceptionCode = GetExceptionCode();
  278. if (ExceptionCode == STATUS_FILE_DELETED) {
  279. IrpContext->ExceptionStatus = ExceptionCode = STATUS_END_OF_FILE;
  280. Irp->IoStatus.Information = 0;
  281. }
  282. Status = NtfsProcessException( IrpContext,
  283. Irp,
  284. ExceptionCode );
  285. }
  286. //
  287. // Retry if this is a top level request, and the Irp was not completed due
  288. // to a retryable error.
  289. //
  290. RetryCount += 1;
  291. } while ((Status == STATUS_CANT_WAIT || Status == STATUS_LOG_FILE_FULL) &&
  292. TopLevelContext.TopLevelRequest);
  293. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  294. FsRtlExitFileSystem();
  295. //
  296. // And return to our caller
  297. //
  298. DebugTrace( -1, Dbg, ("NtfsFsdRead -> %08lx\n", Status) );
  299. return Status;
  300. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  301. }
  302. //
  303. // Internal support routine
  304. //
  305. VOID
  306. NtfsStackOverflowRead (
  307. IN PVOID Context,
  308. IN PKEVENT Event
  309. )
  310. /*++
  311. Routine Description:
  312. This routine processes a read request that could not be processed by
  313. the fsp thread because of stack overflow potential.
  314. Arguments:
  315. Context - Supplies the IrpContext being processed
  316. Event - Supplies the event to be signaled when we are done processing this
  317. request.
  318. Return Value:
  319. None.
  320. --*/
  321. {
  322. TOP_LEVEL_CONTEXT TopLevelContext;
  323. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  324. PIRP_CONTEXT IrpContext = Context;
  325. //
  326. // Make it now look like we can wait for I/O to complete
  327. //
  328. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  329. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, TRUE, FALSE );
  330. //
  331. // Do the read operation protected by a try-except clause
  332. //
  333. try {
  334. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  335. //
  336. // Set the flag to indicate that we are in the overflow thread.
  337. //
  338. ThreadTopLevelContext->OverflowReadThread = TRUE;
  339. (VOID) NtfsCommonRead( IrpContext, IrpContext->OriginatingIrp, FALSE );
  340. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  341. NTSTATUS ExceptionCode;
  342. //
  343. // We had some trouble trying to perform the requested
  344. // operation, so we'll abort the I/O request with
  345. // the error status that we get back from the
  346. // execption code
  347. //
  348. ExceptionCode = GetExceptionCode();
  349. if (ExceptionCode == STATUS_FILE_DELETED) {
  350. IrpContext->ExceptionStatus = ExceptionCode = STATUS_END_OF_FILE;
  351. IrpContext->OriginatingIrp->IoStatus.Information = 0;
  352. }
  353. (VOID) NtfsProcessException( IrpContext, IrpContext->OriginatingIrp, ExceptionCode );
  354. }
  355. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  356. //
  357. // Set the stack overflow item's event to tell the original
  358. // thread that we're done and then go get another work item.
  359. //
  360. KeSetEvent( Event, 0, FALSE );
  361. }
  362. NTSTATUS
  363. NtfsCommonRead (
  364. IN PIRP_CONTEXT IrpContext,
  365. IN PIRP Irp,
  366. IN BOOLEAN AcquireScb
  367. )
  368. /*++
  369. Routine Description:
  370. This is the common routine for Read called by both the fsd and fsp
  371. threads.
  372. Arguments:
  373. Irp - Supplies the Irp to process
  374. AcquireScb - Indicates if this routine should acquire the scb
  375. Return Value:
  376. NTSTATUS - The return status for the operation
  377. --*/
  378. {
  379. NTSTATUS Status;
  380. PIO_STACK_LOCATION IrpSp;
  381. PFILE_OBJECT FileObject;
  382. TYPE_OF_OPEN TypeOfOpen;
  383. PVCB Vcb;
  384. PFCB Fcb;
  385. PSCB Scb;
  386. PCCB Ccb;
  387. PNTFS_ADVANCED_FCB_HEADER Header;
  388. PTOP_LEVEL_CONTEXT TopLevelContext;
  389. VBO StartingVbo;
  390. LONGLONG ByteCount;
  391. LONGLONG ByteRange;
  392. ULONG RequestedByteCount;
  393. BOOLEAN PostIrp = FALSE;
  394. BOOLEAN OplockPostIrp = FALSE;
  395. BOOLEAN ScbAcquired = FALSE;
  396. BOOLEAN ReleaseScb;
  397. BOOLEAN PagingIoAcquired = FALSE;
  398. BOOLEAN DoingIoAtEof = FALSE;
  399. BOOLEAN Wait;
  400. BOOLEAN PagingIo;
  401. BOOLEAN NonCachedIo;
  402. BOOLEAN SynchronousIo;
  403. BOOLEAN PagingFileIo;
  404. #ifdef COMPRESS_ON_WIRE
  405. PCOMPRESSION_SYNC CompressionSync = NULL;
  406. BOOLEAN CompressedIo = FALSE;
  407. #endif
  408. NTFS_IO_CONTEXT LocalContext;
  409. //
  410. // A system buffer is only used if we have to access the
  411. // buffer directly from the Fsp to clear a portion or to
  412. // do a synchronous I/O, or a cached transfer. It is
  413. // possible that our caller may have already mapped a
  414. // system buffer, in which case we must remember this so
  415. // we do not unmap it on the way out.
  416. //
  417. PVOID SystemBuffer = NULL;
  418. ASSERT_IRP_CONTEXT( IrpContext );
  419. ASSERT_IRP( Irp );
  420. //
  421. // Get the current Irp stack location
  422. //
  423. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  424. DebugTrace( +1, Dbg, ("NtfsCommonRead\n") );
  425. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  426. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  427. DebugTrace( 0, Dbg, ("ByteCount = %08lx\n", IrpSp->Parameters.Read.Length) );
  428. DebugTrace( 0, Dbg, ("ByteOffset = %016I64x\n", IrpSp->Parameters.Read.ByteOffset) );
  429. //
  430. // Extract and decode the file object
  431. //
  432. FileObject = IrpSp->FileObject;
  433. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  434. //
  435. // Let's kill invalid read requests.
  436. //
  437. if ((TypeOfOpen != UserFileOpen) &&
  438. (TypeOfOpen != StreamFileOpen) &&
  439. (TypeOfOpen != UserVolumeOpen)) {
  440. DebugTrace( 0, Dbg, ("Invalid file object for read\n") );
  441. DebugTrace( -1, Dbg, ("NtfsCommonRead: Exit -> %08lx\n", STATUS_INVALID_DEVICE_REQUEST) );
  442. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  443. return STATUS_INVALID_DEVICE_REQUEST;
  444. }
  445. //
  446. // Initialize the appropriate local variables.
  447. //
  448. Wait = (BOOLEAN) FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  449. PagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO );
  450. NonCachedIo = BooleanFlagOn( Irp->Flags,IRP_NOCACHE );
  451. SynchronousIo = BooleanFlagOn( FileObject->Flags, FO_SYNCHRONOUS_IO );
  452. PagingFileIo = FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE ) && FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA );
  453. #ifdef COMPRESS_ON_WIRE
  454. if (FileObject->SectionObjectPointer == &Scb->NonpagedScb->SegmentObjectC) {
  455. CompressedIo = TRUE;
  456. }
  457. #endif
  458. //
  459. // Extract starting Vbo and offset.
  460. //
  461. StartingVbo = IrpSp->Parameters.Read.ByteOffset.QuadPart;
  462. ByteCount = (LONGLONG)IrpSp->Parameters.Read.Length;
  463. //
  464. // Check for overflow and underflow.
  465. //
  466. if (MAXLONGLONG - StartingVbo < ByteCount) {
  467. ASSERT( !PagingIo );
  468. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  469. return STATUS_INVALID_PARAMETER;
  470. }
  471. ByteRange = StartingVbo + ByteCount;
  472. RequestedByteCount = (ULONG)ByteCount;
  473. //
  474. // Check for a null request, and return immediately
  475. //
  476. if ((ULONG)ByteCount == 0) {
  477. DebugTrace( 0, Dbg, ("No bytes to read\n") );
  478. DebugTrace( -1, Dbg, ("NtfsCommonRead: Exit -> %08lx\n", STATUS_SUCCESS) );
  479. NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  480. return STATUS_SUCCESS;
  481. }
  482. //
  483. // Convert all paging i/o against a usa_protected_sequence or compressed file
  484. // to synchrnonous because we must do the transform after finishing the i/o
  485. // If the header isn't initialized just do the op synchronous rather than
  486. // trying to figure out if its compressed by resyncing with disk
  487. //
  488. if (!Wait &&
  489. PagingIo &&
  490. (FlagOn( Scb->ScbState, SCB_STATE_USA_PRESENT ) ||
  491. (Scb->CompressionUnit != 0) ||
  492. Scb->EncryptionContext) ||
  493. !FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  494. Wait = TRUE;
  495. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  496. }
  497. //
  498. // Make sure there is an initialized NtfsIoContext block.
  499. //
  500. if (!PagingFileIo) {
  501. NtfsInitializeIoContext( IrpContext, &LocalContext, PagingIo );
  502. }
  503. //
  504. // Handle volume Dasd here.
  505. //
  506. if (TypeOfOpen == UserVolumeOpen) {
  507. //
  508. // If the caller has not asked for extended DASD IO access then
  509. // limit with the volume size.
  510. //
  511. if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_XTENDED_DASD_IO )) {
  512. //
  513. // If the starting vbo is past the end of the volume, we are done.
  514. //
  515. if (Scb->Header.FileSize.QuadPart <= StartingVbo) {
  516. DebugTrace( 0, Dbg, ("No bytes to read\n") );
  517. DebugTrace( -1, Dbg, ("NtfsCommonRead: Exit -> %08lx\n", STATUS_END_OF_FILE) );
  518. NtfsCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE );
  519. return STATUS_END_OF_FILE;
  520. //
  521. // If the write extends beyond the end of the volume, truncate the
  522. // bytes to write.
  523. //
  524. } else if (Scb->Header.FileSize.QuadPart < ByteRange) {
  525. ByteCount = Scb->Header.FileSize.QuadPart - StartingVbo;
  526. }
  527. }
  528. //
  529. // Set the io context async if necc. before doing the i/o
  530. //
  531. if (!Wait) {
  532. NtfsSetIoContextAsync( IrpContext, NULL, (ULONG)ByteCount );
  533. }
  534. Status = NtfsVolumeDasdIo( IrpContext,
  535. Irp,
  536. Scb,
  537. Ccb,
  538. StartingVbo,
  539. (ULONG)ByteCount );
  540. //
  541. // If the volume was opened for Synchronous IO, update the current
  542. // file position.
  543. //
  544. if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
  545. IrpSp->FileObject->CurrentByteOffset.QuadPart = StartingVbo + Irp->IoStatus.Information;
  546. }
  547. DebugTrace( 0, Dbg, ("Complete with %08lx bytes read\n", Irp->IoStatus.Information) );
  548. DebugTrace( -1, Dbg, ("NtfsCommonRead: Exit -> %08lx\n", Status) );
  549. if (Wait) {
  550. NtfsCompleteRequest( IrpContext, Irp, Status );
  551. }
  552. return Status;
  553. }
  554. //
  555. // Keep a pointer to the common fsrtl header.
  556. //
  557. Header = &Scb->Header;
  558. //
  559. // If this is a paging file, just send it to the device driver.
  560. // We assume Mm is a good citizen.
  561. //
  562. if (PagingFileIo) {
  563. if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED )) {
  564. NtfsRaiseStatus( IrpContext, STATUS_FILE_DELETED, NULL, NULL );
  565. }
  566. //
  567. // Do the usual STATUS_PENDING things.
  568. //
  569. IoMarkIrpPending( Irp );
  570. //
  571. // Perform the actual IO, it will be completed when the io finishes.
  572. //
  573. NtfsPagingFileIo( IrpContext,
  574. Irp,
  575. Scb,
  576. StartingVbo,
  577. (ULONG)ByteCount );
  578. //
  579. // We, nor anybody else, need the IrpContext any more.
  580. //
  581. NtfsCompleteRequest( IrpContext, NULL, 0 );
  582. return STATUS_PENDING;
  583. }
  584. //
  585. // Accumulate interesting statistics.
  586. //
  587. if (PagingIo) {
  588. CollectReadStats( Vcb, TypeOfOpen, Scb, Fcb, ByteCount );
  589. }
  590. //
  591. // Use a try-finally to free Scb and buffers on the way out.
  592. // At this point we can treat all requests identically since we
  593. // have a usable Scb for each of them. (Volume, User or Stream file)
  594. //
  595. try {
  596. //
  597. // This case corresponds to a non-directory file read.
  598. //
  599. LONGLONG FileSize;
  600. LONGLONG ValidDataLength;
  601. //
  602. // If this is a noncached transfer and is not a paging I/O, and
  603. // the file has a data section, then we will do a flush here
  604. // to avoid stale data problems. Note that we must flush before
  605. // acquiring the Fcb shared since the write may try to acquire
  606. // it exclusive. This is not necessary for compressed files, since
  607. // we will turn user noncached writes into cached writes.
  608. //
  609. if (!PagingIo &&
  610. NonCachedIo &&
  611. (FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
  612. //
  613. // Acquire the paging exclusive to avoid collided flushes
  614. //
  615. NtfsAcquirePagingResourceExclusive( IrpContext, Scb, TRUE );
  616. if (!FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  617. //
  618. // It is possible that this read is part of a top level request or
  619. // is being called by MM to create an image section. We will update
  620. // the top-level context to reflect this. All of the exception
  621. // handling will correctly handle the log file full in this case.
  622. //
  623. TopLevelContext = NtfsGetTopLevelContext();
  624. if (TopLevelContext->SavedTopLevelIrp != NULL) {
  625. TopLevelContext->TopLevelRequest = FALSE;
  626. }
  627. #ifdef SYSCACHE_DEBUG
  628. if (ScbIsBeingLogged( Scb )) {
  629. ULONG Flags = SCE_FLAG_READ;
  630. if (PagingIo) {
  631. SetFlag( Flags, SCE_FLAG_PAGING );
  632. }
  633. if (!SynchronousIo) {
  634. SetFlag( Flags, SCE_FLAG_ASYNC );
  635. }
  636. FsRtlLogSyscacheEvent( Scb, SCE_CC_FLUSH, Flags, StartingVbo, ByteCount, 0 );
  637. }
  638. #endif
  639. CcFlushCache( FileObject->SectionObjectPointer,
  640. (PLARGE_INTEGER)&StartingVbo,
  641. (ULONG)ByteCount,
  642. &Irp->IoStatus );
  643. NtfsReleasePagingResource( IrpContext, Scb );
  644. //
  645. // Check for errors in the flush.
  646. //
  647. NtfsNormalizeAndCleanupTransaction( IrpContext,
  648. &Irp->IoStatus.Status,
  649. TRUE,
  650. STATUS_UNEXPECTED_IO_ERROR );
  651. } else {
  652. NtfsReleasePagingResource( IrpContext, Scb );
  653. }
  654. }
  655. #ifdef COMPRESS_ON_WIRE
  656. //
  657. // For top-level noncached reads (including page reads and read-ahead paged reads),
  658. // to the normal data section when a compressed section exists, we have to flush the
  659. // range in the compressed section first. Note that NtfsSynchronizeUncompressedIo
  660. // is used to synchronize the cached case below.
  661. //
  662. // Currently only cached access is supported to the compressed section, and the
  663. // coherency to that section is synchronized in rwcmpsup.c. You do not see a similar
  664. // block of code in write.c, which would only be concerned about user-mapped files,
  665. // since user-mapping is incompatible with writes to the compressed stream, and in
  666. // fact the user mapper would break the oplocks that allow the only compressed stream
  667. // access supported at this time.
  668. //
  669. if ((Scb->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) &&
  670. !CompressedIo &&
  671. NonCachedIo &&
  672. (NtfsGetTopLevelContext()->SavedTopLevelIrp == NULL)) {
  673. LONGLONG LocalVbo;
  674. ULONG LocalCount;
  675. NtfsAcquirePagingResourceShared( IrpContext, Scb, TRUE );
  676. LocalVbo = BlockAlignTruncate( StartingVbo, (LONG)Scb->CompressionUnit );
  677. LocalCount = BlockAlign( (ULONG)((ByteCount + (StartingVbo - LocalVbo)), (LONG)Scb->CompressionUnit );
  678. CcFlushCache( &Scb->NonpagedScb->SegmentObjectC,
  679. (PLARGE_INTEGER)&LocalVbo,
  680. LocalCount,
  681. &Irp->IoStatus );
  682. NtfsReleasePagingResource( IrpContext, Scb );
  683. #ifdef NTFS_RWC_DEBUG
  684. ASSERT( !NtfsBreakOnConflict ||
  685. (IrpContext->TopLevelIrpContext->ExceptionStatus != STATUS_CANT_WAIT) );
  686. #endif
  687. //
  688. // Check for errors in the flush.
  689. //
  690. NtfsNormalizeAndCleanupTransaction( IrpContext,
  691. &Irp->IoStatus.Status,
  692. TRUE,
  693. STATUS_UNEXPECTED_IO_ERROR );
  694. }
  695. #endif
  696. //
  697. // We need shared access to the Scb before proceeding.
  698. // We won't acquire the Scb for a non-cached read of the first 4
  699. // file records.
  700. //
  701. if (AcquireScb &&
  702. (!NonCachedIo || NtfsGtrMftRef( &Fcb->FileReference, &VolumeFileReference))) {
  703. //
  704. // Figure out if we have been entered during the posting
  705. // of a top level request.
  706. //
  707. TopLevelContext = NtfsGetTopLevelContext();
  708. //
  709. // Initially we always force reads to appear to be top level
  710. // requests. If we reach this point the read not to the paging
  711. // file so it is safe to determine if we are really a top level
  712. // request. If there is an Ntfs request above us we will clear
  713. // the TopLevelRequest field in the TopLevelContext.
  714. //
  715. if (TopLevelContext->ValidSavedTopLevel) {
  716. TopLevelContext->TopLevelRequest = FALSE;
  717. }
  718. //
  719. // If this is not a paging I/O (cached or user noncached I/O),
  720. // then acquire the paging I/O resource. (Note, you can only
  721. // do cached I/O to user streams, and they always have a paging
  722. // I/O resource.
  723. //
  724. if (!PagingIo) {
  725. //
  726. // If we cannot acquire the resource, then raise.
  727. //
  728. if (!NtfsAcquirePagingResourceSharedWaitForExclusive( IrpContext, Scb, Wait )) {
  729. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  730. }
  731. PagingIoAcquired = TRUE;
  732. //
  733. // Check if we have already gone through cleanup on this handle.
  734. //
  735. if (FlagOn( Ccb->Flags, CCB_FLAG_CLEANUP )) {
  736. NtfsRaiseStatus( IrpContext, STATUS_FILE_CLOSED, NULL, NULL );
  737. }
  738. //
  739. // The reason that we always handle the user requests through the cache,
  740. // is that there is no better way to deal with alignment issues, for
  741. // the frequent case where the user noncached I/O is not an integral of
  742. // the Compression Unit. Also, the way we synchronize the case where
  743. // a compression unit is being moved to a different spot on disk during
  744. // a write, is to keep the pages locked in memory during the write, so
  745. // that there will be no need to read the disk at the same time. (If
  746. // we allowed real noncached I/O, then we would somehow have to synchronize
  747. // the noncached read with the write of the same data.)
  748. //
  749. // Bottom line is we can only really support cached reads to compresed
  750. // files.
  751. //
  752. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK ) && NonCachedIo) {
  753. NonCachedIo = FALSE;
  754. if (Scb->FileObject == NULL) {
  755. //
  756. // Make sure we are serialized with the FileSizes, and
  757. // will remove this condition if we abort.
  758. //
  759. FsRtlLockFsRtlHeader( Header );
  760. IrpContext->CleanupStructure = Scb;
  761. NtfsCreateInternalAttributeStream( IrpContext, Scb, FALSE, NULL );
  762. FsRtlUnlockFsRtlHeader( Header );
  763. IrpContext->CleanupStructure = NULL;
  764. }
  765. FileObject = Scb->FileObject;
  766. }
  767. //
  768. // Now check if the attribute has been deleted or if the
  769. // volume has been dismounted.
  770. //
  771. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED | SCB_STATE_VOLUME_DISMOUNTED)) {
  772. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )) {
  773. NtfsRaiseStatus( IrpContext, STATUS_FILE_DELETED, NULL, NULL );
  774. } else {
  775. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  776. }
  777. }
  778. //
  779. // If this is a paging I/O, and there is a paging I/O resource, then
  780. // we acquire the main resource here. Note that for most paging I/Os
  781. // (like faulting for cached I/O), we already own the paging I/O resource,
  782. // so we acquire nothing here! But, for other cases like user-mapped files,
  783. // we do check if paging I/O is acquired, and acquire the main resource if
  784. // not. The point is, we need some guarantee still that the file will not
  785. // be truncated.
  786. //
  787. } else if ((Scb->Header.PagingIoResource != NULL) &&
  788. !NtfsIsSharedScbPagingIo( Scb )) {
  789. //
  790. // If we cannot acquire the resource, then raise.
  791. //
  792. if (!NtfsAcquireResourceShared( IrpContext, Scb, Wait )) {
  793. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  794. }
  795. ScbAcquired = TRUE;
  796. //
  797. // Now check if the attribute has been deleted or if the
  798. // volume has been dismounted.
  799. //
  800. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED | SCB_STATE_VOLUME_DISMOUNTED )) {
  801. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )) {
  802. NtfsRaiseStatus( IrpContext, STATUS_FILE_DELETED, NULL, NULL );
  803. } else {
  804. NtfsRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED, NULL, NULL );
  805. }
  806. }
  807. }
  808. }
  809. //
  810. // If the Scb is uninitialized, we initialize it now.
  811. //
  812. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  813. DebugTrace( 0, Dbg, ("Initializing Scb -> %08lx\n", Scb) );
  814. ReleaseScb = FALSE;
  815. if (AcquireScb && !ScbAcquired) {
  816. NtfsAcquireResourceShared( IrpContext, Scb, TRUE );
  817. ScbAcquired = TRUE;
  818. ReleaseScb = TRUE;
  819. }
  820. NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
  821. if (ReleaseScb) {
  822. NtfsReleaseResource( IrpContext, Scb );
  823. ScbAcquired = FALSE;
  824. }
  825. }
  826. //
  827. // We check whether we can proceed
  828. // based on the state of the file oplocks.
  829. //
  830. if (TypeOfOpen == UserFileOpen) {
  831. Status = FsRtlCheckOplock( &Scb->ScbType.Data.Oplock,
  832. Irp,
  833. IrpContext,
  834. NtfsOplockComplete,
  835. NtfsPrePostIrp );
  836. if (Status != STATUS_SUCCESS) {
  837. OplockPostIrp = TRUE;
  838. PostIrp = TRUE;
  839. try_return( NOTHING );
  840. }
  841. //
  842. // This oplock call can affect whether fast IO is possible.
  843. // We may have broken an oplock to no oplock held. If the
  844. // current state of the file is FastIoIsNotPossible then
  845. // recheck the fast IO state.
  846. //
  847. if (Scb->Header.IsFastIoPossible == FastIoIsNotPossible) {
  848. NtfsAcquireFsrtlHeader( Scb );
  849. Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
  850. NtfsReleaseFsrtlHeader( Scb );
  851. }
  852. //
  853. // We have to check for read access according to the current
  854. // state of the file locks.
  855. //
  856. if (!PagingIo
  857. && Scb->ScbType.Data.FileLock != NULL
  858. && !FsRtlCheckLockForReadAccess( Scb->ScbType.Data.FileLock,
  859. Irp )) {
  860. try_return( Status = STATUS_FILE_LOCK_CONFLICT );
  861. }
  862. }
  863. //
  864. // Now synchronize with the FsRtl Header
  865. //
  866. NtfsAcquireFsrtlHeader( (PSCB) Header );
  867. //
  868. // Now see if we are reading beyond ValidDataLength. We have to
  869. // do it now so that our reads are not nooped. We only need to block
  870. // on nonrecursive I/O (cached or page fault to user section, because
  871. // if it is paging I/O, we must be part of a reader or writer who is
  872. // synchronized.
  873. //
  874. if ((ByteRange > Header->ValidDataLength.QuadPart) && !PagingIo) {
  875. //
  876. // We must serialize with anyone else doing I/O at beyond
  877. // ValidDataLength, and then remember if we need to declare
  878. // when we are done. If our caller has already serialized
  879. // with EOF then there is nothing for us to do here.
  880. //
  881. if ((IrpContext->TopLevelIrpContext->CleanupStructure == Fcb) ||
  882. (IrpContext->TopLevelIrpContext->CleanupStructure == Scb)) {
  883. DoingIoAtEof = TRUE;
  884. } else {
  885. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  886. NtfsWaitForIoAtEof( Header,
  887. (PLARGE_INTEGER)&StartingVbo,
  888. (ULONG)ByteCount );
  889. //
  890. // Set the Flag if we are in fact beyond ValidDataLength.
  891. //
  892. if (DoingIoAtEof) {
  893. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  894. IrpContext->CleanupStructure = Scb;
  895. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  896. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  897. } else {
  898. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  899. #endif
  900. }
  901. }
  902. }
  903. //
  904. // Get file sizes from the Scb.
  905. //
  906. // We must get ValidDataLength first since it is always
  907. // increased second (the case we are unprotected) and
  908. // we don't want to capture ValidDataLength > FileSize.
  909. //
  910. ValidDataLength = Header->ValidDataLength.QuadPart;
  911. FileSize = Header->FileSize.QuadPart;
  912. NtfsReleaseFsrtlHeader( (PSCB) Header );
  913. //
  914. // Optimize for the case where we are trying to fault in an entire
  915. // compression unit, even if past the end of the file. Go ahead
  916. // and round the local FileSize to a compression unit boundary.
  917. // This will allow all of these pages to come into memory when
  918. // CC touches the first page out of memory. Otherwise CC will
  919. // force them into memory one page at a time.
  920. //
  921. if (PagingIo) {
  922. if (NtfsIsTypeCodeCompressible( Scb->AttributeTypeCode ) &&
  923. FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK ) &&
  924. !FlagOn(Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT)) {
  925. FileSize = BlockAlign( FileSize, (LONG)Scb->CompressionUnit );
  926. }
  927. #ifdef COMPRESS_ON_WIRE
  928. //
  929. // If we are reading the compressed stream then we may need the
  930. // data past file size.
  931. //
  932. if (CompressedIo) {
  933. ValidDataLength = BlockAlign( ValidDataLength, (LONG)Scb->CompressionUnit );
  934. }
  935. #endif
  936. //
  937. // If this is the Usn Journal then bias the Io to the correct location in the
  938. // file.
  939. //
  940. if (FlagOn( Scb->ScbPersist, SCB_PERSIST_USN_JOURNAL )) {
  941. StartingVbo += Vcb->UsnCacheBias;
  942. ByteRange = StartingVbo + (LONGLONG) IrpSp->Parameters.Read.Length;
  943. }
  944. }
  945. //
  946. // If the read starts beyond End of File, return EOF.
  947. //
  948. if (StartingVbo >= FileSize) {
  949. DebugTrace( 0, Dbg, ("End of File\n") );
  950. try_return ( Status = STATUS_END_OF_FILE );
  951. }
  952. //
  953. // If the read extends beyond EOF, truncate the read
  954. //
  955. if (ByteRange > FileSize) {
  956. #ifdef NTFS_RWC_DEBUG
  957. #ifdef COMPRESS_ON_WIRE
  958. if (CompressedIo &&
  959. (StartingVbo < NtfsRWCHighThreshold) &&
  960. (ByteRange > NtfsRWCLowThreshold)) {
  961. PRWC_HISTORY_ENTRY NextBuffer;
  962. NextBuffer = NtfsGetHistoryEntry( Scb );
  963. NextBuffer->Operation = TrimCompressedRead;
  964. NextBuffer->Information = Scb->Header.FileSize.LowPart;
  965. NextBuffer->FileOffset = (ULONG) StartingVbo;
  966. NextBuffer->Length = (ULONG) ByteRange;
  967. }
  968. #endif
  969. #endif
  970. ByteCount = FileSize - StartingVbo;
  971. ByteRange = StartingVbo + ByteCount;
  972. RequestedByteCount = (ULONG)ByteCount;
  973. }
  974. //
  975. // HANDLE THE NONCACHED RESIDENT ATTRIBUTE CASE
  976. //
  977. // We let the cached case take the normal path for the following
  978. // reasons:
  979. //
  980. // o To insure data coherency if a user maps the file
  981. // o To get a page in the cache to keep the Fcb around
  982. // o So the data can be accessed via the Fast I/O path
  983. //
  984. // The disadvantage is the overhead to fault the data in the
  985. // first time, but we may be able to do this with asynchronous
  986. // read ahead.
  987. //
  988. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT | SCB_STATE_CONVERT_UNDERWAY ) && NonCachedIo) {
  989. ReleaseScb = FALSE;
  990. if (AcquireScb && !ScbAcquired) {
  991. NtfsAcquireResourceShared( IrpContext, Scb, TRUE );
  992. ScbAcquired = TRUE;
  993. ReleaseScb = TRUE;
  994. }
  995. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  996. NtfsNonCachedResidentRead( IrpContext, Irp, Scb, (ULONG)StartingVbo, (ULONG)ByteCount );
  997. try_return( Status = STATUS_SUCCESS );
  998. } else {
  999. if (ReleaseScb) {
  1000. NtfsReleaseResource( IrpContext, Scb );
  1001. ScbAcquired = FALSE;
  1002. }
  1003. }
  1004. }
  1005. //
  1006. // HANDLE THE NON-CACHED CASE
  1007. //
  1008. if (NonCachedIo) {
  1009. ULONG BytesToRead;
  1010. ULONG SectorSize;
  1011. ULONG ZeroOffset;
  1012. ULONG ZeroLength = 0;
  1013. DebugTrace( 0, Dbg, ("Non cached read.\n") );
  1014. //
  1015. // For a compressed stream, which is user-mapped, reserve space
  1016. // as pages come in.
  1017. //
  1018. if (FlagOn( Header->Flags, FSRTL_FLAG_USER_MAPPED_FILE ) &&
  1019. FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK ) &&
  1020. !NtfsReserveClusters( IrpContext, Scb, StartingVbo, (ULONG)ByteCount )) {
  1021. NtfsRaiseStatus( IrpContext, STATUS_DISK_FULL, NULL, NULL );
  1022. }
  1023. //
  1024. // If this is a read of an encrypted file then make it synchronous. We
  1025. // need to do this so that the encryption driver has a thread to run in.
  1026. //
  1027. if ((Scb->EncryptionContext != NULL) &&
  1028. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT ) &&
  1029. (NtfsData.EncryptionCallBackTable.AfterReadProcess != NULL) &&
  1030. NtfsIsTypeCodeUserData( Scb->AttributeTypeCode )) {
  1031. Wait = TRUE;
  1032. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  1033. }
  1034. //
  1035. // Start by zeroing any part of the read after Valid Data
  1036. //
  1037. if (ByteRange > ValidDataLength) {
  1038. ReleaseScb = FALSE;
  1039. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  1040. //
  1041. // For compressed files we need to look at ValidDataToDisk, because it could be higher.
  1042. // This requires the main resource
  1043. //
  1044. if (AcquireScb && !ScbAcquired) {
  1045. NtfsAcquireResourceShared( IrpContext, Scb, TRUE );
  1046. ScbAcquired = TRUE;
  1047. ReleaseScb = TRUE;
  1048. }
  1049. //
  1050. // If ValidDataToDisk is actually greater than
  1051. // ValidDataLength, then we must have lost a page
  1052. // during the middle of a write, and we should not
  1053. // zero that data on the way back in!
  1054. //
  1055. if (ValidDataLength < Scb->ValidDataToDisk) {
  1056. ValidDataLength = Scb->ValidDataToDisk;
  1057. }
  1058. }
  1059. if (ByteRange > ValidDataLength) {
  1060. if (StartingVbo < ValidDataLength) {
  1061. //
  1062. // Assume we will zero the entire amount.
  1063. //
  1064. ZeroLength = (ULONG)ByteCount;
  1065. //
  1066. // The new byte count and the offset to start filling with zeroes.
  1067. //
  1068. ByteCount = ValidDataLength - StartingVbo;
  1069. ZeroOffset = (ULONG)ByteCount;
  1070. //
  1071. // Now reduce the amount to zero by the zero offset.
  1072. //
  1073. ZeroLength -= ZeroOffset;
  1074. //
  1075. // If this was non-cached I/O then convert it to synchronous.
  1076. // This is because we don't want to zero the buffer now or
  1077. // we will lose the data when the driver purges the cache.
  1078. //
  1079. if (!Wait) {
  1080. Wait = TRUE;
  1081. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  1082. }
  1083. //
  1084. // Reserve the clusters in the range beyond VDL
  1085. //
  1086. if ((PagingIo) &&
  1087. (FlagOn( Scb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE )) &&
  1088. (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK | ATTRIBUTE_FLAG_SPARSE ) == ATTRIBUTE_FLAG_SPARSE)) {
  1089. if (!NtfsReserveClusters( IrpContext,
  1090. Scb,
  1091. ZeroOffset,
  1092. ZeroLength )) {
  1093. NtfsRaiseStatus( IrpContext, STATUS_DISK_FULL, NULL, NULL );
  1094. }
  1095. }
  1096. } else {
  1097. //
  1098. // Reserve space for mapped sparse files which would normally be
  1099. // done in NtfsPrepareBuffers
  1100. //
  1101. if ((PagingIo) &&
  1102. (FlagOn( Scb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE )) &&
  1103. (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK | ATTRIBUTE_FLAG_SPARSE ) == ATTRIBUTE_FLAG_SPARSE)) {
  1104. if (!NtfsReserveClusters( IrpContext,
  1105. Scb,
  1106. StartingVbo,
  1107. (ULONG)ByteCount )) {
  1108. NtfsRaiseStatus( IrpContext, STATUS_DISK_FULL, NULL, NULL );
  1109. }
  1110. }
  1111. //
  1112. // All we have to do now is sit here and zero the
  1113. // user's buffer, no reading is required.
  1114. //
  1115. NtfsFillIrpBuffer( IrpContext, Irp, (ULONG)ByteCount, 0, 0 );
  1116. #ifdef SYSCACHE_DEBUG
  1117. if (ScbIsBeingLogged( Scb )) {
  1118. ULONG Flags = SCE_FLAG_READ;
  1119. if (PagingIo) {
  1120. Flags |= SCE_FLAG_PAGING;
  1121. }
  1122. if (!SynchronousIo) {
  1123. Flags |= SCE_FLAG_ASYNC;
  1124. }
  1125. ASSERT( Scb->NonpagedScb->SegmentObject.ImageSectionObject == NULL );
  1126. FsRtlLogSyscacheEvent( Scb, SCE_ZERO_NC, Flags, StartingVbo, ByteCount, ValidDataLength );
  1127. }
  1128. #endif
  1129. Irp->IoStatus.Information = (ULONG)ByteCount;
  1130. try_return ( Status = STATUS_SUCCESS );
  1131. }
  1132. }
  1133. //
  1134. // Now free the Scb if we only acquired it here.
  1135. //
  1136. if (ReleaseScb) {
  1137. NtfsReleaseResource( IrpContext, Scb );
  1138. ScbAcquired = FALSE;
  1139. }
  1140. }
  1141. //
  1142. // Get the sector size
  1143. //
  1144. SectorSize = Vcb->BytesPerSector;
  1145. //
  1146. // Round up to a sector boundry
  1147. //
  1148. BytesToRead = BlockAlign( (ULONG)ByteCount, (LONG)SectorSize );
  1149. //
  1150. // Call a special routine if we do not have sector alignment
  1151. // and the file is not compressed.
  1152. //
  1153. if (((((ULONG) StartingVbo) & (SectorSize - 1)) ||
  1154. (BytesToRead > IrpSp->Parameters.Read.Length))
  1155. &&
  1156. !FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  1157. //
  1158. // If we can't wait, we must post this.
  1159. //
  1160. if (!Wait) {
  1161. try_return( PostIrp = TRUE );
  1162. }
  1163. //
  1164. // Do the physical read.
  1165. //
  1166. #ifdef COMPRESS_ON_WIRE
  1167. ASSERT( !CompressedIo );
  1168. #endif
  1169. ASSERT( Wait );
  1170. NtfsNonCachedNonAlignedIo( IrpContext,
  1171. Irp,
  1172. Scb,
  1173. StartingVbo,
  1174. (ULONG)ByteCount );
  1175. BytesToRead = (ULONG)ByteCount;
  1176. } else {
  1177. //
  1178. // Just to help reduce confusion. At this point:
  1179. //
  1180. // RequestedByteCount - is the number of bytes originally
  1181. // taken from the Irp, but constrained
  1182. // to filesize.
  1183. //
  1184. // ByteCount - is RequestedByteCount constrained to
  1185. // ValidDataLength.
  1186. //
  1187. // BytesToRead - is ByteCount rounded up to sector
  1188. // boundry. This is the number of bytes
  1189. // that we must physically read.
  1190. //
  1191. if (!Wait) {
  1192. //
  1193. // Setup the async io context info
  1194. //
  1195. if (!PagingIo) {
  1196. NtfsSetIoContextAsync( IrpContext, Scb->Header.PagingIoResource, RequestedByteCount );
  1197. } else if (ScbAcquired) {
  1198. NtfsSetIoContextAsync( IrpContext, Scb->Header.Resource, RequestedByteCount );
  1199. } else {
  1200. NtfsSetIoContextAsync( IrpContext, NULL, RequestedByteCount );
  1201. }
  1202. }
  1203. #if defined( BENL_DBG ) || defined( NTFSDBG )
  1204. try {
  1205. #endif
  1206. //
  1207. // Perform the actual IO - all resources will be released by
  1208. // the completion routine after this point if its successful
  1209. //
  1210. Status = NtfsNonCachedIo( IrpContext,
  1211. Irp,
  1212. Scb,
  1213. StartingVbo,
  1214. BytesToRead,
  1215. #ifdef COMPRESS_ON_WIRE
  1216. (CompressedIo ? COMPRESSED_STREAM : 0)
  1217. #else
  1218. 0 );
  1219. #endif
  1220. #if defined( BENL_DBG ) || defined( NTFSDBG )
  1221. } finally {
  1222. #endif
  1223. #if defined( BENL_DBG ) || defined( NTFSDBG )
  1224. }
  1225. #endif
  1226. if (Status == STATUS_PENDING) {
  1227. //
  1228. // Ownership of the irp / iocontext and paging resource
  1229. // is passed to the async completion routine
  1230. //
  1231. IrpContext->Union.NtfsIoContext = NULL;
  1232. PagingIoAcquired = FALSE;
  1233. #ifdef NTFSDBG
  1234. //
  1235. // Reflect transfer of main ownership to completion routine
  1236. //
  1237. if (ScbAcquired) {
  1238. NTFS_RESOURCE_NAME ResourceName;
  1239. ResourceName = NtfsIdentifyFcb( Vcb, Scb->Fcb );
  1240. NtfsChangeResourceOrderState( IrpContext, ResourceName, TRUE, FALSE );
  1241. }
  1242. #endif
  1243. ScbAcquired = FALSE;
  1244. Irp = NULL;
  1245. try_return( Status );
  1246. }
  1247. }
  1248. //
  1249. // If the call didn't succeed, raise the error status
  1250. //
  1251. if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
  1252. NtfsNormalizeAndRaiseStatus( IrpContext,
  1253. Status,
  1254. STATUS_UNEXPECTED_IO_ERROR );
  1255. }
  1256. //
  1257. // Else set the Irp information field to reflect the
  1258. // entire desired read.
  1259. //
  1260. ASSERT( Irp->IoStatus.Information == BytesToRead );
  1261. Irp->IoStatus.Information = RequestedByteCount;
  1262. //
  1263. // If we rounded up to a sector boundry before, zero out
  1264. // the other garbage we read from the disk.
  1265. //
  1266. if (BytesToRead > (ULONG)ByteCount) {
  1267. NtfsFillIrpBuffer( IrpContext, Irp, BytesToRead - (ULONG)ByteCount, (ULONG)ByteCount, 0 );
  1268. #ifdef SYSCACHE_DEBUG
  1269. if (ScbIsBeingLogged( Scb )) {
  1270. ULONG Flags = SCE_FLAG_READ;
  1271. if (PagingIo)
  1272. {
  1273. Flags |= SCE_FLAG_PAGING;
  1274. }
  1275. if (!SynchronousIo)
  1276. {
  1277. Flags |= SCE_FLAG_ASYNC;
  1278. }
  1279. FsRtlLogSyscacheEvent( Scb, SCE_ZERO_NC, Flags, ByteCount + StartingVbo, BytesToRead - ByteCount, 0 );
  1280. }
  1281. #endif
  1282. }
  1283. //
  1284. // If we need to zero the tail of the buffer because of valid data
  1285. // then do so now.
  1286. //
  1287. if (ZeroLength != 0) {
  1288. NtfsFillIrpBuffer( IrpContext, Irp, ZeroLength, ZeroOffset, 0 );
  1289. #ifdef SYSCACHE_DEBUG
  1290. if (ScbIsBeingLogged( Scb )) {
  1291. ULONG Flags = SCE_FLAG_READ;
  1292. if (PagingIo)
  1293. {
  1294. Flags |= SCE_FLAG_PAGING;
  1295. }
  1296. if (!SynchronousIo)
  1297. {
  1298. Flags |= SCE_FLAG_ASYNC;
  1299. }
  1300. ASSERT( Scb->NonpagedScb->SegmentObject.ImageSectionObject == NULL );
  1301. FsRtlLogSyscacheEvent( Scb, SCE_ZERO_NC, Flags, ZeroOffset + StartingVbo, ZeroLength, 0 );
  1302. }
  1303. #endif
  1304. }
  1305. //
  1306. // The transfer is complete.
  1307. //
  1308. try_return( Status );
  1309. } // if No Intermediate Buffering
  1310. //
  1311. // HANDLE THE CACHED CASE
  1312. //
  1313. else {
  1314. //
  1315. // We need to go through the cache for this
  1316. // file object. First handle the noncompressed calls.
  1317. //
  1318. #ifdef COMPRESS_ON_WIRE
  1319. if (!FlagOn(IrpContext->MinorFunction, IRP_MN_COMPRESSED)) {
  1320. #endif
  1321. //
  1322. // We delay setting up the file cache until now, in case the
  1323. // caller never does any I/O to the file, and thus
  1324. // FileObject->PrivateCacheMap == NULL.
  1325. //
  1326. if (FileObject->PrivateCacheMap == NULL) {
  1327. DebugTrace( 0, Dbg, ("Initialize cache mapping.\n") );
  1328. //
  1329. // Now initialize the cache map.
  1330. //
  1331. // Make sure we are serialized with the FileSizes, and
  1332. // will remove this condition if we abort.
  1333. //
  1334. if (!DoingIoAtEof) {
  1335. FsRtlLockFsRtlHeader( Header );
  1336. IrpContext->CleanupStructure = Scb;
  1337. }
  1338. CcInitializeCacheMap( FileObject,
  1339. (PCC_FILE_SIZES)&Header->AllocationSize,
  1340. FALSE,
  1341. &NtfsData.CacheManagerCallbacks,
  1342. Scb );
  1343. if (!DoingIoAtEof) {
  1344. FsRtlUnlockFsRtlHeader( Header );
  1345. IrpContext->CleanupStructure = NULL;
  1346. }
  1347. CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY );
  1348. }
  1349. //
  1350. // DO A NORMAL CACHED READ, if the MDL bit is not set,
  1351. //
  1352. DebugTrace( 0, Dbg, ("Cached read.\n") );
  1353. //
  1354. // If there is a compressed section, we have to do cache coherency for
  1355. // that stream, and loop here to do a Cache Manager view at a time.
  1356. //
  1357. #ifdef COMPRESS_ON_WIRE
  1358. if (Scb->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  1359. LONGLONG LocalOffset = StartingVbo;
  1360. ULONG LocalLength;
  1361. ULONG LengthLeft = (ULONG) ByteCount;
  1362. //
  1363. // Create the compressed stream if not there.
  1364. //
  1365. if (Header->FileObjectC == NULL) {
  1366. NtfsCreateInternalCompressedStream( IrpContext, Scb, FALSE, NULL );
  1367. }
  1368. if (!FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
  1369. //
  1370. // Get hold of the user's buffer.
  1371. //
  1372. SystemBuffer = NtfsMapUserBuffer( Irp, NormalPagePriority );
  1373. }
  1374. //
  1375. // We must loop to do a view at a time, because that is how much
  1376. // we synchronize at once below.
  1377. //
  1378. do {
  1379. ULONG PageCount;
  1380. ULONG ViewOffset;
  1381. //
  1382. // Calculate length left in view.
  1383. //
  1384. LocalLength = LengthLeft;
  1385. if (LocalLength > (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)))) {
  1386. LocalLength = (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)));
  1387. }
  1388. //
  1389. // Trim the read so we don't inadvertently go beyond the end of the
  1390. // view because of the MM read ahead.
  1391. //
  1392. ViewOffset = ((ULONG) LocalOffset & (VACB_MAPPING_GRANULARITY - 1));
  1393. PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(((PVOID)(ULONG_PTR)((ULONG)LocalOffset)), LocalLength);
  1394. if (LocalLength > (VACB_MAPPING_GRANULARITY - ((PageCount - 1) * PAGE_SIZE) - ViewOffset)) {
  1395. #ifdef NTFS_RWC_DEBUG
  1396. if ((LocalOffset < NtfsRWCHighThreshold) &&
  1397. (LocalOffset + LocalLength > NtfsRWCLowThreshold)) {
  1398. PRWC_HISTORY_ENTRY NextBuffer;
  1399. NextBuffer = NtfsGetHistoryEntry( (PSCB) Header );
  1400. NextBuffer->Operation = TrimCopyRead;
  1401. NextBuffer->Information = PageCount;
  1402. NextBuffer->FileOffset = (ULONG) LocalOffset;
  1403. NextBuffer->Length = (ULONG) LocalLength;
  1404. }
  1405. #endif
  1406. LocalLength = (VACB_MAPPING_GRANULARITY - ((PageCount - 1) * PAGE_SIZE) - ViewOffset);
  1407. }
  1408. Status = NtfsSynchronizeUncompressedIo( Scb,
  1409. &LocalOffset,
  1410. LocalLength,
  1411. FALSE,
  1412. &CompressionSync );
  1413. //
  1414. // If we successfully synchronized, then do a piece of the transfer.
  1415. //
  1416. if (NT_SUCCESS(Status)) {
  1417. if (!FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
  1418. //
  1419. // Now try to do the copy.
  1420. //
  1421. if (!CcCopyRead( FileObject,
  1422. (PLARGE_INTEGER)&LocalOffset,
  1423. LocalLength,
  1424. Wait,
  1425. SystemBuffer,
  1426. &Irp->IoStatus )) {
  1427. DebugTrace( 0, Dbg, ("Cached Read could not wait\n") );
  1428. try_return( PostIrp = TRUE );
  1429. }
  1430. SystemBuffer = Add2Ptr( SystemBuffer, LocalLength );
  1431. //
  1432. // HANDLE A MDL READ
  1433. //
  1434. } else {
  1435. DebugTrace( 0, Dbg, ("MDL read.\n") );
  1436. ASSERT( Wait );
  1437. #ifdef NTFS_RWCMP_TRACE
  1438. if (NtfsCompressionTrace && IsSyscache(Header)) {
  1439. DbgPrint("CcMdlRead: FO = %08lx, Len = %08lx\n", (ULONG)LocalOffset, LocalLength );
  1440. }
  1441. #endif
  1442. CcMdlRead( FileObject,
  1443. (PLARGE_INTEGER)&LocalOffset,
  1444. LocalLength,
  1445. &Irp->MdlAddress,
  1446. &Irp->IoStatus );
  1447. }
  1448. Status = Irp->IoStatus.Status;
  1449. LocalOffset += LocalLength;
  1450. LengthLeft -= LocalLength;
  1451. }
  1452. } while ((LengthLeft != 0) && NT_SUCCESS(Status));
  1453. //
  1454. // Make sure to return the total of all of the IOs.
  1455. //
  1456. Irp->IoStatus.Information = (ULONG) ByteCount;
  1457. try_return( Status );
  1458. }
  1459. #endif
  1460. if (!FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
  1461. //
  1462. // Get hold of the user's buffer.
  1463. //
  1464. SystemBuffer = NtfsMapUserBuffer( Irp, NormalPagePriority );
  1465. #ifdef SYSCACHE_DEBUG
  1466. if (ScbIsBeingLogged( Scb )) {
  1467. ULONG Flags = SCE_FLAG_READ;
  1468. if (PagingIo)
  1469. {
  1470. Flags |= SCE_FLAG_PAGING;
  1471. }
  1472. if (!SynchronousIo)
  1473. {
  1474. Flags |= SCE_FLAG_ASYNC;
  1475. }
  1476. ASSERT( Scb->NonpagedScb->SegmentObject.ImageSectionObject == NULL );
  1477. FsRtlLogSyscacheEvent( Scb, SCE_READ, Flags, StartingVbo, ByteCount, (LONGLONG)FileObject );
  1478. }
  1479. #endif
  1480. //
  1481. // Now try to do the copy.
  1482. //
  1483. if (!CcCopyRead( FileObject,
  1484. (PLARGE_INTEGER)&StartingVbo,
  1485. (ULONG)ByteCount,
  1486. Wait,
  1487. SystemBuffer,
  1488. &Irp->IoStatus )) {
  1489. DebugTrace( 0, Dbg, ("Cached Read could not wait\n") );
  1490. try_return( PostIrp = TRUE );
  1491. }
  1492. //
  1493. // HANDLE A MDL READ
  1494. //
  1495. } else {
  1496. DebugTrace( 0, Dbg, ("MDL read.\n") );
  1497. ASSERT( Wait );
  1498. #ifdef NTFS_RWCMP_TRACE
  1499. if (NtfsCompressionTrace && IsSyscache(Header)) {
  1500. DbgPrint("CcMdlRead: FO = %08lx, Len = %08lx\n", (ULONG)StartingVbo, (ULONG)ByteCount );
  1501. }
  1502. #endif
  1503. CcMdlRead( FileObject,
  1504. (PLARGE_INTEGER)&StartingVbo,
  1505. (ULONG)ByteCount,
  1506. &Irp->MdlAddress,
  1507. &Irp->IoStatus );
  1508. }
  1509. Status = Irp->IoStatus.Status;
  1510. ASSERT( NT_SUCCESS( Status ));
  1511. try_return( Status );
  1512. #ifdef COMPRESS_ON_WIRE
  1513. //
  1514. // Handle the compressed calls.
  1515. //
  1516. } else {
  1517. PCOMPRESSED_DATA_INFO CompressedDataInfo;
  1518. PMDL *NewMdl;
  1519. ASSERT((StartingVbo & (NTFS_CHUNK_SIZE - 1)) == 0);
  1520. if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT | SCB_STATE_REALLOCATE_ON_WRITE )) {
  1521. try_return( Status = STATUS_INVALID_READ_MODE );
  1522. }
  1523. //
  1524. // Get out if COW is not supported.
  1525. //
  1526. if (!NtfsEnableCompressedIO) {
  1527. try_return( Status = STATUS_INVALID_READ_MODE );
  1528. }
  1529. if ((Header->FileObjectC == NULL) ||
  1530. (Header->FileObjectC->PrivateCacheMap == NULL)) {
  1531. //
  1532. // Make sure we are serialized with the FileSizes, and
  1533. // will remove this condition if we abort.
  1534. //
  1535. if (!DoingIoAtEof) {
  1536. FsRtlLockFsRtlHeader( Header );
  1537. IrpContext->CleanupStructure = Scb;
  1538. }
  1539. NtfsCreateInternalCompressedStream( IrpContext, Scb, FALSE, NULL );
  1540. if (!DoingIoAtEof) {
  1541. FsRtlUnlockFsRtlHeader( Header );
  1542. IrpContext->CleanupStructure = NULL;
  1543. }
  1544. }
  1545. //
  1546. // Assume success.
  1547. //
  1548. Irp->IoStatus.Status = Status = STATUS_SUCCESS;
  1549. Irp->IoStatus.Information = (ULONG)(ByteRange - StartingVbo);
  1550. //
  1551. // Based on the Mdl minor function, set up the appropriate
  1552. // parameters for the call below.
  1553. //
  1554. if (!FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
  1555. //
  1556. // Get hold of the user's buffer.
  1557. //
  1558. SystemBuffer = NtfsMapUserBuffer( Irp, NormalPagePriority );
  1559. NewMdl = NULL;
  1560. } else {
  1561. //
  1562. // We will deliver the Mdl directly to the Irp.
  1563. //
  1564. SystemBuffer = NULL;
  1565. NewMdl = &Irp->MdlAddress;
  1566. }
  1567. CompressedDataInfo = (PCOMPRESSED_DATA_INFO)IrpContext->Union.AuxiliaryBuffer->Buffer;
  1568. CompressedDataInfo->CompressionFormatAndEngine =
  1569. (USHORT)((Scb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK) + 1);
  1570. CompressedDataInfo->CompressionUnitShift = (UCHAR)(Scb->CompressionUnitShift + Vcb->ClusterShift);
  1571. CompressedDataInfo->ChunkShift = NTFS_CHUNK_SHIFT;
  1572. CompressedDataInfo->ClusterShift = (UCHAR)Vcb->ClusterShift;
  1573. CompressedDataInfo->Reserved = 0;
  1574. //
  1575. // Do the compressed read in common code with the Fast Io path.
  1576. // We do it from a loop because we may need to create the other
  1577. // data stream.
  1578. //
  1579. while (TRUE) {
  1580. //
  1581. // Make sure to reset this if we pass through the loop again.
  1582. //
  1583. CompressedDataInfo->NumberOfChunks = 0;
  1584. Status = NtfsCompressedCopyRead( FileObject,
  1585. (PLARGE_INTEGER)&StartingVbo,
  1586. (ULONG)ByteCount,
  1587. SystemBuffer,
  1588. NewMdl,
  1589. CompressedDataInfo,
  1590. IrpContext->Union.AuxiliaryBuffer->Length,
  1591. IoGetRelatedDeviceObject(FileObject),
  1592. Header,
  1593. Scb->CompressionUnit,
  1594. NTFS_CHUNK_SIZE );
  1595. //
  1596. // On successful Mdl requests we hang on to the PagingIo resource.
  1597. //
  1598. if ((NewMdl != NULL) && NT_SUCCESS(Status) && (*NewMdl != NULL)) {
  1599. PagingIoAcquired = FALSE;
  1600. }
  1601. //
  1602. // Check for the status that says we need to create the normal
  1603. // data stream, else we are done.
  1604. //
  1605. if (Status != STATUS_NOT_MAPPED_DATA) {
  1606. break;
  1607. }
  1608. //
  1609. // Make sure we are serialized with the FileSizes, and
  1610. // will remove this condition if we abort.
  1611. //
  1612. if (!DoingIoAtEof) {
  1613. FsRtlLockFsRtlHeader( Header );
  1614. IrpContext->CleanupStructure = Scb;
  1615. }
  1616. //
  1617. // Create the normal data stream and loop back to try again.
  1618. //
  1619. NtfsCreateInternalAttributeStream( IrpContext, Scb, FALSE, NULL );
  1620. if (!DoingIoAtEof) {
  1621. FsRtlUnlockFsRtlHeader( Header );
  1622. IrpContext->CleanupStructure = NULL;
  1623. }
  1624. }
  1625. }
  1626. #endif
  1627. }
  1628. try_exit: NOTHING;
  1629. //
  1630. // If the request was not posted, deal with it.
  1631. //
  1632. if (Irp) {
  1633. if (!PostIrp) {
  1634. DebugTrace( 0, Dbg, ("Completing request with status = %08lx\n",
  1635. Status));
  1636. DebugTrace( 0, Dbg, (" Information = %08lx\n",
  1637. Irp->IoStatus.Information));
  1638. //
  1639. // If the file was opened for Synchronous IO, update the current
  1640. // file position. Make sure to use the original file object
  1641. // not an internal stream we may use within this routine.
  1642. // Information field contains the actual bytes read
  1643. //
  1644. if (!PagingIo) {
  1645. if (SynchronousIo) {
  1646. IrpSp->FileObject->CurrentByteOffset.QuadPart = StartingVbo + Irp->IoStatus.Information;
  1647. }
  1648. //
  1649. // On success, do the following to let us update last access time.
  1650. //
  1651. if (NT_SUCCESS( Status )) {
  1652. SetFlag( IrpSp->FileObject->Flags, FO_FILE_FAST_IO_READ );
  1653. }
  1654. }
  1655. //
  1656. // Abort transaction on error by raising.
  1657. //
  1658. NtfsCleanupTransaction( IrpContext, Status, FALSE );
  1659. }
  1660. }
  1661. } finally {
  1662. DebugUnwind( NtfsCommonRead );
  1663. #ifdef COMPRESS_ON_WIRE
  1664. //
  1665. // Clean up any Bcb from read/synchronize compressed.
  1666. //
  1667. if (CompressionSync != NULL) {
  1668. NtfsReleaseCompressionSync( CompressionSync );
  1669. }
  1670. #endif
  1671. //
  1672. // If the Scb has been acquired, release it.
  1673. //
  1674. if (PagingIoAcquired) {
  1675. NtfsReleasePagingResource( IrpContext, Scb );
  1676. }
  1677. if (Irp) {
  1678. if (ScbAcquired) {
  1679. NtfsReleaseResource( IrpContext, Scb );
  1680. }
  1681. }
  1682. }
  1683. //
  1684. // Complete the request if we didn't post it and no exception
  1685. //
  1686. // Note that NtfsCompleteRequest does the right thing if either
  1687. // IrpContext or Irp are NULL
  1688. //
  1689. if (!PostIrp) {
  1690. NtfsCompleteRequest( IrpContext, Irp, Status );
  1691. } else if (!OplockPostIrp) {
  1692. Status = NtfsPostRequest( IrpContext, Irp );
  1693. }
  1694. return Status;
  1695. }
  1696. VOID
  1697. NtfsNonCachedResidentRead (
  1698. IN PIRP_CONTEXT IrpContext,
  1699. IN PIRP Irp,
  1700. IN PSCB Scb,
  1701. IN ULONG StartingVbo,
  1702. IN ULONG ByteCount
  1703. )
  1704. /*++
  1705. Routine Description:
  1706. Read a resident file record directly for the non cached path. This is
  1707. done separately to scope the attribute enumeration context so its not present
  1708. in most of the read path and for simplicity
  1709. Arguments:
  1710. IrpContext - If present this an IrpContext put on the caller's stack
  1711. to avoid having to allocate it from pool.
  1712. Irp - Supplies the Irp being processed
  1713. Scb - scb to read from
  1714. StartingVbo - start offset in the file - since its resident can be stored in a ulong
  1715. ByteCount - bytes to read - since its resident can be stored in a ulong
  1716. Return Value:
  1717. NTSTATUS - The FSD status for the IRP
  1718. --*/
  1719. {
  1720. PVOID SystemBuffer;
  1721. PUCHAR AttrValue;
  1722. PVCB Vcb = IrpContext->Vcb;
  1723. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  1724. UCHAR Buffer[sizeof( MDL ) + sizeof( PFN_NUMBER ) * 2];
  1725. PMDL PartialMdl = (PMDL) Buffer;
  1726. BOOLEAN ReservedInUse = FALSE;
  1727. //
  1728. // We're reading from a resident attribute
  1729. //
  1730. ASSERT( ByteCount < 0x400 );
  1731. //
  1732. // Get hold of the user's buffer.
  1733. //
  1734. SystemBuffer = NtfsMapUserBufferNoRaise( Irp, NormalPagePriority );
  1735. if (!SystemBuffer) {
  1736. ASSERT( Irp->MdlAddress != NULL );
  1737. MmInitializeMdl( PartialMdl, NULL, 2 * PAGE_SIZE );
  1738. ExAcquireFastMutexUnsafe( &Vcb->ReservedMappingMutex );
  1739. ReservedInUse = TRUE;
  1740. IoBuildPartialMdl( Irp->MdlAddress, PartialMdl, Add2Ptr( MmGetMdlBaseVa( Irp->MdlAddress ), MmGetMdlByteOffset( Irp->MdlAddress )), ByteCount );
  1741. SystemBuffer = MmMapLockedPagesWithReservedMapping( Vcb->ReservedMapping,
  1742. RESERVE_POOL_TAG,
  1743. PartialMdl,
  1744. MmCached );
  1745. ASSERT( SystemBuffer != NULL );
  1746. }
  1747. //
  1748. // This is a resident attribute, we need to look it up
  1749. // and copy the desired range of bytes to the user's
  1750. // buffer.
  1751. //
  1752. NtfsInitializeAttributeContext( &AttrContext );
  1753. try {
  1754. NtfsLookupAttributeForScb( IrpContext,
  1755. Scb,
  1756. NULL,
  1757. &AttrContext );
  1758. AttrValue = NtfsAttributeValue( NtfsFoundAttribute( &AttrContext ));
  1759. RtlCopyMemory( SystemBuffer,
  1760. Add2Ptr( AttrValue, StartingVbo ),
  1761. ByteCount );
  1762. Irp->IoStatus.Information = ByteCount;
  1763. } finally {
  1764. if (ReservedInUse) {
  1765. MmUnmapReservedMapping( Vcb->ReservedMapping, RESERVE_POOL_TAG, PartialMdl );
  1766. MmPrepareMdlForReuse( PartialMdl );
  1767. ExReleaseFastMutexUnsafe( &Vcb->ReservedMappingMutex );
  1768. }
  1769. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  1770. }
  1771. return;
  1772. }