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.

1061 lines
35 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. FastIo2.c
  5. Abstract:
  6. This module REimplements the fsrtl copy read/write routines.
  7. Author:
  8. Joe Linn [JoeLinn] 9-Nov-1994
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #ifndef FlagOn
  14. //
  15. // This macro returns TRUE if a flag in a set of flags is on and FALSE
  16. // otherwise
  17. //
  18. #define FlagOn(Flags,SingleFlag) ((Flags) & (SingleFlag))
  19. #endif
  20. BOOLEAN
  21. FsRtlCopyRead2 (
  22. IN PFILE_OBJECT FileObject,
  23. IN PLARGE_INTEGER FileOffset,
  24. IN ULONG Length,
  25. IN BOOLEAN Wait,
  26. IN ULONG LockKey,
  27. OUT PVOID Buffer,
  28. OUT PIO_STATUS_BLOCK IoStatus,
  29. IN PDEVICE_OBJECT DeviceObject,
  30. IN ULONG_PTR TopLevelIrpValue
  31. );
  32. BOOLEAN
  33. FsRtlCopyWrite2 (
  34. IN PFILE_OBJECT FileObject,
  35. IN PLARGE_INTEGER FileOffset,
  36. IN ULONG Length,
  37. IN BOOLEAN Wait,
  38. IN ULONG LockKey,
  39. IN PVOID Buffer,
  40. OUT PIO_STATUS_BLOCK IoStatus,
  41. IN PDEVICE_OBJECT DeviceObject,
  42. IN ULONG_PTR TopLevelIrpValue
  43. );
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text(PAGE, FsRtlCopyRead2)
  46. #pragma alloc_text(PAGE, FsRtlCopyWrite2)
  47. #endif
  48. BOOLEAN
  49. FsRtlCopyRead2 (
  50. IN PFILE_OBJECT FileObject,
  51. IN PLARGE_INTEGER FileOffset,
  52. IN ULONG Length,
  53. IN BOOLEAN Wait,
  54. IN ULONG LockKey,
  55. OUT PVOID Buffer,
  56. OUT PIO_STATUS_BLOCK IoStatus,
  57. IN PDEVICE_OBJECT DeviceObject,
  58. IN ULONG_PTR TopLevelIrpValue
  59. )
  60. /*++
  61. Routine Description:
  62. This routine does a fast cached read bypassing the usual file system
  63. entry routine (i.e., without the Irp). It is used to do a copy read
  64. of a cached file object. For a complete description of the arguments
  65. see CcCopyRead.
  66. Arguments:
  67. FileObject - Pointer to the file object being read.
  68. FileOffset - Byte offset in file for desired data.
  69. Length - Length of desired data in bytes.
  70. Wait - FALSE if caller may not block, TRUE otherwise
  71. Buffer - Pointer to output buffer to which data should be copied.
  72. IoStatus - Pointer to standard I/O status block to receive the status
  73. for the transfer.
  74. Return Value:
  75. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  76. if there is an I/O error.
  77. TRUE - if the data is being delivered
  78. --*/
  79. {
  80. PFSRTL_COMMON_FCB_HEADER Header;
  81. BOOLEAN Status = TRUE;
  82. ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES((ULongToPtr(FileOffset->LowPart)), Length);
  83. LARGE_INTEGER BeyondLastByte;
  84. PDEVICE_OBJECT targetVdo;
  85. PAGED_CODE();
  86. //
  87. // Special case a read of zero length
  88. //
  89. if (Length != 0) {
  90. //
  91. // Get a real pointer to the common fcb header
  92. //
  93. BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  94. Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
  95. //
  96. // Enter the file system
  97. //
  98. FsRtlEnterFileSystem();
  99. //
  100. // Increment performance counters and get the resource
  101. //
  102. if (Wait) {
  103. //
  104. // Acquired shared on the common fcb header
  105. //
  106. (VOID)ExAcquireResourceSharedLite( Header->Resource, TRUE );
  107. } else {
  108. //
  109. // Acquired shared on the common fcb header, and return if we
  110. // don't get it
  111. //
  112. if (!ExAcquireResourceSharedLite( Header->Resource, FALSE )) {
  113. FsRtlExitFileSystem();
  114. //the ntfs guys dont do this AND it causes a compile error for me so
  115. //comment it out
  116. //CcFastReadResourceMiss += 1;
  117. return FALSE;
  118. }
  119. }
  120. //
  121. // Now that the File is acquired shared, we can safely test if it
  122. // is really cached and if we can do fast i/o and if not, then
  123. // release the fcb and return.
  124. //
  125. if ((FileObject->PrivateCacheMap == NULL) ||
  126. (Header->IsFastIoPossible == FastIoIsNotPossible)) {
  127. ExReleaseResourceLite( Header->Resource );
  128. FsRtlExitFileSystem();
  129. return FALSE;
  130. }
  131. //
  132. // Check if fast I/O is questionable and if so then go ask the
  133. // file system the answer
  134. //
  135. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  136. PFAST_IO_DISPATCH FastIoDispatch;
  137. // ASSERT(!KeIsExecutingDpc());
  138. targetVdo = IoGetRelatedDeviceObject( FileObject );
  139. FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  140. //
  141. // All file systems that set "Is Questionable" had better support
  142. // fast I/O
  143. //
  144. ASSERT(FastIoDispatch != NULL);
  145. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  146. //
  147. // Call the file system to check for fast I/O. If the answer is
  148. // anything other than GoForIt then we cannot take the fast I/O
  149. // path.
  150. //
  151. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  152. FileOffset,
  153. Length,
  154. Wait,
  155. LockKey,
  156. TRUE, // read operation
  157. IoStatus,
  158. targetVdo )) {
  159. //
  160. // Fast I/O is not possible so release the Fcb and return.
  161. //
  162. ExReleaseResourceLite( Header->Resource );
  163. FsRtlExitFileSystem();
  164. return FALSE;
  165. }
  166. }
  167. //
  168. // Check for read past file size.
  169. //
  170. if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) {
  171. if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) {
  172. IoStatus->Status = STATUS_END_OF_FILE;
  173. IoStatus->Information = 0;
  174. ExReleaseResourceLite( Header->Resource );
  175. FsRtlExitFileSystem();
  176. return TRUE;
  177. }
  178. Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart );
  179. }
  180. //
  181. // We can do fast i/o so call the cc routine to do the work and then
  182. // release the fcb when we've done. If for whatever reason the
  183. // copy read fails, then return FALSE to our caller.
  184. //
  185. // Also mark this as the top level "Irp" so that lower file system
  186. // levels will not attempt a pop-up
  187. //
  188. IoSetTopLevelIrp((PIRP) TopLevelIrpValue);
  189. try {
  190. if (Wait && ((BeyondLastByte.HighPart | Header->FileSize.HighPart) == 0)) {
  191. CcFastCopyRead( FileObject,
  192. FileOffset->LowPart,
  193. Length,
  194. PageCount,
  195. Buffer,
  196. IoStatus );
  197. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  198. ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) ||
  199. ((FileOffset->LowPart + IoStatus->Information) <= Header->FileSize.LowPart));
  200. } else {
  201. Status = CcCopyRead( FileObject,
  202. FileOffset,
  203. Length,
  204. Wait,
  205. Buffer,
  206. IoStatus );
  207. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  208. ASSERT( !Status || (IoStatus->Status == STATUS_END_OF_FILE) ||
  209. (((ULONGLONG)FileOffset->QuadPart + IoStatus->Information) <= (ULONGLONG)Header->FileSize.QuadPart));
  210. }
  211. if (Status) {
  212. FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information;
  213. }
  214. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  215. ? EXCEPTION_EXECUTE_HANDLER
  216. : EXCEPTION_CONTINUE_SEARCH ) {
  217. Status = FALSE;
  218. }
  219. IoSetTopLevelIrp(NULL);
  220. ExReleaseResourceLite( Header->Resource );
  221. FsRtlExitFileSystem();
  222. return Status;
  223. } else {
  224. //
  225. // A zero length transfer was requested.
  226. //
  227. IoStatus->Status = STATUS_SUCCESS;
  228. IoStatus->Information = 0;
  229. return TRUE;
  230. }
  231. }
  232. BOOLEAN
  233. FsRtlCopyWrite2 (
  234. IN PFILE_OBJECT FileObject,
  235. IN PLARGE_INTEGER FileOffset,
  236. IN ULONG Length,
  237. IN BOOLEAN Wait,
  238. IN ULONG LockKey,
  239. IN PVOID Buffer,
  240. OUT PIO_STATUS_BLOCK IoStatus,
  241. IN PDEVICE_OBJECT DeviceObject,
  242. IN ULONG_PTR TopLevelIrpValue
  243. )
  244. /*++
  245. Routine Description:
  246. This routine does a fast cached write bypassing the usual file system
  247. entry routine (i.e., without the Irp). It is used to do a copy write
  248. of a cached file object. For a complete description of the arguments
  249. see CcCopyWrite.
  250. Arguments:
  251. FileObject - Pointer to the file object being write.
  252. FileOffset - Byte offset in file for desired data.
  253. Length - Length of desired data in bytes.
  254. Wait - FALSE if caller may not block, TRUE otherwise
  255. Buffer - Pointer to output buffer to which data should be copied.
  256. IoStatus - Pointer to standard I/O status block to receive the status
  257. for the transfer.
  258. Return Value:
  259. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  260. if there is an I/O error.
  261. TRUE - if the data is being delivered
  262. --*/
  263. {
  264. PFSRTL_COMMON_FCB_HEADER Header;
  265. BOOLEAN AcquiredShared = FALSE;
  266. BOOLEAN Status = TRUE;
  267. BOOLEAN FileSizeChanged = FALSE;
  268. BOOLEAN WriteToEndOfFile = (BOOLEAN)((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) &&
  269. (FileOffset->HighPart == -1));
  270. PAGED_CODE();
  271. //
  272. // Get a real pointer to the common fcb header
  273. //
  274. Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
  275. //
  276. // Do we need to verify the volume? If so, we must go to the file
  277. // system. Also return FALSE if FileObject is write through, the
  278. // File System must do that.
  279. //
  280. if (CcCanIWrite( FileObject, Length, Wait, FALSE ) &&
  281. !FlagOn(FileObject->Flags, FO_WRITE_THROUGH) &&
  282. CcCopyWriteWontFlush(FileObject, FileOffset, Length)) {
  283. //
  284. // Assume our transfer will work
  285. //
  286. IoStatus->Status = STATUS_SUCCESS;
  287. IoStatus->Information = Length;
  288. //
  289. // Special case the zero byte length
  290. //
  291. if (Length != 0) {
  292. //
  293. // Enter the file system
  294. //
  295. FsRtlEnterFileSystem();
  296. //
  297. // Split into separate paths for increased performance. First
  298. // we have the faster path which only supports Wait == TRUE and
  299. // 32 bits. We will make an unsafe test on whether the fast path
  300. // is ok, then just return FALSE later if we were wrong. This
  301. // should virtually never happen.
  302. //
  303. // IMPORTANT NOTE: It is very important that any changes mad to
  304. // this path also be applied to the 64-bit path
  305. // which is the else of this test!
  306. //
  307. if (Wait && (Header->AllocationSize.HighPart == 0)) {
  308. ULONG Offset, NewFileSize;
  309. ULONG OldFileSize;
  310. ULONG OldValidDataLength;
  311. BOOLEAN Wrapped;
  312. //
  313. // Make our best guess on whether we need the file exclusive
  314. // or shared. Note that we do not check FileOffset->HighPart
  315. // until below.
  316. //
  317. NewFileSize = FileOffset->LowPart + Length;
  318. if (WriteToEndOfFile || (NewFileSize > Header->ValidDataLength.LowPart)) {
  319. //
  320. // Acquired shared on the common fcb header
  321. //
  322. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  323. } else {
  324. //
  325. // Acquired shared on the common fcb header
  326. //
  327. ExAcquireResourceSharedLite( Header->Resource, TRUE );
  328. AcquiredShared = TRUE;
  329. }
  330. //
  331. // We have the fcb shared now check if we can do fast i/o
  332. // and if the file space is allocated, and if not then
  333. // release the fcb and return.
  334. //
  335. if (WriteToEndOfFile) {
  336. Offset = Header->FileSize.LowPart;
  337. NewFileSize = Header->FileSize.LowPart + Length;
  338. Wrapped = NewFileSize < Header->FileSize.LowPart;
  339. } else {
  340. Offset = FileOffset->LowPart;
  341. NewFileSize = FileOffset->LowPart + Length;
  342. Wrapped = (NewFileSize < FileOffset->LowPart) || (FileOffset->HighPart != 0);
  343. }
  344. //
  345. // Now that the File is acquired shared, we can safely test
  346. // if it is really cached and if we can do fast i/o and we
  347. // do not have to extend. If not then release the fcb and
  348. // return.
  349. //
  350. // Get out if we have too much to zero. This case is not important
  351. // for performance, and a file system supporting sparseness may have
  352. // a way to do this more efficiently.
  353. //
  354. if ((FileObject->PrivateCacheMap == NULL) ||
  355. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  356. (NewFileSize > Header->AllocationSize.LowPart) ||
  357. (Offset >= (Header->ValidDataLength.LowPart + 0x2000)) ||
  358. (Header->AllocationSize.HighPart != 0) || Wrapped) {
  359. ExReleaseResourceLite( Header->Resource );
  360. FsRtlExitFileSystem();
  361. return FALSE;
  362. }
  363. //
  364. // If we will be extending ValidDataLength, we will have to
  365. // get the Fcb exclusive, and make sure that FastIo is still
  366. // possible. We should only execute this block of code very
  367. // rarely, when the unsafe test for ValidDataLength failed
  368. // above.
  369. //
  370. if (AcquiredShared && (NewFileSize > Header->ValidDataLength.LowPart)) {
  371. ExReleaseResourceLite( Header->Resource );
  372. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  373. //
  374. // If writing to end of file, we must recalculate new size.
  375. //
  376. if (WriteToEndOfFile) {
  377. Offset = Header->FileSize.LowPart;
  378. NewFileSize = Header->FileSize.LowPart + Length;
  379. Wrapped = NewFileSize < Header->FileSize.LowPart;
  380. }
  381. if ((FileObject->PrivateCacheMap == NULL) ||
  382. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  383. (NewFileSize > Header->AllocationSize.LowPart) ||
  384. (Header->AllocationSize.HighPart != 0) || Wrapped) {
  385. ExReleaseResourceLite( Header->Resource );
  386. FsRtlExitFileSystem();
  387. return FALSE;
  388. }
  389. }
  390. //
  391. // Check if fast I/O is questionable and if so then go ask
  392. // the file system the answer
  393. //
  394. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  395. PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject );
  396. PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  397. IO_STATUS_BLOCK IoStatus;
  398. //
  399. // All file system then set "Is Questionable" had better
  400. // support fast I/O
  401. //
  402. ASSERT(FastIoDispatch != NULL);
  403. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  404. //
  405. // Call the file system to check for fast I/O. If the
  406. // answer is anything other than GoForIt then we cannot
  407. // take the fast I/O path.
  408. //
  409. ASSERT(FILE_WRITE_TO_END_OF_FILE == 0xffffffff);
  410. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  411. FileOffset->QuadPart != (LONGLONG)-1 ?
  412. FileOffset : &Header->FileSize,
  413. Length,
  414. TRUE,
  415. LockKey,
  416. FALSE, // write operation
  417. &IoStatus,
  418. targetVdo )) {
  419. //
  420. // Fast I/O is not possible so release the Fcb and
  421. // return.
  422. //
  423. ExReleaseResourceLite( Header->Resource );
  424. FsRtlExitFileSystem();
  425. return FALSE;
  426. }
  427. }
  428. //
  429. // Now see if we will change FileSize. We have to do it now
  430. // so that our reads are not nooped.
  431. //
  432. if (NewFileSize > Header->FileSize.LowPart) {
  433. FileSizeChanged = TRUE;
  434. OldFileSize = Header->FileSize.LowPart;
  435. OldValidDataLength = Header->ValidDataLength.LowPart;
  436. Header->FileSize.LowPart = NewFileSize;
  437. }
  438. //
  439. // We can do fast i/o so call the cc routine to do the work
  440. // and then release the fcb when we've done. If for whatever
  441. // reason the copy write fails, then return FALSE to our
  442. // caller.
  443. //
  444. // Also mark this as the top level "Irp" so that lower file
  445. // system levels will not attempt a pop-up
  446. //
  447. IoSetTopLevelIrp((PIRP) TopLevelIrpValue);
  448. try {
  449. //
  450. // See if we have to do some zeroing
  451. //
  452. if (Offset > Header->ValidDataLength.LowPart) {
  453. LARGE_INTEGER ZeroEnd;
  454. ZeroEnd.LowPart = Offset;
  455. ZeroEnd.HighPart = 0;
  456. CcZeroData( FileObject,
  457. &Header->ValidDataLength,
  458. &ZeroEnd,
  459. TRUE );
  460. }
  461. CcFastCopyWrite( FileObject,
  462. Offset,
  463. Length,
  464. Buffer );
  465. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  466. ? EXCEPTION_EXECUTE_HANDLER
  467. : EXCEPTION_CONTINUE_SEARCH ) {
  468. Status = FALSE;
  469. }
  470. IoSetTopLevelIrp(NULL);
  471. //
  472. // If we succeeded, see if we have to update FileSize or
  473. // ValidDataLength.
  474. //
  475. if (Status) {
  476. //
  477. // In the case of ValidDataLength, we really have to
  478. // check again since we did not do this when we acquired
  479. // the resource exclusive.
  480. //
  481. if (NewFileSize > Header->ValidDataLength.LowPart) {
  482. Header->ValidDataLength.LowPart = NewFileSize;
  483. }
  484. //
  485. // Set this handle as having modified the file
  486. //
  487. FileObject->Flags |= FO_FILE_MODIFIED;
  488. if (FileSizeChanged) {
  489. CcGetFileSizePointer(FileObject)->LowPart = NewFileSize;
  490. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  491. }
  492. //
  493. // Also update the file position pointer
  494. //
  495. FileObject->CurrentByteOffset.LowPart = Offset + Length;
  496. FileObject->CurrentByteOffset.HighPart = 0;
  497. //
  498. // If we did not succeed, then we must restore the original
  499. // FileSize while holding the PagingIoResource exclusive if
  500. // it exists.
  501. //
  502. } else if (FileSizeChanged) {
  503. if ( Header->PagingIoResource != NULL ) {
  504. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  505. Header->FileSize.LowPart = OldFileSize;
  506. Header->ValidDataLength.LowPart = OldValidDataLength;
  507. ExReleaseResourceLite( Header->PagingIoResource );
  508. } else {
  509. Header->FileSize.LowPart = OldFileSize;
  510. Header->ValidDataLength.LowPart = OldValidDataLength;
  511. }
  512. }
  513. //
  514. // Here is the 64-bit or no-wait path.
  515. //
  516. } else {
  517. LARGE_INTEGER Offset, NewFileSize;
  518. LARGE_INTEGER OldFileSize;
  519. LARGE_INTEGER OldValidDataLength;
  520. // ASSERT(!KeIsExecutingDpc());
  521. //
  522. // Make our best guess on whether we need the file exclusive
  523. // or shared.
  524. //
  525. NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  526. if (WriteToEndOfFile || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) {
  527. //
  528. // Acquired shared on the common fcb header, and return
  529. // if we don't get it.
  530. //
  531. if (!ExAcquireResourceExclusiveLite( Header->Resource, Wait )) {
  532. FsRtlExitFileSystem();
  533. return FALSE;
  534. }
  535. } else {
  536. //
  537. // Acquired shared on the common fcb header, and return
  538. // if we don't get it.
  539. //
  540. if (!ExAcquireResourceSharedLite( Header->Resource, Wait )) {
  541. FsRtlExitFileSystem();
  542. return FALSE;
  543. }
  544. AcquiredShared = TRUE;
  545. }
  546. //
  547. // We have the fcb shared now check if we can do fast i/o
  548. // and if the file space is allocated, and if not then
  549. // release the fcb and return.
  550. //
  551. if (WriteToEndOfFile) {
  552. Offset = Header->FileSize;
  553. NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;
  554. } else {
  555. Offset = *FileOffset;
  556. NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  557. }
  558. //
  559. // Now that the File is acquired shared, we can safely test
  560. // if it is really cached and if we can do fast i/o and we
  561. // do not have to extend. If not then release the fcb and
  562. // return.
  563. //
  564. // Get out if we are about to zero too much as well, as commented above.
  565. //
  566. if ((FileObject->PrivateCacheMap == NULL) ||
  567. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  568. (Offset.QuadPart >= (Header->ValidDataLength.QuadPart + 0x2000)) ||
  569. ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart ) ) {
  570. ExReleaseResourceLite( Header->Resource );
  571. FsRtlExitFileSystem();
  572. return FALSE;
  573. }
  574. //
  575. // If we will be extending ValidDataLength, we will have to
  576. // get the Fcb exclusive, and make sure that FastIo is still
  577. // possible. We should only execute this block of code very
  578. // rarely, when the unsafe test for ValidDataLength failed
  579. // above.
  580. //
  581. if (AcquiredShared && ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart )) {
  582. ExReleaseResourceLite( Header->Resource );
  583. if (!ExAcquireResourceExclusiveLite( Header->Resource, Wait )) {
  584. FsRtlExitFileSystem();
  585. return FALSE;
  586. }
  587. //
  588. // If writing to end of file, we must recalculate new size.
  589. //
  590. if (WriteToEndOfFile) {
  591. Offset = Header->FileSize;
  592. NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;
  593. }
  594. if ((FileObject->PrivateCacheMap == NULL) ||
  595. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  596. ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart ) ) {
  597. ExReleaseResourceLite( Header->Resource );
  598. FsRtlExitFileSystem();
  599. return FALSE;
  600. }
  601. }
  602. //
  603. // Check if fast I/O is questionable and if so then go ask
  604. // the file system the answer
  605. //
  606. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  607. PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject );
  608. PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  609. IO_STATUS_BLOCK IoStatus;
  610. //
  611. // All file system then set "Is Questionable" had better
  612. // support fast I/O
  613. //
  614. ASSERT(FastIoDispatch != NULL);
  615. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  616. //
  617. // Call the file system to check for fast I/O. If the
  618. // answer is anything other than GoForIt then we cannot
  619. // take the fast I/O path.
  620. //
  621. ASSERT(FILE_WRITE_TO_END_OF_FILE == 0xffffffff);
  622. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  623. FileOffset->QuadPart != (LONGLONG)-1 ?
  624. FileOffset : &Header->FileSize,
  625. Length,
  626. Wait,
  627. LockKey,
  628. FALSE, // write operation
  629. &IoStatus,
  630. targetVdo )) {
  631. //
  632. // Fast I/O is not possible so release the Fcb and
  633. // return.
  634. //
  635. ExReleaseResourceLite( Header->Resource );
  636. FsRtlExitFileSystem();
  637. return FALSE;
  638. }
  639. }
  640. //
  641. // Now see if we will change FileSize. We have to do it now
  642. // so that our reads are not nooped.
  643. //
  644. if ( NewFileSize.QuadPart > Header->FileSize.QuadPart ) {
  645. FileSizeChanged = TRUE;
  646. OldFileSize = Header->FileSize;
  647. OldValidDataLength = Header->ValidDataLength;
  648. //
  649. // Deal with an extremely rare pathalogical case here the
  650. // file size wraps.
  651. //
  652. if ( (Header->FileSize.HighPart != NewFileSize.HighPart) &&
  653. (Header->PagingIoResource != NULL) ) {
  654. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  655. Header->FileSize = NewFileSize;
  656. ExReleaseResourceLite( Header->PagingIoResource );
  657. } else {
  658. Header->FileSize = NewFileSize;
  659. }
  660. }
  661. //
  662. // We can do fast i/o so call the cc routine to do the work
  663. // and then release the fcb when we've done. If for whatever
  664. // reason the copy write fails, then return FALSE to our
  665. // caller.
  666. //
  667. // Also mark this as the top level "Irp" so that lower file
  668. // system levels will not attempt a pop-up
  669. //
  670. IoSetTopLevelIrp((PIRP) TopLevelIrpValue);
  671. try {
  672. //
  673. // See if we have to do some zeroing
  674. //
  675. if ( Offset.QuadPart > Header->ValidDataLength.QuadPart ) {
  676. Status = CcZeroData( FileObject,
  677. &Header->ValidDataLength,
  678. &Offset,
  679. Wait );
  680. }
  681. if (Status) {
  682. Status = CcCopyWrite( FileObject,
  683. &Offset,
  684. Length,
  685. Wait,
  686. Buffer );
  687. }
  688. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  689. ? EXCEPTION_EXECUTE_HANDLER
  690. : EXCEPTION_CONTINUE_SEARCH ) {
  691. Status = FALSE;
  692. }
  693. IoSetTopLevelIrp(NULL);
  694. //
  695. // If we succeeded, see if we have to update FileSize or
  696. // ValidDataLength.
  697. //
  698. if (Status) {
  699. //
  700. // In the case of ValidDataLength, we really have to
  701. // check again since we did not do this when we acquired
  702. // the resource exclusive.
  703. //
  704. if ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart ) {
  705. //
  706. // Deal with an extremely rare pathalogical case here
  707. // the ValidDataLength wraps.
  708. //
  709. if ( (Header->ValidDataLength.HighPart != NewFileSize.HighPart) &&
  710. (Header->PagingIoResource != NULL) ) {
  711. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  712. Header->ValidDataLength = NewFileSize;
  713. ExReleaseResourceLite( Header->PagingIoResource );
  714. } else {
  715. Header->ValidDataLength = NewFileSize;
  716. }
  717. }
  718. //
  719. // Set this handle as having modified the file
  720. //
  721. FileObject->Flags |= FO_FILE_MODIFIED;
  722. if (FileSizeChanged) {
  723. *CcGetFileSizePointer(FileObject) = NewFileSize;
  724. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  725. }
  726. //
  727. // Also update the current file position pointer
  728. //
  729. FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
  730. //
  731. // If we did not succeed, then we must restore the original
  732. // FileSize while holding the PagingIoResource exclusive if
  733. // it exists.
  734. //
  735. } else if (FileSizeChanged) {
  736. if ( Header->PagingIoResource != NULL ) {
  737. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  738. Header->FileSize = OldFileSize;
  739. Header->ValidDataLength = OldValidDataLength;
  740. ExReleaseResourceLite( Header->PagingIoResource );
  741. } else {
  742. Header->FileSize = OldFileSize;
  743. Header->ValidDataLength = OldValidDataLength;
  744. }
  745. }
  746. }
  747. ExReleaseResourceLite( Header->Resource );
  748. FsRtlExitFileSystem();
  749. return Status;
  750. } else {
  751. //
  752. // A zero length transfer was requested.
  753. //
  754. return TRUE;
  755. }
  756. } else {
  757. //
  758. // The volume must be verified or the file is write through.
  759. //
  760. return FALSE;
  761. }
  762. }