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.

2269 lines
75 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. FstIoSup.c
  5. Abstract:
  6. This module implements the fast I/O routines for Ntfs.
  7. Author:
  8. Tom Miller [TomM] 16-May-96
  9. Revision History:
  10. --*/
  11. #include "NtfsProc.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, NtfsCopyReadA)
  14. #pragma alloc_text(PAGE, NtfsCopyWriteA)
  15. #pragma alloc_text(PAGE, NtfsMdlReadA)
  16. #pragma alloc_text(PAGE, NtfsPrepareMdlWriteA)
  17. #pragma alloc_text(PAGE, NtfsWaitForIoAtEof)
  18. #pragma alloc_text(PAGE, NtfsFinishIoAtEof)
  19. #endif
  20. #ifdef NTFS_RWC_DEBUG
  21. PRWC_HISTORY_ENTRY
  22. NtfsGetHistoryEntry (
  23. IN PSCB Scb
  24. );
  25. #endif
  26. BOOLEAN
  27. NtfsCopyReadA (
  28. IN PFILE_OBJECT FileObject,
  29. IN PLARGE_INTEGER FileOffset,
  30. IN ULONG Length,
  31. IN BOOLEAN Wait,
  32. IN ULONG LockKey,
  33. OUT PVOID Buffer,
  34. OUT PIO_STATUS_BLOCK IoStatus,
  35. IN PDEVICE_OBJECT DeviceObject
  36. )
  37. /*++
  38. Routine Description:
  39. This routine does a fast cached read bypassing the usual file system
  40. entry routine (i.e., without the Irp). It is used to do a copy read
  41. of a cached file object. For a complete description of the arguments
  42. see CcCopyRead.
  43. Arguments:
  44. FileObject - Pointer to the file object being read.
  45. FileOffset - Byte offset in file for desired data.
  46. Length - Length of desired data in bytes.
  47. Wait - FALSE if caller may not block, TRUE otherwise
  48. Buffer - Pointer to output buffer to which data should be copied.
  49. IoStatus - Pointer to standard I/O status block to receive the status
  50. for the transfer.
  51. Return Value:
  52. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  53. if there is an I/O error.
  54. TRUE - if the data is being delivered
  55. --*/
  56. {
  57. PNTFS_ADVANCED_FCB_HEADER Header;
  58. LARGE_INTEGER BeyondLastByte;
  59. PDEVICE_OBJECT targetVdo;
  60. #ifdef COMPRESS_ON_WIRE
  61. PCOMPRESSION_SYNC CompressionSync = NULL;
  62. #endif
  63. BOOLEAN WasDataRead = TRUE;
  64. ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES( FileOffset->QuadPart, Length );
  65. BOOLEAN DoingIoAtEof = FALSE;
  66. UNREFERENCED_PARAMETER( DeviceObject );
  67. PAGED_CODE();
  68. #ifdef NTFS_NO_FASTIO
  69. UNREFERENCED_PARAMETER( FileObject );
  70. UNREFERENCED_PARAMETER( FileOffset );
  71. UNREFERENCED_PARAMETER( Length );
  72. UNREFERENCED_PARAMETER( Wait );
  73. UNREFERENCED_PARAMETER( LockKey );
  74. UNREFERENCED_PARAMETER( Buffer );
  75. UNREFERENCED_PARAMETER( IoStatus );
  76. return FALSE;
  77. #endif
  78. //
  79. // Don't take the fast io path if someone is already active in this thread.
  80. //
  81. if (IoGetTopLevelIrp() != NULL) {
  82. return FALSE;
  83. }
  84. //
  85. // Special case a read of zero length
  86. //
  87. if (Length != 0) {
  88. //
  89. // Get a real pointer to the common fcb header. Check for overflow.
  90. //
  91. if (MAXLONGLONG - FileOffset->QuadPart < (LONGLONG)Length) {
  92. return FALSE;
  93. }
  94. BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  95. Header = (PNTFS_ADVANCED_FCB_HEADER)FileObject->FsContext;
  96. //
  97. // Enter the file system
  98. //
  99. FsRtlEnterFileSystem();
  100. //
  101. // Make our best guess on whether we need the file exclusive
  102. // or shared. Note that we do not check FileOffset->HighPart
  103. // until below.
  104. //
  105. if (Wait) {
  106. FsRtlIncrementCcFastReadWait();
  107. } else {
  108. FsRtlIncrementCcFastReadNoWait();
  109. }
  110. if ((Header->PagingIoResource == NULL) ||
  111. !ExAcquireResourceSharedLite(Header->PagingIoResource, Wait)) {
  112. FsRtlIncrementCcFastReadResourceMiss();
  113. WasDataRead = FALSE;
  114. goto Done2;
  115. }
  116. //
  117. // Now synchronize with the FsRtl Header
  118. //
  119. NtfsAcquireFsrtlHeader( (PSCB)Header );
  120. //
  121. // Now see if we are reading beyond ValidDataLength. We have to
  122. // do it now so that our reads are not nooped.
  123. //
  124. if (BeyondLastByte.QuadPart > Header->ValidDataLength.QuadPart) {
  125. //
  126. // We must serialize with anyone else doing I/O at beyond
  127. // ValidDataLength, and then remember if we need to declare
  128. // when we are done.
  129. //
  130. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  131. NtfsWaitForIoAtEof( Header, FileOffset, Length );
  132. //
  133. // Set the Flag if we are in fact beyond ValidDataLength.
  134. //
  135. if (DoingIoAtEof) {
  136. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  137. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  138. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  139. } else {
  140. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  141. #endif
  142. }
  143. }
  144. NtfsReleaseFsrtlHeader( (PSCB)Header );
  145. //
  146. // Now that the File is acquired shared, we can safely test if it
  147. // is really cached and if we can do fast i/o and if not, then
  148. // release the fcb and return.
  149. //
  150. if ((FileObject->PrivateCacheMap == NULL) ||
  151. (Header->IsFastIoPossible == FastIoIsNotPossible)) {
  152. FsRtlIncrementCcFastReadNotPossible();
  153. WasDataRead = FALSE;
  154. goto Done;
  155. }
  156. //
  157. // Check if fast I/O is questionable and if so then go ask the
  158. // file system the answer
  159. //
  160. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  161. PFAST_IO_DISPATCH FastIoDispatch;
  162. targetVdo = IoGetRelatedDeviceObject( FileObject );
  163. FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  164. //
  165. // All file systems that set "Is Questionable" had better support
  166. // fast I/O
  167. //
  168. ASSERT(FastIoDispatch != NULL);
  169. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  170. //
  171. // Call the file system to check for fast I/O. If the answer is
  172. // anything other than GoForIt then we cannot take the fast I/O
  173. // path.
  174. //
  175. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  176. FileOffset,
  177. Length,
  178. Wait,
  179. LockKey,
  180. TRUE, // read operation
  181. IoStatus,
  182. targetVdo )) {
  183. //
  184. // Fast I/O is not possible so release the Fcb and return.
  185. //
  186. FsRtlIncrementCcFastReadNotPossible();
  187. WasDataRead = FALSE;
  188. goto Done;
  189. }
  190. }
  191. //
  192. // Check for read past file size.
  193. //
  194. if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) {
  195. if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) {
  196. IoStatus->Status = STATUS_END_OF_FILE;
  197. IoStatus->Information = 0;
  198. goto Done;
  199. }
  200. Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart );
  201. }
  202. //
  203. // We can do fast i/o so call the cc routine to do the work and then
  204. // release the fcb when we've done. If for whatever reason the
  205. // copy read fails, then return FALSE to our caller.
  206. //
  207. // Also mark this as the top level "Irp" so that lower file system
  208. // levels will not attempt a pop-up
  209. //
  210. IoSetTopLevelIrp( (PIRP) FSRTL_FAST_IO_TOP_LEVEL_IRP );
  211. try {
  212. //
  213. // If there is a compressed section, then synchronize with that cache.
  214. //
  215. IoStatus->Status = STATUS_SUCCESS;
  216. #ifdef COMPRESS_ON_WIRE
  217. //
  218. // If there is a compressed section, then we have to synchronize with
  219. // the data out there. Note the FileObjectC better also be there, or else
  220. // we would have made the fast I/O not possible.
  221. //
  222. if (((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  223. LONGLONG LocalOffset = FileOffset->QuadPart;
  224. ULONG LocalLength;
  225. ULONG LengthLeft = Length;
  226. ASSERT(Header->FileObjectC != NULL);
  227. //
  228. // If we are doing DoingIoAtEof then take the long path. Otherwise a recursive
  229. // flush will try to reacquire DoingIoAtEof and deadlock.
  230. //
  231. if (DoingIoAtEof) {
  232. WasDataRead = FALSE;
  233. } else {
  234. do {
  235. ULONG ViewOffset;
  236. //
  237. // Calculate length left in view.
  238. //
  239. ViewOffset = ((ULONG) LocalOffset & (VACB_MAPPING_GRANULARITY - 1));
  240. LocalLength = LengthLeft;
  241. if (LocalLength > VACB_MAPPING_GRANULARITY - ViewOffset) {
  242. LocalLength = VACB_MAPPING_GRANULARITY - ViewOffset;
  243. }
  244. //
  245. // Trim the read so we don't inadvertently go beyond the end of the
  246. // view because of the MM read ahead.
  247. //
  248. PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(((PVOID)(ULONG_PTR)((ULONG)LocalOffset)), LocalLength);
  249. if (LocalLength > (VACB_MAPPING_GRANULARITY - ((PageCount - 1) * PAGE_SIZE) - ViewOffset)) {
  250. #ifdef NTFS_RWC_DEBUG
  251. {
  252. PRWC_HISTORY_ENTRY NextBuffer;
  253. NextBuffer = NtfsGetHistoryEntry( (PSCB) Header );
  254. NextBuffer->Operation = TrimCopyRead;
  255. NextBuffer->Information = PageCount;
  256. NextBuffer->FileOffset = (ULONG) LocalOffset;
  257. NextBuffer->Length = (ULONG) LocalLength;
  258. }
  259. #endif
  260. LocalLength = (VACB_MAPPING_GRANULARITY - ((PageCount - 1) * PAGE_SIZE) - ViewOffset);
  261. PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(((PVOID)(ULONG_PTR)((ULONG)LocalOffset)), LocalLength);
  262. ASSERT( LocalLength <= (VACB_MAPPING_GRANULARITY - ((PageCount - 1) * PAGE_SIZE) - ViewOffset) );
  263. }
  264. IoStatus->Status = NtfsSynchronizeUncompressedIo( (PSCB)Header,
  265. &LocalOffset,
  266. LocalLength,
  267. FALSE,
  268. &CompressionSync );
  269. if (NT_SUCCESS(IoStatus->Status)) {
  270. if (Wait && ((BeyondLastByte.HighPart | Header->FileSize.HighPart) == 0)) {
  271. CcFastCopyRead( FileObject,
  272. (ULONG)LocalOffset,
  273. LocalLength,
  274. PageCount,
  275. Buffer,
  276. IoStatus );
  277. ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) ||
  278. ((FileOffset->LowPart + IoStatus->Information) <= Header->FileSize.LowPart));
  279. } else {
  280. WasDataRead = CcCopyRead( FileObject,
  281. (PLARGE_INTEGER)&LocalOffset,
  282. LocalLength,
  283. Wait,
  284. Buffer,
  285. IoStatus );
  286. ASSERT( !WasDataRead || (IoStatus->Status == STATUS_END_OF_FILE) ||
  287. ((LocalOffset + (LONG_PTR) IoStatus->Information) <= Header->FileSize.QuadPart));
  288. }
  289. LocalOffset += LocalLength;
  290. LengthLeft -= LocalLength;
  291. Buffer = Add2Ptr( Buffer, LocalLength );
  292. }
  293. } while ((LengthLeft != 0) && WasDataRead && NT_SUCCESS(IoStatus->Status));
  294. //
  295. // Remember the full amount of the read.
  296. //
  297. if (WasDataRead) {
  298. IoStatus->Information = Length;
  299. }
  300. }
  301. } else {
  302. #endif
  303. #ifdef SYSCACHE_DEBUG
  304. if (ScbIsBeingLogged( (PSCB)Header )) {
  305. ULONG Flags = SCE_FLAG_READ | SCE_FLAG_FASTIO;
  306. if (!Wait)
  307. {
  308. Flags |= SCE_FLAG_ASYNC;
  309. }
  310. ASSERT( ((PSCB)Header)->NonpagedScb->SegmentObject.ImageSectionObject == NULL );
  311. FsRtlLogSyscacheEvent( ((PSCB)Header), SCE_READ, Flags, FileOffset->QuadPart, Length, (LONGLONG)FileObject );
  312. }
  313. #endif
  314. if (Wait && ((BeyondLastByte.HighPart | Header->FileSize.HighPart) == 0)) {
  315. CcFastCopyRead( FileObject,
  316. FileOffset->LowPart,
  317. Length,
  318. PageCount,
  319. Buffer,
  320. IoStatus );
  321. ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) ||
  322. ((FileOffset->LowPart + IoStatus->Information) <= Header->FileSize.LowPart));
  323. } else {
  324. WasDataRead = CcCopyRead( FileObject,
  325. FileOffset,
  326. Length,
  327. Wait,
  328. Buffer,
  329. IoStatus );
  330. ASSERT( !WasDataRead || (IoStatus->Status == STATUS_END_OF_FILE) ||
  331. ((FileOffset->QuadPart + (LONG_PTR) IoStatus->Information) <= Header->FileSize.QuadPart));
  332. }
  333. #ifdef COMPRESS_ON_WIRE
  334. }
  335. #endif
  336. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  337. if (WasDataRead) {
  338. FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information;
  339. }
  340. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  341. ? EXCEPTION_EXECUTE_HANDLER
  342. : EXCEPTION_CONTINUE_SEARCH ) {
  343. WasDataRead = FALSE;
  344. }
  345. IoSetTopLevelIrp( NULL );
  346. #ifdef COMPRESS_ON_WIRE
  347. if (CompressionSync != NULL) {
  348. NtfsReleaseCompressionSync( CompressionSync );
  349. }
  350. #endif
  351. Done:
  352. if (DoingIoAtEof) {
  353. FsRtlUnlockFsRtlHeader( Header );
  354. }
  355. ExReleaseResourceLite( Header->PagingIoResource );
  356. Done2:
  357. FsRtlExitFileSystem();
  358. } else {
  359. //
  360. // A zero length transfer was requested.
  361. //
  362. IoStatus->Status = STATUS_SUCCESS;
  363. IoStatus->Information = 0;
  364. }
  365. return WasDataRead;
  366. }
  367. BOOLEAN
  368. NtfsCopyWriteA (
  369. IN PFILE_OBJECT FileObject,
  370. IN PLARGE_INTEGER FileOffset,
  371. IN ULONG Length,
  372. IN BOOLEAN Wait,
  373. IN ULONG LockKey,
  374. IN PVOID Buffer,
  375. OUT PIO_STATUS_BLOCK IoStatus,
  376. IN PDEVICE_OBJECT DeviceObject
  377. )
  378. /*++
  379. Routine Description:
  380. This routine does a fast cached write bypassing the usual file system
  381. entry routine (i.e., without the Irp). It is used to do a copy write
  382. of a cached file object. For a complete description of the arguments
  383. see CcCopyWrite.
  384. Arguments:
  385. FileObject - Pointer to the file object being write.
  386. FileOffset - Byte offset in file for desired data.
  387. Length - Length of desired data in bytes.
  388. Wait - FALSE if caller may not block, TRUE otherwise
  389. Buffer - Pointer to output buffer to which data should be copied.
  390. IoStatus - Pointer to standard I/O status block to receive the status
  391. for the transfer.
  392. Return Value:
  393. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  394. if there is an I/O error.
  395. TRUE - if the data is being delivered
  396. --*/
  397. {
  398. PNTFS_ADVANCED_FCB_HEADER Header;
  399. LARGE_INTEGER Offset;
  400. LARGE_INTEGER NewFileSize;
  401. LARGE_INTEGER OldFileSize;
  402. #ifdef COMPRESS_ON_WIRE
  403. PCOMPRESSION_SYNC CompressionSync = NULL;
  404. #endif
  405. PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject );
  406. PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  407. BOOLEAN DoingIoAtEof = FALSE;
  408. BOOLEAN WasDataWritten = FALSE;
  409. #ifdef SYSCACHE_DEBUG
  410. PSCB Scb = (PSCB) FileObject->FsContext;
  411. #endif
  412. UNREFERENCED_PARAMETER( DeviceObject );
  413. PAGED_CODE();
  414. #ifdef NTFS_NO_FASTIO
  415. UNREFERENCED_PARAMETER( FileObject );
  416. UNREFERENCED_PARAMETER( FileOffset );
  417. UNREFERENCED_PARAMETER( Length );
  418. UNREFERENCED_PARAMETER( Wait );
  419. UNREFERENCED_PARAMETER( LockKey );
  420. UNREFERENCED_PARAMETER( Buffer );
  421. UNREFERENCED_PARAMETER( IoStatus );
  422. return FALSE;
  423. #endif
  424. //
  425. // Don't take the fast io path if someone is already active in this thread.
  426. //
  427. if (IoGetTopLevelIrp() != NULL) {
  428. return FALSE;
  429. }
  430. //
  431. // Get a real pointer to the common fcb header
  432. //
  433. Header = (PNTFS_ADVANCED_FCB_HEADER)FileObject->FsContext;
  434. //
  435. // Do we need to verify the volume? If so, we must go to the file
  436. // system. Also return FALSE if FileObject is write through, the
  437. // File System must do that.
  438. //
  439. if (!FlagOn( FileObject->Flags, FO_WRITE_THROUGH ) &&
  440. CcCanIWrite( FileObject, Length, Wait, FALSE ) &&
  441. CcCopyWriteWontFlush( FileObject, FileOffset, Length ) &&
  442. (Header->PagingIoResource != NULL)) {
  443. //
  444. // Assume our transfer will work
  445. //
  446. IoStatus->Status = STATUS_SUCCESS;
  447. IoStatus->Information = Length;
  448. //
  449. // Special case the zero byte length
  450. //
  451. if (Length != 0) {
  452. //
  453. // Enter the file system
  454. //
  455. FsRtlEnterFileSystem();
  456. //
  457. // Split into separate paths for increased performance. First
  458. // we have the faster path which only supports Wait == TRUE and
  459. // 32 bits. We will make an unsafe test on whether the fast path
  460. // is ok, then just return FALSE later if we were wrong. This
  461. // should virtually never happen.
  462. //
  463. // IMPORTANT NOTE: It is very important that any changes mad to
  464. // this path also be applied to the 64-bit path
  465. // which is the else of this test!
  466. //
  467. NewFileSize.QuadPart = FileOffset->QuadPart + Length;
  468. Offset = *FileOffset;
  469. if (Wait && (Header->AllocationSize.HighPart == 0)) {
  470. //
  471. // Prevent truncates by acquiring paging I/O
  472. //
  473. ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
  474. //
  475. // Now synchronize with the FsRtl Header
  476. //
  477. NtfsAcquireFsrtlHeader( (PSCB) Header );
  478. //
  479. // Now see if we will change FileSize. We have to do it now
  480. // so that our reads are not nooped.
  481. //
  482. if ((FileOffset->HighPart < 0) || (NewFileSize.LowPart > Header->ValidDataLength.LowPart)) {
  483. //
  484. // We can change FileSize and ValidDataLength if either, no one
  485. // else is now, or we are still extending after waiting.
  486. //
  487. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  488. NtfsWaitForIoAtEof( Header, FileOffset, Length );
  489. //
  490. // Set the Flag if we are changing FileSize or ValidDataLength,
  491. // and save current values.
  492. //
  493. if (DoingIoAtEof) {
  494. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  495. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  496. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  497. #endif
  498. //
  499. // Now that we are synchronized for end of file cases,
  500. // we can calculate the real offset for this transfer and
  501. // the new file size (if we succeed).
  502. //
  503. if ((FileOffset->HighPart < 0)) {
  504. Offset = Header->FileSize;
  505. }
  506. //
  507. // Above we allowed any negative .HighPart for the 32-bit path,
  508. // but now we are counting on the I/O system to have thrown
  509. // any negative number other than write to end of file.
  510. //
  511. ASSERT(Offset.HighPart >= 0);
  512. //
  513. // Now calculate the new FileSize and see if we wrapped the
  514. // 32-bit boundary.
  515. //
  516. NewFileSize.QuadPart = Offset.QuadPart + Length;
  517. //
  518. // Update Filesize now so that we do not truncate reads.
  519. //
  520. OldFileSize.QuadPart = Header->FileSize.QuadPart;
  521. if (NewFileSize.QuadPart > Header->FileSize.QuadPart) {
  522. //
  523. // If we are beyond AllocationSize, make sure we will
  524. // ErrOut below, and don't modify FileSize now!
  525. //
  526. if (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) {
  527. NewFileSize.QuadPart = (LONGLONG)0x7FFFFFFFFFFFFFFF;
  528. } else {
  529. Header->FileSize.QuadPart = NewFileSize.QuadPart;
  530. }
  531. }
  532. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  533. } else {
  534. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  535. #endif
  536. }
  537. }
  538. NtfsReleaseFsrtlHeader( (PSCB)Header );
  539. //
  540. // Now that the File is acquired shared, we can safely test
  541. // if it is really cached and if we can do fast i/o and we
  542. // do not have to extend. If not then release the fcb and
  543. // return.
  544. //
  545. // Get out if we have to do any zeroing. This is handled in the main path
  546. // which deals with sparse files - cc rollbacks etc.
  547. //
  548. // If there is a compressed stream and we are DoingIoAtEof, then get
  549. // out because we could deadlock on a recursive flush from the synchronize.
  550. //
  551. if ((FileObject->PrivateCacheMap == NULL) ||
  552. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  553. /* Remove? */ (NewFileSize.LowPart > Header->AllocationSize.QuadPart) ||
  554. (Offset.LowPart > (Header->ValidDataLength.LowPart)) ||
  555. (NewFileSize.HighPart != 0) ||
  556. #ifdef COMPRESS_ON_WIRE
  557. ((((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) &&
  558. DoingIoAtEof)
  559. #else
  560. FALSE
  561. #endif
  562. ) {
  563. goto ErrOut;
  564. }
  565. //
  566. // Check if fast I/O is questionable and if so then go ask
  567. // the file system the answer
  568. //
  569. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  570. targetVdo = IoGetRelatedDeviceObject( FileObject );
  571. FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  572. //
  573. // All file system then set "Is Questionable" had better
  574. // support fast I/O
  575. //
  576. ASSERT(FastIoDispatch != NULL);
  577. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  578. //
  579. // Call the file system to check for fast I/O. If the
  580. // answer is anything other than GoForIt then we cannot
  581. // take the fast I/O path.
  582. //
  583. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  584. &Offset,
  585. Length,
  586. TRUE,
  587. LockKey,
  588. FALSE, // write operation
  589. IoStatus,
  590. targetVdo )) {
  591. //
  592. // Fast I/O is not possible so cleanup and return.
  593. //
  594. goto ErrOut;
  595. }
  596. }
  597. //
  598. // We can do fast i/o so call the cc routine to do the work
  599. // and then release the fcb when we've done. If for whatever
  600. // reason the copy write fails, then return FALSE to our
  601. // caller.
  602. //
  603. // Also mark this as the top level "Irp" so that lower file
  604. // system levels will not attempt a pop-up
  605. //
  606. IoSetTopLevelIrp( (PIRP) FSRTL_FAST_IO_TOP_LEVEL_IRP );
  607. try {
  608. ASSERT( Offset.LowPart <= Header->ValidDataLength.LowPart );
  609. #ifdef COMPRESS_ON_WIRE
  610. //
  611. // If there is a compressed section, then we have to synchronize with
  612. // the data out there. Note the FileObjectC better also be there, or else
  613. // we would have made the fast I/O not possible.
  614. //
  615. if (((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  616. LONGLONG LocalOffset = Offset.QuadPart;
  617. ULONG LocalLength;
  618. ULONG LengthLeft = Length;
  619. ASSERT( Header->FileObjectC != NULL );
  620. do {
  621. //
  622. // Calculate length left in view.
  623. //
  624. LocalLength = LengthLeft;
  625. if (LocalLength > (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)))) {
  626. LocalLength = (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)));
  627. }
  628. IoStatus->Status = NtfsSynchronizeUncompressedIo( (PSCB)Header,
  629. &LocalOffset,
  630. LocalLength,
  631. TRUE,
  632. &CompressionSync );
  633. if (NT_SUCCESS(IoStatus->Status)) {
  634. WasDataWritten = TRUE;
  635. CcFastCopyWrite( FileObject,
  636. (ULONG)LocalOffset,
  637. LocalLength,
  638. Buffer );
  639. LocalOffset += LocalLength;
  640. LengthLeft -= LocalLength;
  641. Buffer = Add2Ptr( Buffer, LocalLength );
  642. }
  643. } while ((LengthLeft != 0) && NT_SUCCESS( IoStatus->Status ));
  644. } else {
  645. #endif
  646. CcFastCopyWrite( FileObject,
  647. Offset.LowPart,
  648. Length,
  649. Buffer );
  650. WasDataWritten = TRUE;
  651. #ifdef COMPRESS_ON_WIRE
  652. }
  653. #endif
  654. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  655. ? EXCEPTION_EXECUTE_HANDLER
  656. : EXCEPTION_CONTINUE_SEARCH ) {
  657. WasDataWritten = FALSE;
  658. }
  659. IoSetTopLevelIrp( NULL );
  660. #ifdef COMPRESS_ON_WIRE
  661. if (CompressionSync != NULL) {
  662. NtfsReleaseCompressionSync( CompressionSync );
  663. }
  664. #endif
  665. //
  666. // If we succeeded, see if we have to update FileSize or
  667. // ValidDataLength.
  668. //
  669. if (WasDataWritten) {
  670. //
  671. // Set this handle as having modified the file and update
  672. // the current file position pointer
  673. //
  674. FileObject->Flags |= FO_FILE_MODIFIED;
  675. FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
  676. if (DoingIoAtEof) {
  677. #ifdef COMPRESS_ON_WIRE
  678. CC_FILE_SIZES CcFileSizes;
  679. #endif
  680. //
  681. // Make sure Cc knows the current FileSize, as set above,
  682. // (we may not have changed it). Update ValidDataLength
  683. // and finish EOF.
  684. //
  685. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  686. NtfsAcquireFsrtlHeader( (PSCB) Header );
  687. CcGetFileSizePointer(FileObject)->LowPart = Header->FileSize.LowPart;
  688. Header->ValidDataLength = NewFileSize;
  689. #ifdef SYSCACHE_DEBUG
  690. if (ScbIsBeingLogged( ((PSCB)Header) )) {
  691. FsRtlLogSyscacheEvent( Scb, SCE_VDL_CHANGE, SCE_FLAG_WRITE | SCE_FLAG_FASTIO, 0, 0, NewFileSize.QuadPart );
  692. }
  693. #endif
  694. #ifdef COMPRESS_ON_WIRE
  695. CcFileSizes = *(PCC_FILE_SIZES)&Header->AllocationSize;
  696. #endif
  697. NtfsVerifySizes( Header );
  698. NtfsFinishIoAtEof( Header );
  699. NtfsReleaseFsrtlHeader( (PSCB) Header );
  700. #ifdef COMPRESS_ON_WIRE
  701. //
  702. // Update the CompressedCache with ValidDataLength.
  703. //
  704. if (Header->FileObjectC != NULL) {
  705. CcSetFileSizes( Header->FileObjectC, &CcFileSizes );
  706. }
  707. #endif
  708. }
  709. goto Done1;
  710. }
  711. //
  712. // Here is the 64-bit or no-wait path.
  713. //
  714. } else {
  715. //
  716. // Prevent truncates by acquiring paging I/O
  717. //
  718. WasDataWritten = ExAcquireResourceSharedLite( Header->PagingIoResource, Wait );
  719. if (!WasDataWritten) {
  720. goto Done2;
  721. }
  722. //
  723. // Now synchronize with the FsRtl Header
  724. //
  725. NtfsAcquireFsrtlHeader( (PSCB) Header );
  726. //
  727. // Now see if we will change FileSize. We have to do it now
  728. // so that our reads are not nooped.
  729. //
  730. if ((FileOffset->QuadPart < 0) || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) {
  731. //
  732. // We can change FileSize and ValidDataLength if either, no one
  733. // else is now, or we are still extending after waiting.
  734. //
  735. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  736. NtfsWaitForIoAtEof( Header, FileOffset, Length );
  737. //
  738. // Set the Flag if we are changing FileSize or ValidDataLength,
  739. // and save current values.
  740. //
  741. if (DoingIoAtEof) {
  742. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  743. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  744. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  745. #endif
  746. //
  747. // Now that we are synchronized for end of file cases,
  748. // we can calculate the real offset for this transfer and
  749. // the new file size (if we succeed).
  750. //
  751. if ((FileOffset->QuadPart < 0)) {
  752. Offset = Header->FileSize;
  753. }
  754. //
  755. // Now calculate the new FileSize and see if we wrapped the
  756. // 32-bit boundary.
  757. //
  758. NewFileSize.QuadPart = Offset.QuadPart + Length;
  759. //
  760. // Update Filesize now so that we do not truncate reads.
  761. //
  762. OldFileSize.QuadPart = Header->FileSize.QuadPart;
  763. if (NewFileSize.QuadPart > Header->FileSize.QuadPart) {
  764. //
  765. // If we are beyond AllocationSize, make sure we will
  766. // ErrOut below, and don't modify FileSize now!
  767. //
  768. if (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) {
  769. NewFileSize.QuadPart = (LONGLONG)0x7FFFFFFFFFFFFFFF;
  770. } else {
  771. Header->FileSize.QuadPart = NewFileSize.QuadPart;
  772. }
  773. }
  774. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  775. } else {
  776. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  777. #endif
  778. }
  779. }
  780. NtfsReleaseFsrtlHeader( (PSCB) Header );
  781. //
  782. // Now that the File is acquired shared, we can safely test
  783. // if it is really cached and if we can do fast i/o and we
  784. // do not have to extend. If not then release the fcb and
  785. // return.
  786. //
  787. // Get out if we need to zero anything - handle in the main path
  788. //
  789. // If there is a compressed stream and we are DoingIoAtEof, then get
  790. // out because we could deadlock on a recursive flush from the synchronize.
  791. //
  792. if ((FileObject->PrivateCacheMap == NULL) ||
  793. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  794. /* Remove? */ (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) ||
  795. (Offset.QuadPart > Header->ValidDataLength.QuadPart) ||
  796. #ifdef COMPRESS_ON_WIRE
  797. ((((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) &&
  798. DoingIoAtEof)
  799. #else
  800. FALSE
  801. #endif
  802. ) {
  803. goto ErrOut;
  804. }
  805. //
  806. // Check if fast I/O is questionable and if so then go ask
  807. // the file system the answer
  808. //
  809. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  810. targetVdo = IoGetRelatedDeviceObject( FileObject );
  811. FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  812. //
  813. // All file system then set "Is Questionable" had better
  814. // support fast I/O
  815. //
  816. ASSERT(FastIoDispatch != NULL);
  817. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  818. //
  819. // Call the file system to check for fast I/O. If the
  820. // answer is anything other than GoForIt then we cannot
  821. // take the fast I/O path.
  822. //
  823. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  824. &Offset,
  825. Length,
  826. Wait,
  827. LockKey,
  828. FALSE, // write operation
  829. IoStatus,
  830. targetVdo )) {
  831. //
  832. // Fast I/O is not possible so cleanup and return.
  833. //
  834. goto ErrOut;
  835. }
  836. }
  837. //
  838. // We can do fast i/o so call the cc routine to do the work
  839. // and then release the fcb when we've done. If for whatever
  840. // reason the copy write fails, then return FALSE to our
  841. // caller.
  842. //
  843. // Also mark this as the top level "Irp" so that lower file
  844. // system levels will not attempt a pop-up
  845. //
  846. IoSetTopLevelIrp( (PIRP) FSRTL_FAST_IO_TOP_LEVEL_IRP );
  847. try {
  848. ASSERT( Offset.QuadPart <= Header->ValidDataLength.QuadPart );
  849. #ifdef COMPRESS_ON_WIRE
  850. if (((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  851. LONGLONG LocalOffset = Offset.QuadPart;
  852. ULONG LocalLength;
  853. ULONG LengthLeft = Length;
  854. ASSERT(Header->FileObjectC != NULL);
  855. do {
  856. //
  857. // Calculate length left in view.
  858. //
  859. LocalLength = LengthLeft;
  860. if (LocalLength > (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)))) {
  861. LocalLength = (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)));
  862. }
  863. IoStatus->Status = NtfsSynchronizeUncompressedIo( (PSCB)Header,
  864. &LocalOffset,
  865. LocalLength,
  866. TRUE,
  867. &CompressionSync );
  868. if (NT_SUCCESS(IoStatus->Status)) {
  869. WasDataWritten = CcCopyWrite( FileObject,
  870. (PLARGE_INTEGER)&LocalOffset,
  871. LocalLength,
  872. Wait,
  873. Buffer );
  874. LocalOffset += LocalLength;
  875. LengthLeft -= LocalLength;
  876. Buffer = Add2Ptr( Buffer, LocalLength );
  877. }
  878. } while ((LengthLeft != 0) && WasDataWritten && NT_SUCCESS(IoStatus->Status));
  879. } else {
  880. #endif
  881. WasDataWritten = CcCopyWrite( FileObject,
  882. &Offset,
  883. Length,
  884. Wait,
  885. Buffer );
  886. #ifdef COMPRESS_ON_WIRE
  887. }
  888. #endif
  889. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  890. ? EXCEPTION_EXECUTE_HANDLER
  891. : EXCEPTION_CONTINUE_SEARCH ) {
  892. WasDataWritten = FALSE;
  893. }
  894. IoSetTopLevelIrp( NULL );
  895. #ifdef COMPRESS_ON_WIRE
  896. if (CompressionSync != NULL) {
  897. NtfsReleaseCompressionSync( CompressionSync );
  898. }
  899. #endif
  900. //
  901. // If we succeeded, see if we have to update FileSize ValidDataLength.
  902. //
  903. if (WasDataWritten) {
  904. //
  905. // Set this handle as having modified the file and update
  906. // the current file position pointer
  907. //
  908. FileObject->Flags |= FO_FILE_MODIFIED;
  909. FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
  910. if (DoingIoAtEof) {
  911. #ifdef COMPRESS_ON_WIRE
  912. CC_FILE_SIZES CcFileSizes;
  913. #endif
  914. //
  915. // Make sure Cc knows the current FileSize, as set above,
  916. // (we may not have changed it). Update ValidDataLength
  917. // and finish EOF.
  918. //
  919. NtfsAcquireFsrtlHeader( (PSCB) Header );
  920. CcGetFileSizePointer(FileObject)->QuadPart = Header->FileSize.QuadPart;
  921. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  922. Header->ValidDataLength = NewFileSize;
  923. #ifdef COMPRESS_ON_WIRE
  924. CcFileSizes = *(PCC_FILE_SIZES)&Header->AllocationSize;
  925. #endif
  926. NtfsVerifySizes( Header );
  927. NtfsFinishIoAtEof( Header );
  928. NtfsReleaseFsrtlHeader( (PSCB) Header );
  929. #ifdef SYSCACHE_DEBUG
  930. if (ScbIsBeingLogged( Scb )) {
  931. FsRtlLogSyscacheEvent( Scb, SCE_VDL_CHANGE, SCE_FLAG_WRITE | SCE_FLAG_FASTIO, 0, 0, NewFileSize.QuadPart );
  932. }
  933. #endif
  934. #ifdef COMPRESS_ON_WIRE
  935. //
  936. // Update the CompressedCache with ValidDataLength.
  937. //
  938. if (Header->FileObjectC != NULL) {
  939. CcSetFileSizes( Header->FileObjectC, &CcFileSizes );
  940. }
  941. #endif
  942. }
  943. goto Done1;
  944. }
  945. }
  946. ErrOut:
  947. WasDataWritten = FALSE;
  948. if (DoingIoAtEof) {
  949. NtfsAcquireFsrtlHeader( (PSCB) Header );
  950. #ifdef COMPRESS_ON_WIRE
  951. if (Header->FileObjectC != NULL) {
  952. *CcGetFileSizePointer(Header->FileObjectC) = OldFileSize;
  953. }
  954. #endif
  955. Header->FileSize = OldFileSize;
  956. NtfsFinishIoAtEof( Header );
  957. NtfsReleaseFsrtlHeader( (PSCB) Header );
  958. }
  959. Done1:
  960. ExReleaseResourceLite( Header->PagingIoResource );
  961. Done2:
  962. FsRtlExitFileSystem();
  963. } else {
  964. //
  965. // Noop case
  966. //
  967. WasDataWritten = TRUE;
  968. }
  969. } else {
  970. //
  971. // We could not do the I/O now.
  972. //
  973. WasDataWritten = FALSE;
  974. }
  975. return WasDataWritten;
  976. }
  977. BOOLEAN
  978. NtfsMdlReadA (
  979. IN PFILE_OBJECT FileObject,
  980. IN PLARGE_INTEGER FileOffset,
  981. IN ULONG Length,
  982. IN ULONG LockKey,
  983. OUT PMDL *MdlChain,
  984. OUT PIO_STATUS_BLOCK IoStatus,
  985. IN PDEVICE_OBJECT DeviceObject
  986. )
  987. /*++
  988. Routine Description:
  989. This routine does a fast cached mdl read bypassing the usual file system
  990. entry routine (i.e., without the Irp). It is used to do a copy read
  991. of a cached file object. For a complete description of the arguments
  992. see CcMdlRead.
  993. Arguments:
  994. FileObject - Pointer to the file object being read.
  995. FileOffset - Byte offset in file for desired data.
  996. Length - Length of desired data in bytes.
  997. MdlChain - On output it returns a pointer to an MDL chain describing
  998. the desired data.
  999. IoStatus - Pointer to standard I/O status block to receive the status
  1000. for the transfer.
  1001. Return Value:
  1002. FALSE - if the data was not delivered, or if there is an I/O error.
  1003. TRUE - if the data is being delivered
  1004. --*/
  1005. {
  1006. PNTFS_ADVANCED_FCB_HEADER Header;
  1007. #ifdef COMPRESS_ON_WIRE
  1008. PCOMPRESSION_SYNC CompressionSync = NULL;
  1009. #endif
  1010. BOOLEAN DoingIoAtEof = FALSE;
  1011. BOOLEAN WasDataRead = TRUE;
  1012. LARGE_INTEGER BeyondLastByte;
  1013. UNREFERENCED_PARAMETER( DeviceObject );
  1014. PAGED_CODE();
  1015. //
  1016. // Special case a read of zero length
  1017. //
  1018. if (Length == 0) {
  1019. IoStatus->Status = STATUS_SUCCESS;
  1020. IoStatus->Information = 0;
  1021. //
  1022. // Get a real pointer to the common fcb header
  1023. //
  1024. } else {
  1025. BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  1026. //
  1027. // Overflows should've been handled by the caller.
  1028. //
  1029. ASSERT(MAXLONGLONG - FileOffset->QuadPart >= (LONGLONG)Length);
  1030. Header = (PNTFS_ADVANCED_FCB_HEADER)FileObject->FsContext;
  1031. //
  1032. // Enter the file system
  1033. //
  1034. FsRtlEnterFileSystem();
  1035. #ifdef _WIN64
  1036. //
  1037. // The following should work for either 64 or 32 bits.
  1038. // Remove the 32 bit-only version in the #else clause
  1039. // after NT2K ships.
  1040. //
  1041. **((PULONG *)&CcFastMdlReadWait) += 1;
  1042. #else
  1043. *(PULONG)CcFastMdlReadWait += 1;
  1044. #endif
  1045. //
  1046. // Acquired shared on the common fcb header
  1047. //
  1048. if (Header->PagingIoResource == NULL) {
  1049. WasDataRead = FALSE;
  1050. goto Done2;
  1051. }
  1052. (VOID)ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
  1053. //
  1054. // Now synchronize with the FsRtl Header
  1055. //
  1056. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1057. //
  1058. // Now see if we are reading beyond ValidDataLength. We have to
  1059. // do it now so that our reads are not nooped.
  1060. //
  1061. if (BeyondLastByte.QuadPart > Header->ValidDataLength.QuadPart) {
  1062. //
  1063. // We must serialize with anyone else doing I/O at beyond
  1064. // ValidDataLength, and then remember if we need to declare
  1065. // when we are done.
  1066. //
  1067. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  1068. NtfsWaitForIoAtEof( Header, FileOffset, Length );
  1069. //
  1070. // Set the Flag if we are in fact beyond ValidDataLength.
  1071. //
  1072. if (DoingIoAtEof) {
  1073. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  1074. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1075. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  1076. } else {
  1077. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  1078. #endif
  1079. }
  1080. }
  1081. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1082. //
  1083. // Now that the File is acquired shared, we can safely test if it is
  1084. // really cached and if we can do fast i/o and if not
  1085. // then release the fcb and return.
  1086. //
  1087. if ((FileObject->PrivateCacheMap == NULL) ||
  1088. (Header->IsFastIoPossible == FastIoIsNotPossible)) {
  1089. WasDataRead = FALSE;
  1090. goto Done;
  1091. }
  1092. //
  1093. // Check if fast I/O is questionable and if so then go ask the file system
  1094. // the answer
  1095. //
  1096. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  1097. PFAST_IO_DISPATCH FastIoDispatch;
  1098. FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch;
  1099. //
  1100. // All file system then set "Is Questionable" had better support fast I/O
  1101. //
  1102. ASSERT(FastIoDispatch != NULL);
  1103. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  1104. //
  1105. // Call the file system to check for fast I/O. If the answer is anything
  1106. // other than GoForIt then we cannot take the fast I/O path.
  1107. //
  1108. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  1109. FileOffset,
  1110. Length,
  1111. TRUE,
  1112. LockKey,
  1113. TRUE, // read operation
  1114. IoStatus,
  1115. IoGetRelatedDeviceObject( FileObject ) )) {
  1116. //
  1117. // Fast I/O is not possible so release the Fcb and return.
  1118. //
  1119. WasDataRead = FALSE;
  1120. goto Done;
  1121. }
  1122. }
  1123. //
  1124. // Check for read past file size.
  1125. //
  1126. if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) {
  1127. if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) {
  1128. IoStatus->Status = STATUS_END_OF_FILE;
  1129. IoStatus->Information = 0;
  1130. goto Done;
  1131. }
  1132. Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart );
  1133. }
  1134. //
  1135. // We can do fast i/o so call the cc routine to do the work and then
  1136. // release the fcb when we've done. If for whatever reason the
  1137. // mdl read fails, then return FALSE to our caller.
  1138. //
  1139. //
  1140. // Also mark this as the top level "Irp" so that lower file system levels
  1141. // will not attempt a pop-up
  1142. //
  1143. IoSetTopLevelIrp( (PIRP) FSRTL_FAST_IO_TOP_LEVEL_IRP );
  1144. try {
  1145. //
  1146. // If there is a compressed section, then synchronize with that cache.
  1147. //
  1148. IoStatus->Status = STATUS_SUCCESS;
  1149. //
  1150. // If there is a compressed section, then we have to synchronize with
  1151. // the data out there. Note the FileObjectC better also be there, or else
  1152. // we would have made the fast I/O not possible.
  1153. //
  1154. WasDataRead = FALSE;
  1155. #ifdef COMPRESS_ON_WIRE
  1156. if (((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  1157. LONGLONG LocalOffset = FileOffset->QuadPart;
  1158. ULONG LengthRemaining = Length;
  1159. ULONG LocalLength;
  1160. ASSERT(Header->FileObjectC != NULL);
  1161. //
  1162. // If we are doing DoingIoAtEof then take the long path. Otherwise a recursive
  1163. // flush will try to reacquire DoingIoAtEof and deadlock.
  1164. //
  1165. if (DoingIoAtEof) {
  1166. WasDataRead = FALSE;
  1167. } else {
  1168. do {
  1169. //
  1170. // Calculate length left in view.
  1171. //
  1172. LocalLength = LengthRemaining;
  1173. if (LocalLength > (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)))) {
  1174. LocalLength = (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)));
  1175. }
  1176. IoStatus->Status = NtfsSynchronizeUncompressedIo( (PSCB)Header,
  1177. &LocalOffset,
  1178. LocalLength,
  1179. FALSE,
  1180. &CompressionSync );
  1181. if (NT_SUCCESS(IoStatus->Status)) {
  1182. #ifdef NTFS_RWCMP_TRACE
  1183. if (NtfsCompressionTrace && IsSyscache(Header)) {
  1184. DbgPrint("CcMdlRead(F): FO = %08lx, Len = %08lx\n", (ULONG)LocalOffset, LocalLength );
  1185. }
  1186. #endif
  1187. CcMdlRead( FileObject,
  1188. (PLARGE_INTEGER)&LocalOffset,
  1189. LocalLength,
  1190. MdlChain,
  1191. IoStatus );
  1192. LocalOffset += LocalLength;
  1193. LengthRemaining -= LocalLength;
  1194. }
  1195. } while ((LengthRemaining != 0) && NT_SUCCESS(IoStatus->Status));
  1196. //
  1197. // Store final return byte count.
  1198. //
  1199. if (NT_SUCCESS( IoStatus->Status )) {
  1200. IoStatus->Information = Length;
  1201. }
  1202. }
  1203. } else {
  1204. #endif
  1205. #ifdef NTFS_RWCMP_TRACE
  1206. if (NtfsCompressionTrace && IsSyscache(Header)) {
  1207. DbgPrint("CcMdlRead(F): FO = %08lx, Len = %08lx\n", FileOffset->LowPart, Length );
  1208. }
  1209. #endif
  1210. CcMdlRead( FileObject, FileOffset, Length, MdlChain, IoStatus );
  1211. WasDataRead = TRUE;
  1212. #ifdef COMPRESS_ON_WIRE
  1213. }
  1214. #endif
  1215. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  1216. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  1217. ? EXCEPTION_EXECUTE_HANDLER
  1218. : EXCEPTION_CONTINUE_SEARCH ) {
  1219. WasDataRead = FALSE;
  1220. }
  1221. IoSetTopLevelIrp( NULL );
  1222. #ifdef COMPRESS_ON_WIRE
  1223. if (CompressionSync != NULL) {
  1224. NtfsReleaseCompressionSync( CompressionSync );
  1225. }
  1226. #endif
  1227. Done: NOTHING;
  1228. if (DoingIoAtEof) {
  1229. FsRtlUnlockFsRtlHeader( Header );
  1230. }
  1231. ExReleaseResourceLite( Header->PagingIoResource );
  1232. Done2: NOTHING;
  1233. FsRtlExitFileSystem();
  1234. }
  1235. return WasDataRead;
  1236. }
  1237. BOOLEAN
  1238. NtfsPrepareMdlWriteA (
  1239. IN PFILE_OBJECT FileObject,
  1240. IN PLARGE_INTEGER FileOffset,
  1241. IN ULONG Length,
  1242. IN ULONG LockKey,
  1243. OUT PMDL *MdlChain,
  1244. OUT PIO_STATUS_BLOCK IoStatus,
  1245. IN PDEVICE_OBJECT DeviceObject
  1246. )
  1247. /*++
  1248. Routine Description:
  1249. This routine does a fast cached mdl read bypassing the usual file system
  1250. entry routine (i.e., without the Irp). It is used to do a copy read
  1251. of a cached file object. For a complete description of the arguments
  1252. see CcMdlRead.
  1253. Arguments:
  1254. FileObject - Pointer to the file object being read.
  1255. FileOffset - Byte offset in file for desired data.
  1256. Length - Length of desired data in bytes.
  1257. MdlChain - On output it returns a pointer to an MDL chain describing
  1258. the desired data.
  1259. IoStatus - Pointer to standard I/O status block to receive the status
  1260. for the transfer.
  1261. Return Value:
  1262. FALSE - if the data was not written, or if there is an I/O error.
  1263. TRUE - if the data is being written
  1264. --*/
  1265. {
  1266. PNTFS_ADVANCED_FCB_HEADER Header;
  1267. LARGE_INTEGER Offset, NewFileSize;
  1268. LARGE_INTEGER OldFileSize;
  1269. #ifdef COMPRESS_ON_WIRE
  1270. PCOMPRESSION_SYNC CompressionSync = NULL;
  1271. #endif
  1272. BOOLEAN DoingIoAtEof = FALSE;
  1273. BOOLEAN WasDataWritten = FALSE;
  1274. UNREFERENCED_PARAMETER( DeviceObject );
  1275. PAGED_CODE();
  1276. //
  1277. // Get a real pointer to the common fcb header
  1278. //
  1279. Header = (PNTFS_ADVANCED_FCB_HEADER)FileObject->FsContext;
  1280. //
  1281. // Do we need to verify the volume? If so, we must go to the file
  1282. // system. Also return FALSE if FileObject is write through, the
  1283. // File System must do that.
  1284. //
  1285. if (CcCanIWrite( FileObject, Length, TRUE, FALSE ) &&
  1286. !FlagOn(FileObject->Flags, FO_WRITE_THROUGH) &&
  1287. CcCopyWriteWontFlush(FileObject, FileOffset, Length) &&
  1288. (Header->PagingIoResource != NULL)) {
  1289. //
  1290. // Assume our transfer will work
  1291. //
  1292. IoStatus->Status = STATUS_SUCCESS;
  1293. //
  1294. // Special case the zero byte length
  1295. //
  1296. if (Length != 0) {
  1297. //
  1298. // Enter the file system
  1299. //
  1300. FsRtlEnterFileSystem();
  1301. //
  1302. // Make our best guess on whether we need the file exclusive or
  1303. // shared.
  1304. //
  1305. NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  1306. Offset = *FileOffset;
  1307. //
  1308. // Prevent truncates by acquiring paging I/O
  1309. //
  1310. ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
  1311. //
  1312. // Now synchronize with the FsRtl Header
  1313. //
  1314. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1315. //
  1316. // Now see if we will change FileSize. We have to do it now
  1317. // so that our reads are not nooped.
  1318. //
  1319. if ((FileOffset->QuadPart < 0) || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) {
  1320. //
  1321. // We can change FileSize and ValidDataLength if either, no one
  1322. // else is now, or we are still extending after waiting.
  1323. //
  1324. DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
  1325. NtfsWaitForIoAtEof( Header, FileOffset, Length );
  1326. //
  1327. // Set the Flag if we are changing FileSize or ValidDataLength,
  1328. // and save current values.
  1329. //
  1330. if (DoingIoAtEof) {
  1331. SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  1332. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1333. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  1334. #endif
  1335. //
  1336. // Now that we are synchronized for end of file cases,
  1337. // we can calculate the real offset for this transfer and
  1338. // the new file size (if we succeed).
  1339. //
  1340. if ((FileOffset->QuadPart < 0)) {
  1341. Offset = Header->FileSize;
  1342. }
  1343. //
  1344. // Now calculate the new FileSize and see if we wrapped the
  1345. // 32-bit boundary.
  1346. //
  1347. NewFileSize.QuadPart = Offset.QuadPart + Length;
  1348. //
  1349. // Update Filesize now so that we do not truncate reads.
  1350. //
  1351. OldFileSize.QuadPart = Header->FileSize.QuadPart;
  1352. if (NewFileSize.QuadPart > Header->FileSize.QuadPart) {
  1353. //
  1354. // If we are beyond AllocationSize, make sure we will
  1355. // ErrOut below, and don't modify FileSize now!
  1356. //
  1357. if (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) {
  1358. NewFileSize.QuadPart = (LONGLONG)0x7FFFFFFFFFFFFFFF;
  1359. } else {
  1360. Header->FileSize.QuadPart = NewFileSize.QuadPart;
  1361. }
  1362. }
  1363. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1364. } else {
  1365. ASSERT( ((PSCB) Header)->IoAtEofThread != (PERESOURCE_THREAD) ExGetCurrentResourceThread() );
  1366. #endif
  1367. }
  1368. }
  1369. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1370. //
  1371. // Now that the File is acquired shared, we can safely test
  1372. // if it is really cached and if we can do fast i/o and we
  1373. // do not have to extend. If not then release the fcb and
  1374. // return.
  1375. //
  1376. // Get out if we need to do any zeroing and do that in the main write path
  1377. //
  1378. if ((FileObject->PrivateCacheMap == NULL) ||
  1379. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  1380. /* Remove? */ (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) ||
  1381. (Offset.QuadPart > Header->ValidDataLength.QuadPart)) {
  1382. goto ErrOut;
  1383. }
  1384. //
  1385. // Check if fast I/O is questionable and if so then go ask the file system
  1386. // the answer
  1387. //
  1388. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  1389. PFAST_IO_DISPATCH FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch;
  1390. //
  1391. // All file system then set "Is Questionable" had better support fast I/O
  1392. //
  1393. ASSERT(FastIoDispatch != NULL);
  1394. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  1395. //
  1396. // Call the file system to check for fast I/O. If the answer is anything
  1397. // other than GoForIt then we cannot take the fast I/O path.
  1398. //
  1399. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  1400. &Offset,
  1401. Length,
  1402. TRUE,
  1403. LockKey,
  1404. FALSE, // write operation
  1405. IoStatus,
  1406. IoGetRelatedDeviceObject( FileObject ) )) {
  1407. //
  1408. // Fast I/O is not possible so release the Fcb and return.
  1409. //
  1410. goto ErrOut;
  1411. }
  1412. }
  1413. //
  1414. // We can do fast i/o so call the cc routine to do the work and then
  1415. // release the fcb when we've done. If for whatever reason the
  1416. // copy write fails, then return FALSE to our caller.
  1417. //
  1418. //
  1419. // Also mark this as the top level "Irp" so that lower file system levels
  1420. // will not attempt a pop-up
  1421. //
  1422. IoSetTopLevelIrp( (PIRP) FSRTL_FAST_IO_TOP_LEVEL_IRP );
  1423. try {
  1424. ASSERT( Offset.QuadPart <= Header->ValidDataLength.QuadPart );
  1425. #ifdef COMPRESS_ON_WIRE
  1426. if (((PSCB)Header)->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) {
  1427. LONGLONG LocalOffset = Offset.QuadPart;
  1428. ULONG LocalLength;
  1429. ULONG LengthLeft = Length;
  1430. ASSERT(Header->FileObjectC != NULL);
  1431. //
  1432. // If we are doing DoingIoAtEof then take the long path. Otherwise a recursive
  1433. // flush will try to reacquire DoingIoAtEof and deadlock.
  1434. //
  1435. if (DoingIoAtEof) {
  1436. WasDataWritten = FALSE;
  1437. } else {
  1438. do {
  1439. //
  1440. // Calculate length left in view.
  1441. //
  1442. LocalLength = LengthLeft;
  1443. if (LocalLength > (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)))) {
  1444. LocalLength = (ULONG)(VACB_MAPPING_GRANULARITY - (LocalOffset & (VACB_MAPPING_GRANULARITY - 1)));
  1445. }
  1446. IoStatus->Status = NtfsSynchronizeUncompressedIo( (PSCB)Header,
  1447. &LocalOffset,
  1448. LocalLength,
  1449. TRUE,
  1450. &CompressionSync );
  1451. if (NT_SUCCESS(IoStatus->Status)) {
  1452. #ifdef NTFS_RWCMP_TRACE
  1453. if (NtfsCompressionTrace && IsSyscache(Header)) {
  1454. DbgPrint("CcMdlWrite(F): FO = %08lx, Len = %08lx\n", (ULONG)LocalOffset, LocalLength );
  1455. }
  1456. #endif
  1457. CcPrepareMdlWrite( FileObject,
  1458. (PLARGE_INTEGER)&LocalOffset,
  1459. LocalLength,
  1460. MdlChain,
  1461. IoStatus );
  1462. LocalOffset += LocalLength;
  1463. LengthLeft -= LocalLength;
  1464. }
  1465. } while ((LengthLeft != 0) && NT_SUCCESS(IoStatus->Status));
  1466. WasDataWritten = TRUE;
  1467. }
  1468. } else {
  1469. #endif
  1470. #ifdef NTFS_RWCMP_TRACE
  1471. if (NtfsCompressionTrace && IsSyscache(Header)) {
  1472. DbgPrint("CcMdlWrite(F): FO = %08lx, Len = %08lx\n", Offset.LowPart, Length );
  1473. }
  1474. #endif
  1475. CcPrepareMdlWrite( FileObject, &Offset, Length, MdlChain, IoStatus );
  1476. WasDataWritten = TRUE;
  1477. #ifdef COMPRESS_ON_WIRE
  1478. }
  1479. #endif
  1480. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  1481. ? EXCEPTION_EXECUTE_HANDLER
  1482. : EXCEPTION_CONTINUE_SEARCH ) {
  1483. WasDataWritten = FALSE;
  1484. }
  1485. IoSetTopLevelIrp( NULL );
  1486. #ifdef COMPRESS_ON_WIRE
  1487. if (CompressionSync != NULL) {
  1488. NtfsReleaseCompressionSync( CompressionSync );
  1489. }
  1490. #endif
  1491. //
  1492. // If we succeeded, see if we have to update FileSize ValidDataLength.
  1493. //
  1494. if (WasDataWritten) {
  1495. //
  1496. // Set this handle as having modified the file
  1497. //
  1498. FileObject->Flags |= FO_FILE_MODIFIED;
  1499. IoStatus->Information = Length;
  1500. if (DoingIoAtEof) {
  1501. #ifdef COMPRESS_ON_WIRE
  1502. CC_FILE_SIZES CcFileSizes;
  1503. #endif
  1504. //
  1505. // Make sure Cc knows the current FileSize, as set above,
  1506. // (we may not have changed it). Update ValidDataLength
  1507. // and finish EOF.
  1508. //
  1509. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1510. CcGetFileSizePointer(FileObject)->QuadPart = Header->FileSize.QuadPart;
  1511. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  1512. Header->ValidDataLength = NewFileSize;
  1513. #ifdef COMPRESS_ON_WIRE
  1514. CcFileSizes = *(PCC_FILE_SIZES)&Header->AllocationSize;
  1515. #endif
  1516. NtfsVerifySizes( Header );
  1517. NtfsFinishIoAtEof( Header );
  1518. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1519. #ifdef SYSCACHE_DEBUG
  1520. if (ScbIsBeingLogged( (PSCB)Header )) {
  1521. FsRtlLogSyscacheEvent( (PSCB)Header, SCE_VDL_CHANGE, SCE_FLAG_WRITE | SCE_FLAG_FASTIO | SCE_FLAG_MDL, 0, 0, NewFileSize.QuadPart );
  1522. }
  1523. #endif
  1524. #ifdef COMPRESS_ON_WIRE
  1525. //
  1526. // Update the CompressedCache with ValidDataLength.
  1527. //
  1528. if (Header->FileObjectC != NULL) {
  1529. CcSetFileSizes( Header->FileObjectC, &CcFileSizes );
  1530. }
  1531. #endif
  1532. }
  1533. goto Done1;
  1534. }
  1535. ErrOut: NOTHING;
  1536. WasDataWritten = FALSE;
  1537. if (DoingIoAtEof) {
  1538. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1539. #ifdef COMPRESS_ON_WIRE
  1540. if (Header->FileObjectC != NULL) {
  1541. *CcGetFileSizePointer(Header->FileObjectC) = OldFileSize;
  1542. }
  1543. #endif
  1544. Header->FileSize = OldFileSize;
  1545. NtfsFinishIoAtEof( Header );
  1546. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1547. }
  1548. Done1: ExReleaseResourceLite( Header->PagingIoResource );
  1549. FsRtlExitFileSystem();
  1550. }
  1551. } else {
  1552. //
  1553. // We could not do the I/O now.
  1554. //
  1555. WasDataWritten = FALSE;
  1556. }
  1557. return WasDataWritten;
  1558. }
  1559. BOOLEAN
  1560. NtfsWaitForIoAtEof (
  1561. IN PNTFS_ADVANCED_FCB_HEADER Header,
  1562. IN OUT PLARGE_INTEGER FileOffset,
  1563. IN ULONG Length
  1564. )
  1565. /*++
  1566. Routine Description:
  1567. This routine may be called while synchronized for cached write, to
  1568. test for a possible Eof update, and return with a status if Eof is
  1569. being updated and with the previous FileSize to restore on error.
  1570. All updates to Eof are serialized by waiting in this routine. If
  1571. this routine returns TRUE, then NtfsFinishIoAtEof must be called.
  1572. This routine must be called while synchronized with the FsRtl header.
  1573. Arguments:
  1574. Header - Pointer to the FsRtl header for the file
  1575. FileOffset - Pointer to FileOffset for the intended write
  1576. Length - Length for the intended write
  1577. EofWaitBlock - Uninitialized structure used only to serialize Eof updates
  1578. Return Value:
  1579. FALSE - If the write does not extend Eof (OldFileSize not returned)
  1580. TRUE - If the write does extend Eof OldFileSize returned and caller
  1581. must eventually call NtfsFinishIoAtEof
  1582. --*/
  1583. {
  1584. EOF_WAIT_BLOCK EofWaitBlock;
  1585. PAGED_CODE();
  1586. ASSERT( Header->FileSize.QuadPart >= Header->ValidDataLength.QuadPart );
  1587. //
  1588. // Initialize the event and queue our block
  1589. //
  1590. KeInitializeEvent( &EofWaitBlock.Event, NotificationEvent, FALSE );
  1591. InsertTailList( Header->PendingEofAdvances, &EofWaitBlock.EofWaitLinks );
  1592. //
  1593. // Free the mutex and wait
  1594. //
  1595. NtfsReleaseFsrtlHeader( (PSCB) Header );
  1596. KeWaitForSingleObject( &EofWaitBlock.Event,
  1597. Executive,
  1598. KernelMode,
  1599. FALSE,
  1600. (PLARGE_INTEGER)NULL);
  1601. //
  1602. // Now, resynchronize and get on with it.
  1603. //
  1604. NtfsAcquireFsrtlHeader( (PSCB) Header );
  1605. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1606. ASSERT( ((PSCB) Header)->IoAtEofThread == NULL );
  1607. ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
  1608. #endif
  1609. //
  1610. // Now we have to check again, and actually catch the case
  1611. // where we are no longer extending!
  1612. //
  1613. if ((FileOffset->QuadPart >= 0) &&
  1614. ((FileOffset->QuadPart + Length) <= Header->ValidDataLength.QuadPart)) {
  1615. NtfsFinishIoAtEof( Header );
  1616. return FALSE;
  1617. }
  1618. return TRUE;
  1619. }
  1620. VOID
  1621. NtfsFinishIoAtEof (
  1622. IN PNTFS_ADVANCED_FCB_HEADER Header
  1623. )
  1624. /*++
  1625. Routine Description:
  1626. This routine must be called if NtfsWaitForIoAtEof returned
  1627. TRUE, or we otherwise set EOF_ADVANCE_ACTIVE.
  1628. This routine must be called while synchronized with the FsRtl header.
  1629. Arguments:
  1630. Header - Pointer to the FsRtl header for the file
  1631. Return Value:
  1632. None
  1633. --*/
  1634. {
  1635. PEOF_WAIT_BLOCK EofWaitBlock;
  1636. PAGED_CODE();
  1637. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  1638. ((PSCB) Header)->IoAtEofThread = NULL;
  1639. #endif
  1640. //
  1641. // If anyone is waiting, just let them go.
  1642. //
  1643. if (!IsListEmpty(Header->PendingEofAdvances)) {
  1644. EofWaitBlock = (PEOF_WAIT_BLOCK)RemoveHeadList( Header-> PendingEofAdvances );
  1645. KeSetEvent( &EofWaitBlock->Event, 0, FALSE );
  1646. //
  1647. // Otherwise, show there is no active extender now.
  1648. //
  1649. } else {
  1650. ClearFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );
  1651. }
  1652. }