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.

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