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.

4326 lines
125 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. FastIo.c
  5. Abstract:
  6. The Fast I/O path is used to avoid calling the file systems directly to
  7. do a cached read. This module is only used if the file object indicates
  8. that caching is enabled (i.e., the private cache map is not null).
  9. Author:
  10. Gary Kimura [GaryKi] 25-Feb-1991
  11. Revision History:
  12. Tom Miller [TomM] 14-Apr-1991 Added Fast Write routines
  13. --*/
  14. #include "FsRtlP.h"
  15. #if DBG
  16. typedef struct _FS_RTL_DEBUG_COUNTERS {
  17. ULONG AcquireFileExclusiveEx_Succeed;
  18. ULONG AcquireFileExclusiveEx_Fail;
  19. ULONG ReleaseFile;
  20. ULONG AcquireFileForModWriteEx_Succeed;
  21. ULONG AcquireFileForModWriteEx_Fail;
  22. ULONG ReleaseFileForModWrite;
  23. ULONG AcquireFileForCcFlushEx_Succeed;
  24. ULONG AcquireFileForCcFlushEx_Fail;
  25. ULONG ReleaseFileForCcFlush;
  26. } FS_RTL_DEBUG_COUNTERS, *PFS_RTL_DEBUG_COUNTERS;
  27. FS_RTL_DEBUG_COUNTERS gCounter = { 0, 0, 0,
  28. 0, 0, 0,
  29. 0, 0, 0 };
  30. #endif
  31. //
  32. // Trace level for the module
  33. //
  34. #define Dbg (0x04000000)
  35. #ifdef ALLOC_PRAGMA
  36. #pragma alloc_text(PAGE, FsRtlCopyRead)
  37. #pragma alloc_text(PAGE, FsRtlCopyWrite)
  38. #pragma alloc_text(PAGE, FsRtlMdlRead)
  39. #pragma alloc_text(PAGE, FsRtlMdlReadDev)
  40. #pragma alloc_text(PAGE, FsRtlPrepareMdlWrite)
  41. #pragma alloc_text(PAGE, FsRtlPrepareMdlWriteDev)
  42. #pragma alloc_text(PAGE, FsRtlMdlWriteComplete)
  43. #pragma alloc_text(PAGE, FsRtlMdlWriteCompleteDev)
  44. #pragma alloc_text(PAGE, FsRtlAcquireFileForCcFlush)
  45. #pragma alloc_text(PAGE, FsRtlAcquireFileForCcFlushEx)
  46. #pragma alloc_text(PAGE, FsRtlReleaseFileForCcFlush)
  47. #pragma alloc_text(PAGE, FsRtlAcquireFileExclusive)
  48. #pragma alloc_text(PAGE, FsRtlAcquireToCreateMappedSection)
  49. #pragma alloc_text(PAGE, FsRtlAcquireFileExclusiveCommon)
  50. #pragma alloc_text(PAGE, FsRtlReleaseFile)
  51. #pragma alloc_text(PAGE, FsRtlGetFileSize)
  52. #pragma alloc_text(PAGE, FsRtlSetFileSize)
  53. #pragma alloc_text(PAGE, FsRtlIncrementCcFastReadNotPossible )
  54. #pragma alloc_text(PAGE, FsRtlIncrementCcFastReadWait )
  55. #endif
  56. BOOLEAN
  57. FsRtlCopyRead (
  58. IN PFILE_OBJECT FileObject,
  59. IN PLARGE_INTEGER FileOffset,
  60. IN ULONG Length,
  61. IN BOOLEAN Wait,
  62. IN ULONG LockKey,
  63. OUT PVOID Buffer,
  64. OUT PIO_STATUS_BLOCK IoStatus,
  65. IN PDEVICE_OBJECT DeviceObject
  66. )
  67. /*++
  68. Routine Description:
  69. This routine does a fast cached read bypassing the usual file system
  70. entry routine (i.e., without the Irp). It is used to do a copy read
  71. of a cached file object. For a complete description of the arguments
  72. see CcCopyRead.
  73. Arguments:
  74. FileObject - Pointer to the file object being read.
  75. FileOffset - Byte offset in file for desired data.
  76. Length - Length of desired data in bytes.
  77. Wait - FALSE if caller may not block, TRUE otherwise
  78. Buffer - Pointer to output buffer to which data should be copied.
  79. IoStatus - Pointer to standard I/O status block to receive the status
  80. for the transfer.
  81. Return Value:
  82. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  83. if there is an I/O error.
  84. TRUE - if the data is being delivered
  85. --*/
  86. {
  87. PFSRTL_COMMON_FCB_HEADER Header;
  88. BOOLEAN Status = TRUE;
  89. ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES( FileOffset->QuadPart, Length );
  90. LARGE_INTEGER BeyondLastByte;
  91. PDEVICE_OBJECT targetVdo;
  92. PAGED_CODE();
  93. //
  94. // Special case a read of zero length
  95. //
  96. if (Length != 0) {
  97. //
  98. // Check for overflow. Returning false here will re-route this request through the
  99. // IRP based path, but this isn't performance critical.
  100. //
  101. if (MAXLONGLONG - FileOffset->QuadPart < (LONGLONG)Length) {
  102. IoStatus->Status = STATUS_INVALID_PARAMETER;
  103. IoStatus->Information = 0;
  104. return FALSE;
  105. }
  106. BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  107. Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
  108. //
  109. // Enter the file system
  110. //
  111. FsRtlEnterFileSystem();
  112. //
  113. // Increment performance counters and get the resource
  114. //
  115. if (Wait) {
  116. HOT_STATISTIC(CcFastReadWait) += 1;
  117. //
  118. // Acquired shared on the common fcb header
  119. //
  120. (VOID)ExAcquireResourceSharedLite( Header->Resource, TRUE );
  121. } else {
  122. HOT_STATISTIC(CcFastReadNoWait) += 1;
  123. //
  124. // Acquired shared on the common fcb header, and return if we
  125. // don't get it
  126. //
  127. if (!ExAcquireResourceSharedLite( Header->Resource, FALSE )) {
  128. FsRtlExitFileSystem();
  129. CcFastReadResourceMiss += 1;
  130. return FALSE;
  131. }
  132. }
  133. //
  134. // Now that the File is acquired shared, we can safely test if it
  135. // is really cached and if we can do fast i/o and if not, then
  136. // release the fcb and return.
  137. //
  138. if ((FileObject->PrivateCacheMap == NULL) ||
  139. (Header->IsFastIoPossible == FastIoIsNotPossible)) {
  140. ExReleaseResourceLite( Header->Resource );
  141. FsRtlExitFileSystem();
  142. HOT_STATISTIC(CcFastReadNotPossible) += 1;
  143. return FALSE;
  144. }
  145. //
  146. // Check if fast I/O is questionable and if so then go ask the
  147. // file system the answer
  148. //
  149. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  150. PFAST_IO_DISPATCH FastIoDispatch;
  151. ASSERT(!KeIsExecutingDpc());
  152. targetVdo = IoGetRelatedDeviceObject( FileObject );
  153. FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  154. //
  155. // All file systems that set "Is Questionable" had better support
  156. // fast I/O
  157. //
  158. ASSERT(FastIoDispatch != NULL);
  159. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  160. //
  161. // Call the file system to check for fast I/O. If the answer is
  162. // anything other than GoForIt then we cannot take the fast I/O
  163. // path.
  164. //
  165. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  166. FileOffset,
  167. Length,
  168. Wait,
  169. LockKey,
  170. TRUE, // read operation
  171. IoStatus,
  172. targetVdo )) {
  173. //
  174. // Fast I/O is not possible so release the Fcb and return.
  175. //
  176. ExReleaseResourceLite( Header->Resource );
  177. FsRtlExitFileSystem();
  178. HOT_STATISTIC(CcFastReadNotPossible) += 1;
  179. return FALSE;
  180. }
  181. }
  182. //
  183. // Check for read past file size.
  184. //
  185. if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) {
  186. if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) {
  187. IoStatus->Status = STATUS_END_OF_FILE;
  188. IoStatus->Information = 0;
  189. ExReleaseResourceLite( Header->Resource );
  190. FsRtlExitFileSystem();
  191. return TRUE;
  192. }
  193. Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart );
  194. }
  195. //
  196. // We can do fast i/o so call the cc routine to do the work and then
  197. // release the fcb when we've done. If for whatever reason the
  198. // copy read fails, then return FALSE to our caller.
  199. //
  200. // Also mark this as the top level "Irp" so that lower file system
  201. // levels will not attempt a pop-up
  202. //
  203. PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
  204. try {
  205. if (Wait && ((BeyondLastByte.HighPart | Header->FileSize.HighPart) == 0)) {
  206. CcFastCopyRead( FileObject,
  207. FileOffset->LowPart,
  208. Length,
  209. PageCount,
  210. Buffer,
  211. IoStatus );
  212. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  213. ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) ||
  214. ((FileOffset->LowPart + IoStatus->Information) <= Header->FileSize.LowPart));
  215. } else {
  216. Status = CcCopyRead( FileObject,
  217. FileOffset,
  218. Length,
  219. Wait,
  220. Buffer,
  221. IoStatus );
  222. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  223. ASSERT( !Status || (IoStatus->Status == STATUS_END_OF_FILE) ||
  224. ((LONGLONG)(FileOffset->QuadPart + IoStatus->Information) <= Header->FileSize.QuadPart));
  225. }
  226. if (Status) {
  227. FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information;
  228. }
  229. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  230. ? EXCEPTION_EXECUTE_HANDLER
  231. : EXCEPTION_CONTINUE_SEARCH ) {
  232. Status = FALSE;
  233. }
  234. PsGetCurrentThread()->TopLevelIrp = 0;
  235. ExReleaseResourceLite( Header->Resource );
  236. FsRtlExitFileSystem();
  237. return Status;
  238. } else {
  239. //
  240. // A zero length transfer was requested.
  241. //
  242. IoStatus->Status = STATUS_SUCCESS;
  243. IoStatus->Information = 0;
  244. return TRUE;
  245. }
  246. }
  247. BOOLEAN
  248. FsRtlCopyWrite (
  249. IN PFILE_OBJECT FileObject,
  250. IN PLARGE_INTEGER FileOffset,
  251. IN ULONG Length,
  252. IN BOOLEAN Wait,
  253. IN ULONG LockKey,
  254. IN PVOID Buffer,
  255. OUT PIO_STATUS_BLOCK IoStatus,
  256. IN PDEVICE_OBJECT DeviceObject
  257. )
  258. /*++
  259. Routine Description:
  260. This routine does a fast cached write bypassing the usual file system
  261. entry routine (i.e., without the Irp). It is used to do a copy write
  262. of a cached file object. For a complete description of the arguments
  263. see CcCopyWrite.
  264. Arguments:
  265. FileObject - Pointer to the file object being write.
  266. FileOffset - Byte offset in file for desired data.
  267. Length - Length of desired data in bytes.
  268. Wait - FALSE if caller may not block, TRUE otherwise
  269. Buffer - Pointer to output buffer to which data should be copied.
  270. IoStatus - Pointer to standard I/O status block to receive the status
  271. for the transfer.
  272. Return Value:
  273. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  274. if there is an I/O error.
  275. TRUE - if the data is being delivered
  276. --*/
  277. {
  278. PFSRTL_COMMON_FCB_HEADER Header;
  279. BOOLEAN AcquiredShared = FALSE;
  280. BOOLEAN Status = TRUE;
  281. BOOLEAN FileSizeChanged = FALSE;
  282. BOOLEAN WriteToEndOfFile = (BOOLEAN)((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) &&
  283. (FileOffset->HighPart == -1));
  284. PAGED_CODE();
  285. //
  286. // Get a real pointer to the common fcb header
  287. //
  288. Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
  289. //
  290. // Do we need to verify the volume? If so, we must go to the file
  291. // system. Also return FALSE if FileObject is write through, the
  292. // File System must do that.
  293. //
  294. if (CcCanIWrite( FileObject, Length, Wait, FALSE ) &&
  295. !FlagOn(FileObject->Flags, FO_WRITE_THROUGH) &&
  296. CcCopyWriteWontFlush(FileObject, FileOffset, Length)) {
  297. //
  298. // Assume our transfer will work
  299. //
  300. IoStatus->Status = STATUS_SUCCESS;
  301. IoStatus->Information = Length;
  302. //
  303. // Special case the zero byte length
  304. //
  305. if (Length != 0) {
  306. //
  307. // Enter the file system
  308. //
  309. FsRtlEnterFileSystem();
  310. //
  311. // Split into separate paths for increased performance. First
  312. // we have the faster path which only supports Wait == TRUE and
  313. // 32 bits. We will make an unsafe test on whether the fast path
  314. // is ok, then just return FALSE later if we were wrong. This
  315. // should virtually never happen.
  316. //
  317. // IMPORTANT NOTE: It is very important that any changes made to
  318. // this path also be applied to the 64-bit path
  319. // which is the else of this test!
  320. //
  321. if (Wait && (Header->AllocationSize.HighPart == 0)) {
  322. ULONG Offset, NewFileSize;
  323. ULONG OldFileSize;
  324. ULONG OldValidDataLength;
  325. BOOLEAN Wrapped;
  326. //
  327. // Make our best guess on whether we need the file exclusive
  328. // or shared. Note that we do not check FileOffset->HighPart
  329. // until below.
  330. //
  331. NewFileSize = FileOffset->LowPart + Length;
  332. if (WriteToEndOfFile || (NewFileSize > Header->ValidDataLength.LowPart)) {
  333. //
  334. // Acquired shared on the common fcb header
  335. //
  336. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  337. } else {
  338. //
  339. // Acquired shared on the common fcb header
  340. //
  341. ExAcquireResourceSharedLite( Header->Resource, TRUE );
  342. AcquiredShared = TRUE;
  343. }
  344. //
  345. // We have the fcb shared now check if we can do fast i/o
  346. // and if the file space is allocated, and if not then
  347. // release the fcb and return.
  348. //
  349. if (WriteToEndOfFile) {
  350. Offset = Header->FileSize.LowPart;
  351. NewFileSize = Header->FileSize.LowPart + Length;
  352. Wrapped = NewFileSize < Header->FileSize.LowPart;
  353. } else {
  354. Offset = FileOffset->LowPart;
  355. NewFileSize = FileOffset->LowPart + Length;
  356. Wrapped = (NewFileSize < FileOffset->LowPart) || (FileOffset->HighPart != 0);
  357. }
  358. //
  359. // Now that the File is acquired shared, we can safely test
  360. // if it is really cached and if we can do fast i/o and we
  361. // do not have to extend. If not then release the fcb and
  362. // return.
  363. //
  364. // Get out if we have too much to zero. This case is not important
  365. // for performance, and a file system supporting sparseness may have
  366. // a way to do this more efficiently.
  367. //
  368. if ((FileObject->PrivateCacheMap == NULL) ||
  369. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  370. (NewFileSize > Header->AllocationSize.LowPart) ||
  371. (Offset >= (Header->ValidDataLength.LowPart + 0x2000)) ||
  372. (Header->AllocationSize.HighPart != 0) || Wrapped) {
  373. ExReleaseResourceLite( Header->Resource );
  374. FsRtlExitFileSystem();
  375. return FALSE;
  376. }
  377. //
  378. // If we will be extending ValidDataLength, we will have to
  379. // get the Fcb exclusive, and make sure that FastIo is still
  380. // possible. We should only execute this block of code very
  381. // rarely, when the unsafe test for ValidDataLength failed
  382. // above.
  383. //
  384. if (AcquiredShared && (NewFileSize > Header->ValidDataLength.LowPart)) {
  385. ExReleaseResourceLite( Header->Resource );
  386. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  387. //
  388. // If writing to end of file, we must recalculate new size.
  389. //
  390. if (WriteToEndOfFile) {
  391. Offset = Header->FileSize.LowPart;
  392. NewFileSize = Header->FileSize.LowPart + Length;
  393. Wrapped = NewFileSize < Header->FileSize.LowPart;
  394. }
  395. if ((FileObject->PrivateCacheMap == NULL) ||
  396. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  397. (NewFileSize > Header->AllocationSize.LowPart) ||
  398. (Header->AllocationSize.HighPart != 0) || Wrapped) {
  399. ExReleaseResourceLite( Header->Resource );
  400. FsRtlExitFileSystem();
  401. return FALSE;
  402. }
  403. }
  404. //
  405. // Check if fast I/O is questionable and if so then go ask
  406. // the file system the answer
  407. //
  408. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  409. PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject );
  410. PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
  411. IO_STATUS_BLOCK IoStatus;
  412. //
  413. // All file system then set "Is Questionable" had better
  414. // support fast I/O
  415. //
  416. ASSERT(FastIoDispatch != NULL);
  417. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  418. //
  419. // Call the file system to check for fast I/O. If the
  420. // answer is anything other than GoForIt then we cannot
  421. // take the fast I/O path.
  422. //
  423. ASSERT(FILE_WRITE_TO_END_OF_FILE == 0xffffffff);
  424. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  425. FileOffset->QuadPart != (LONGLONG)-1 ?
  426. FileOffset : &Header->FileSize,
  427. Length,
  428. TRUE,
  429. LockKey,
  430. FALSE, // write operation
  431. &IoStatus,
  432. targetVdo )) {
  433. //
  434. // Fast I/O is not possible so release the Fcb and
  435. // return.
  436. //
  437. ExReleaseResourceLite( Header->Resource );
  438. FsRtlExitFileSystem();
  439. return FALSE;
  440. }
  441. }
  442. //
  443. // Now see if we will change FileSize. We have to do it now
  444. // so that our reads are not nooped.
  445. //
  446. if (NewFileSize > Header->FileSize.LowPart) {
  447. FileSizeChanged = TRUE;
  448. OldFileSize = Header->FileSize.LowPart;
  449. OldValidDataLength = Header->ValidDataLength.LowPart;
  450. Header->FileSize.LowPart = NewFileSize;
  451. }
  452. //
  453. // We can do fast i/o so call the cc routine to do the work
  454. // and then release the fcb when we've done. If for whatever
  455. // reason the copy write fails, then return FALSE to our
  456. // caller.
  457. //
  458. // Also mark this as the top level "Irp" so that lower file
  459. // system levels will not attempt a pop-up
  460. //
  461. PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
  462. try {
  463. //
  464. // See if we have to do some zeroing
  465. //
  466. if (Offset > Header->ValidDataLength.LowPart) {
  467. LARGE_INTEGER ZeroEnd;
  468. ZeroEnd.LowPart = Offset;
  469. ZeroEnd.HighPart = 0;
  470. CcZeroData( FileObject,
  471. &Header->ValidDataLength,
  472. &ZeroEnd,
  473. TRUE );
  474. }
  475. CcFastCopyWrite( FileObject,
  476. Offset,
  477. Length,
  478. Buffer );
  479. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  480. ? EXCEPTION_EXECUTE_HANDLER
  481. : EXCEPTION_CONTINUE_SEARCH ) {
  482. Status = FALSE;
  483. }
  484. PsGetCurrentThread()->TopLevelIrp = 0;
  485. //
  486. // If we succeeded, see if we have to update FileSize or
  487. // ValidDataLength.
  488. //
  489. if (Status) {
  490. //
  491. // In the case of ValidDataLength, we really have to
  492. // check again since we did not do this when we acquired
  493. // the resource exclusive.
  494. //
  495. if (NewFileSize > Header->ValidDataLength.LowPart) {
  496. Header->ValidDataLength.LowPart = NewFileSize;
  497. }
  498. //
  499. // Set this handle as having modified the file
  500. //
  501. FileObject->Flags |= FO_FILE_MODIFIED;
  502. if (FileSizeChanged) {
  503. CcGetFileSizePointer(FileObject)->LowPart = NewFileSize;
  504. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  505. }
  506. //
  507. // Also update the file position pointer
  508. //
  509. FileObject->CurrentByteOffset.LowPart = Offset + Length;
  510. FileObject->CurrentByteOffset.HighPart = 0;
  511. //
  512. // If we did not succeed, then we must restore the original
  513. // FileSize while holding the PagingIoResource exclusive if
  514. // it exists.
  515. //
  516. } else if (FileSizeChanged) {
  517. if ( Header->PagingIoResource != NULL ) {
  518. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  519. Header->FileSize.LowPart = OldFileSize;
  520. Header->ValidDataLength.LowPart = OldValidDataLength;
  521. ExReleaseResourceLite( Header->PagingIoResource );
  522. } else {
  523. Header->FileSize.LowPart = OldFileSize;
  524. Header->ValidDataLength.LowPart = OldValidDataLength;
  525. }
  526. }
  527. //
  528. // Here is the 64-bit or no-wait path.
  529. //
  530. } else {
  531. LARGE_INTEGER Offset, NewFileSize;
  532. LARGE_INTEGER OldFileSize;
  533. LARGE_INTEGER OldValidDataLength;
  534. ASSERT(!KeIsExecutingDpc());
  535. //
  536. // Make our best guess on whether we need the file exclusive
  537. // or shared.
  538. //
  539. NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  540. if (WriteToEndOfFile || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) {
  541. //
  542. // Acquired shared on the common fcb header, and return
  543. // if we don't get it.
  544. //
  545. if (!ExAcquireResourceExclusiveLite( Header->Resource, Wait )) {
  546. FsRtlExitFileSystem();
  547. return FALSE;
  548. }
  549. } else {
  550. //
  551. // Acquired shared on the common fcb header, and return
  552. // if we don't get it.
  553. //
  554. if (!ExAcquireResourceSharedLite( Header->Resource, Wait )) {
  555. FsRtlExitFileSystem();
  556. return FALSE;
  557. }
  558. AcquiredShared = TRUE;
  559. }
  560. //
  561. // We have the fcb shared now check if we can do fast i/o
  562. // and if the file space is allocated, and if not then
  563. // release the fcb and return.
  564. //
  565. if (WriteToEndOfFile) {
  566. Offset = Header->FileSize;
  567. NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;
  568. } else {
  569. Offset = *FileOffset;
  570. NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  571. }
  572. //
  573. // Now that the File is acquired shared, we can safely test
  574. // if it is really cached and if we can do fast i/o and we
  575. // do not have to extend. If not then release the fcb and
  576. // return.
  577. //
  578. // Get out if we are about to zero too much as well, as commented above.
  579. // Likewise, for NewFileSizes that exceed MAXLONGLONG.
  580. //
  581. if ((FileObject->PrivateCacheMap == NULL) ||
  582. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  583. (Offset.QuadPart >= (Header->ValidDataLength.QuadPart + 0x2000)) ||
  584. (MAXLONGLONG - Offset.QuadPart < (LONGLONG)Length) ||
  585. (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) ) {
  586. ExReleaseResourceLite( Header->Resource );
  587. FsRtlExitFileSystem();
  588. return FALSE;
  589. }
  590. //
  591. // If we will be extending ValidDataLength, we will have to
  592. // get the Fcb exclusive, and make sure that FastIo is still
  593. // possible. We should only execute this block of code very
  594. // rarely, when the unsafe test for ValidDataLength failed
  595. // above.
  596. //
  597. if (AcquiredShared && ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart )) {
  598. ExReleaseResourceLite( Header->Resource );
  599. if (!ExAcquireResourceExclusiveLite( Header->Resource, Wait )) {
  600. FsRtlExitFileSystem();
  601. return FALSE;
  602. }
  603. //
  604. // If writing to end of file, we must recalculate new size.
  605. //
  606. if (WriteToEndOfFile) {
  607. Offset = Header->FileSize;
  608. NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;
  609. }
  610. if ((FileObject->PrivateCacheMap == NULL) ||
  611. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  612. ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart ) ) {
  613. ExReleaseResourceLite( Header->Resource );
  614. FsRtlExitFileSystem();
  615. return FALSE;
  616. }
  617. }
  618. //
  619. // Check if fast I/O is questionable and if so then go ask
  620. // the file system the answer
  621. //
  622. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  623. PFAST_IO_DISPATCH FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch;
  624. IO_STATUS_BLOCK IoStatus;
  625. //
  626. // All file system then set "Is Questionable" had better
  627. // support fast I/O
  628. //
  629. ASSERT(FastIoDispatch != NULL);
  630. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  631. //
  632. // Call the file system to check for fast I/O. If the
  633. // answer is anything other than GoForIt then we cannot
  634. // take the fast I/O path.
  635. //
  636. ASSERT(FILE_WRITE_TO_END_OF_FILE == 0xffffffff);
  637. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  638. FileOffset->QuadPart != (LONGLONG)-1 ?
  639. FileOffset : &Header->FileSize,
  640. Length,
  641. Wait,
  642. LockKey,
  643. FALSE, // write operation
  644. &IoStatus,
  645. DeviceObject )) {
  646. //
  647. // Fast I/O is not possible so release the Fcb and
  648. // return.
  649. //
  650. ExReleaseResourceLite( Header->Resource );
  651. FsRtlExitFileSystem();
  652. return FALSE;
  653. }
  654. }
  655. //
  656. // Now see if we will change FileSize. We have to do it now
  657. // so that our reads are not nooped.
  658. //
  659. if ( NewFileSize.QuadPart > Header->FileSize.QuadPart ) {
  660. FileSizeChanged = TRUE;
  661. OldFileSize = Header->FileSize;
  662. OldValidDataLength = Header->ValidDataLength;
  663. //
  664. // Deal with an extremely rare pathalogical case here the
  665. // file size wraps.
  666. //
  667. if ( (Header->FileSize.HighPart != NewFileSize.HighPart) &&
  668. (Header->PagingIoResource != NULL) ) {
  669. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  670. Header->FileSize = NewFileSize;
  671. ExReleaseResourceLite( Header->PagingIoResource );
  672. } else {
  673. Header->FileSize = NewFileSize;
  674. }
  675. }
  676. //
  677. // We can do fast i/o so call the cc routine to do the work
  678. // and then release the fcb when we've done. If for whatever
  679. // reason the copy write fails, then return FALSE to our
  680. // caller.
  681. //
  682. // Also mark this as the top level "Irp" so that lower file
  683. // system levels will not attempt a pop-up
  684. //
  685. PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
  686. try {
  687. //
  688. // See if we have to do some zeroing
  689. //
  690. if ( Offset.QuadPart > Header->ValidDataLength.QuadPart ) {
  691. Status = CcZeroData( FileObject,
  692. &Header->ValidDataLength,
  693. &Offset,
  694. Wait );
  695. }
  696. if (Status) {
  697. Status = CcCopyWrite( FileObject,
  698. &Offset,
  699. Length,
  700. Wait,
  701. Buffer );
  702. }
  703. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  704. ? EXCEPTION_EXECUTE_HANDLER
  705. : EXCEPTION_CONTINUE_SEARCH ) {
  706. Status = FALSE;
  707. }
  708. PsGetCurrentThread()->TopLevelIrp = 0;
  709. //
  710. // If we succeeded, see if we have to update FileSize or
  711. // ValidDataLength.
  712. //
  713. if (Status) {
  714. //
  715. // In the case of ValidDataLength, we really have to
  716. // check again since we did not do this when we acquired
  717. // the resource exclusive.
  718. //
  719. if ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart ) {
  720. //
  721. // Deal with an extremely rare pathalogical case here
  722. // the ValidDataLength wraps.
  723. //
  724. if ( (Header->ValidDataLength.HighPart != NewFileSize.HighPart) &&
  725. (Header->PagingIoResource != NULL) ) {
  726. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  727. Header->ValidDataLength = NewFileSize;
  728. ExReleaseResourceLite( Header->PagingIoResource );
  729. } else {
  730. Header->ValidDataLength = NewFileSize;
  731. }
  732. }
  733. //
  734. // Set this handle as having modified the file
  735. //
  736. FileObject->Flags |= FO_FILE_MODIFIED;
  737. if (FileSizeChanged) {
  738. *CcGetFileSizePointer(FileObject) = NewFileSize;
  739. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  740. }
  741. //
  742. // Also update the current file position pointer
  743. //
  744. FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
  745. //
  746. // If we did not succeed, then we must restore the original
  747. // FileSize while holding the PagingIoResource exclusive if
  748. // it exists.
  749. //
  750. } else if (FileSizeChanged) {
  751. if ( Header->PagingIoResource != NULL ) {
  752. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  753. Header->FileSize = OldFileSize;
  754. Header->ValidDataLength = OldValidDataLength;
  755. ExReleaseResourceLite( Header->PagingIoResource );
  756. } else {
  757. Header->FileSize = OldFileSize;
  758. Header->ValidDataLength = OldValidDataLength;
  759. }
  760. }
  761. }
  762. ExReleaseResourceLite( Header->Resource );
  763. FsRtlExitFileSystem();
  764. return Status;
  765. } else {
  766. //
  767. // A zero length transfer was requested.
  768. //
  769. return TRUE;
  770. }
  771. } else {
  772. //
  773. // The volume must be verified or the file is write through.
  774. //
  775. return FALSE;
  776. }
  777. }
  778. BOOLEAN
  779. FsRtlMdlReadDev (
  780. IN PFILE_OBJECT FileObject,
  781. IN PLARGE_INTEGER FileOffset,
  782. IN ULONG Length,
  783. IN ULONG LockKey,
  784. OUT PMDL *MdlChain,
  785. OUT PIO_STATUS_BLOCK IoStatus,
  786. IN PDEVICE_OBJECT DeviceObject
  787. )
  788. /*++
  789. Routine Description:
  790. This routine does a fast cached mdl read bypassing the usual file system
  791. entry routine (i.e., without the Irp). It is used to do a copy read
  792. of a cached file object. For a complete description of the arguments
  793. see CcMdlRead.
  794. Arguments:
  795. FileObject - Pointer to the file object being read.
  796. FileOffset - Byte offset in file for desired data.
  797. Length - Length of desired data in bytes.
  798. MdlChain - On output it returns a pointer to an MDL chain describing
  799. the desired data.
  800. IoStatus - Pointer to standard I/O status block to receive the status
  801. for the transfer.
  802. DeviceObject - Supplies DeviceObject for callee.
  803. Return Value:
  804. FALSE - if the data was not delivered, or if there is an I/O error.
  805. TRUE - if the data is being delivered
  806. --*/
  807. {
  808. PFSRTL_COMMON_FCB_HEADER Header;
  809. BOOLEAN Status = TRUE;
  810. LARGE_INTEGER BeyondLastByte;
  811. PAGED_CODE();
  812. //
  813. // Special case a read of zero length
  814. //
  815. if (Length == 0) {
  816. IoStatus->Status = STATUS_SUCCESS;
  817. IoStatus->Information = 0;
  818. return TRUE;
  819. }
  820. //
  821. // Overflows should've been handled by caller.
  822. //
  823. ASSERT(MAXLONGLONG - FileOffset->QuadPart >= (LONGLONG)Length);
  824. //
  825. // Get a real pointer to the common fcb header
  826. //
  827. BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  828. Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
  829. //
  830. // Enter the file system
  831. //
  832. FsRtlEnterFileSystem();
  833. CcFastMdlReadWait += 1;
  834. //
  835. // Acquired shared on the common fcb header
  836. //
  837. (VOID)ExAcquireResourceSharedLite( Header->Resource, TRUE );
  838. //
  839. // Now that the File is acquired shared, we can safely test if it is
  840. // really cached and if we can do fast i/o and if not
  841. // then release the fcb and return.
  842. //
  843. if ((FileObject->PrivateCacheMap == NULL) ||
  844. (Header->IsFastIoPossible == FastIoIsNotPossible)) {
  845. ExReleaseResourceLite( Header->Resource );
  846. FsRtlExitFileSystem();
  847. CcFastMdlReadNotPossible += 1;
  848. return FALSE;
  849. }
  850. //
  851. // Check if fast I/O is questionable and if so then go ask the file system
  852. // the answer
  853. //
  854. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  855. PFAST_IO_DISPATCH FastIoDispatch;
  856. ASSERT(!KeIsExecutingDpc());
  857. FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch;
  858. //
  859. // All file system then set "Is Questionable" had better support fast I/O
  860. //
  861. ASSERT(FastIoDispatch != NULL);
  862. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  863. //
  864. // Call the file system to check for fast I/O. If the answer is anything
  865. // other than GoForIt then we cannot take the fast I/O path.
  866. //
  867. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  868. FileOffset,
  869. Length,
  870. TRUE,
  871. LockKey,
  872. TRUE, // read operation
  873. IoStatus,
  874. IoGetRelatedDeviceObject( FileObject ) )) {
  875. //
  876. // Fast I/O is not possible so release the Fcb and return.
  877. //
  878. ExReleaseResourceLite( Header->Resource );
  879. FsRtlExitFileSystem();
  880. CcFastMdlReadNotPossible += 1;
  881. return FALSE;
  882. }
  883. }
  884. //
  885. // Check for read past file size.
  886. //
  887. if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) {
  888. if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) {
  889. IoStatus->Status = STATUS_END_OF_FILE;
  890. IoStatus->Information = 0;
  891. ExReleaseResourceLite( Header->Resource );
  892. FsRtlExitFileSystem();
  893. return TRUE;
  894. }
  895. Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart );
  896. }
  897. //
  898. // We can do fast i/o so call the cc routine to do the work and then
  899. // release the fcb when we've done. If for whatever reason the
  900. // mdl read fails, then return FALSE to our caller.
  901. //
  902. //
  903. // Also mark this as the top level "Irp" so that lower file system levels
  904. // will not attempt a pop-up
  905. //
  906. PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
  907. try {
  908. CcMdlRead( FileObject, FileOffset, Length, MdlChain, IoStatus );
  909. FileObject->Flags |= FO_FILE_FAST_IO_READ;
  910. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  911. ? EXCEPTION_EXECUTE_HANDLER
  912. : EXCEPTION_CONTINUE_SEARCH ) {
  913. Status = FALSE;
  914. }
  915. PsGetCurrentThread()->TopLevelIrp = 0;
  916. ExReleaseResourceLite( Header->Resource );
  917. FsRtlExitFileSystem();
  918. return Status;
  919. }
  920. //
  921. // The old routine will either dispatch or call FsRtlMdlReadDev
  922. //
  923. BOOLEAN
  924. FsRtlMdlRead (
  925. IN PFILE_OBJECT FileObject,
  926. IN PLARGE_INTEGER FileOffset,
  927. IN ULONG Length,
  928. IN ULONG LockKey,
  929. OUT PMDL *MdlChain,
  930. OUT PIO_STATUS_BLOCK IoStatus
  931. )
  932. /*++
  933. Routine Description:
  934. This routine does a fast cached mdl read bypassing the usual file system
  935. entry routine (i.e., without the Irp). It is used to do a copy read
  936. of a cached file object. For a complete description of the arguments
  937. see CcMdlRead.
  938. Arguments:
  939. FileObject - Pointer to the file object being read.
  940. FileOffset - Byte offset in file for desired data.
  941. Length - Length of desired data in bytes.
  942. MdlChain - On output it returns a pointer to an MDL chain describing
  943. the desired data.
  944. IoStatus - Pointer to standard I/O status block to receive the status
  945. for the transfer.
  946. Return Value:
  947. FALSE - if the data was not delivered, or if there is an I/O error.
  948. TRUE - if the data is being delivered
  949. --*/
  950. {
  951. PDEVICE_OBJECT DeviceObject, VolumeDeviceObject;
  952. PFAST_IO_DISPATCH FastIoDispatch;
  953. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  954. FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
  955. //
  956. // See if the (top-level) FileSystem has a FastIo routine, and if so, call it.
  957. //
  958. if ((FastIoDispatch != NULL) &&
  959. (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlRead)) &&
  960. (FastIoDispatch->MdlRead != NULL)) {
  961. return FastIoDispatch->MdlRead( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject );
  962. } else {
  963. //
  964. // Get the DeviceObject for the volume. If that DeviceObject is different, and
  965. // it specifies the FastIo routine, then we have to return FALSE here and cause
  966. // an Irp to get generated.
  967. //
  968. VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
  969. if ((VolumeDeviceObject != DeviceObject) &&
  970. (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) &&
  971. (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlRead)) &&
  972. (FastIoDispatch->MdlRead != NULL)) {
  973. return FALSE;
  974. //
  975. // Otherwise, call the default routine.
  976. //
  977. } else {
  978. return FsRtlMdlReadDev( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject );
  979. }
  980. }
  981. }
  982. //
  983. // The old routine will either dispatch or call FsRtlMdlReadCompleteDev
  984. //
  985. BOOLEAN
  986. FsRtlMdlReadComplete (
  987. IN PFILE_OBJECT FileObject,
  988. IN PMDL MdlChain
  989. )
  990. /*++
  991. Routine Description:
  992. This routine does a fast cached mdl read bypassing the usual file system
  993. entry routine (i.e., without the Irp). It is used to do a copy read
  994. of a cached file object.
  995. Arguments:
  996. FileObject - Pointer to the file object being read.
  997. MdlChain - Supplies a pointer to an MDL chain returned from CcMdlRead.
  998. Return Value:
  999. None
  1000. --*/
  1001. {
  1002. PDEVICE_OBJECT DeviceObject, VolumeDeviceObject;
  1003. PFAST_IO_DISPATCH FastIoDispatch;
  1004. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  1005. FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
  1006. //
  1007. // See if the (top-level) FileSystem has a FastIo routine, and if so, call it.
  1008. //
  1009. if ((FastIoDispatch != NULL) &&
  1010. (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlReadComplete)) &&
  1011. (FastIoDispatch->MdlReadComplete != NULL)) {
  1012. return FastIoDispatch->MdlReadComplete( FileObject, MdlChain, DeviceObject );
  1013. } else {
  1014. //
  1015. // Get the DeviceObject for the volume. If that DeviceObject is different, and
  1016. // it specifies the FastIo routine, then we have to return FALSE here and cause
  1017. // an Irp to get generated.
  1018. //
  1019. VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
  1020. if ((VolumeDeviceObject != DeviceObject) &&
  1021. (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) &&
  1022. (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlReadComplete)) &&
  1023. (FastIoDispatch->MdlReadComplete != NULL)) {
  1024. return FALSE;
  1025. //
  1026. // Otherwise, call the default routine.
  1027. //
  1028. } else {
  1029. return FsRtlMdlReadCompleteDev( FileObject, MdlChain, DeviceObject );
  1030. }
  1031. }
  1032. }
  1033. BOOLEAN
  1034. FsRtlMdlReadCompleteDev (
  1035. IN PFILE_OBJECT FileObject,
  1036. IN PMDL MdlChain,
  1037. IN PDEVICE_OBJECT DeviceObject
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. This routine does a fast cached mdl read bypassing the usual file system
  1042. entry routine (i.e., without the Irp). It is used to do a copy read
  1043. of a cached file object.
  1044. Arguments:
  1045. FileObject - Pointer to the file object being read.
  1046. MdlChain - Supplies a pointer to an MDL chain returned from CcMdlRead.
  1047. DeviceObject - Supplies the DeviceObject for the callee.
  1048. Return Value:
  1049. None
  1050. --*/
  1051. {
  1052. CcMdlReadComplete2( FileObject, MdlChain );
  1053. return TRUE;
  1054. }
  1055. BOOLEAN
  1056. FsRtlPrepareMdlWriteDev (
  1057. IN PFILE_OBJECT FileObject,
  1058. IN PLARGE_INTEGER FileOffset,
  1059. IN ULONG Length,
  1060. IN ULONG LockKey,
  1061. OUT PMDL *MdlChain,
  1062. OUT PIO_STATUS_BLOCK IoStatus,
  1063. IN PDEVICE_OBJECT DeviceObject
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. This routine does a fast cached mdl read bypassing the usual file system
  1068. entry routine (i.e., without the Irp). It is used to do a copy read
  1069. of a cached file object. For a complete description of the arguments
  1070. see CcMdlRead.
  1071. Arguments:
  1072. FileObject - Pointer to the file object being read.
  1073. FileOffset - Byte offset in file for desired data.
  1074. Length - Length of desired data in bytes.
  1075. MdlChain - On output it returns a pointer to an MDL chain describing
  1076. the desired data.
  1077. IoStatus - Pointer to standard I/O status block to receive the status
  1078. for the transfer.
  1079. DeviceObject - Supplies the DeviceObject for the callee.
  1080. Return Value:
  1081. FALSE - if the data was not written, or if there is an I/O error.
  1082. TRUE - if the data is being written
  1083. --*/
  1084. {
  1085. PFSRTL_COMMON_FCB_HEADER Header;
  1086. LARGE_INTEGER Offset, NewFileSize;
  1087. LARGE_INTEGER OldFileSize;
  1088. LARGE_INTEGER OldValidDataLength;
  1089. BOOLEAN Status = TRUE;
  1090. BOOLEAN AcquiredShared = FALSE;
  1091. BOOLEAN FileSizeChanged = FALSE;
  1092. BOOLEAN WriteToEndOfFile = (BOOLEAN)((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) &&
  1093. (FileOffset->HighPart == -1));
  1094. PAGED_CODE();
  1095. //
  1096. // Call CcCanIWrite. Also return FALSE if FileObject is write through,
  1097. // the File System must do that.
  1098. //
  1099. if ( !CcCanIWrite( FileObject, Length, TRUE, FALSE ) ||
  1100. FlagOn( FileObject->Flags, FO_WRITE_THROUGH )) {
  1101. return FALSE;
  1102. }
  1103. //
  1104. // Assume our transfer will work
  1105. //
  1106. IoStatus->Status = STATUS_SUCCESS;
  1107. //
  1108. // Special case the zero byte length
  1109. //
  1110. if (Length == 0) {
  1111. return TRUE;
  1112. }
  1113. //
  1114. // Get a real pointer to the common fcb header
  1115. //
  1116. Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;
  1117. //
  1118. // Enter the file system
  1119. //
  1120. FsRtlEnterFileSystem();
  1121. //
  1122. // Make our best guess on whether we need the file exclusive or
  1123. // shared.
  1124. //
  1125. NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  1126. if (WriteToEndOfFile || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) {
  1127. //
  1128. // Acquired exclusive on the common fcb header, and return if we don't
  1129. // get it.
  1130. //
  1131. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  1132. } else {
  1133. //
  1134. // Acquired shared on the common fcb header, and return if we don't
  1135. // get it.
  1136. //
  1137. ExAcquireResourceSharedLite( Header->Resource, TRUE );
  1138. AcquiredShared = TRUE;
  1139. }
  1140. //
  1141. // We have the fcb shared now check if we can do fast i/o and if the file
  1142. // space is allocated, and if not then release the fcb and return.
  1143. //
  1144. if (WriteToEndOfFile) {
  1145. Offset = Header->FileSize;
  1146. NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;
  1147. } else {
  1148. Offset = *FileOffset;
  1149. NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
  1150. }
  1151. //
  1152. // Now that the File is acquired shared, we can safely test if it is
  1153. // really cached and if we can do fast i/o and we do not have to extend.
  1154. // If not then release the fcb and return.
  1155. //
  1156. if ((FileObject->PrivateCacheMap == NULL) ||
  1157. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  1158. (MAXLONGLONG - Offset.QuadPart < (LONGLONG)Length) ||
  1159. ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart ) ) {
  1160. ExReleaseResourceLite( Header->Resource );
  1161. FsRtlExitFileSystem();
  1162. return FALSE;
  1163. }
  1164. //
  1165. // If we will be extending ValidDataLength, we will have to get the
  1166. // Fcb exclusive, and make sure that FastIo is still possible.
  1167. //
  1168. if (AcquiredShared && ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart )) {
  1169. ExReleaseResourceLite( Header->Resource );
  1170. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  1171. AcquiredShared = FALSE;
  1172. //
  1173. // If writing to end of file, we must recalculate new size.
  1174. //
  1175. if (WriteToEndOfFile) {
  1176. Offset = Header->FileSize;
  1177. NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;
  1178. }
  1179. if ((FileObject->PrivateCacheMap == NULL) ||
  1180. (Header->IsFastIoPossible == FastIoIsNotPossible) ||
  1181. ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart )) {
  1182. ExReleaseResourceLite( Header->Resource );
  1183. FsRtlExitFileSystem();
  1184. return FALSE;
  1185. }
  1186. }
  1187. //
  1188. // Check if fast I/O is questionable and if so then go ask the file system
  1189. // the answer
  1190. //
  1191. if (Header->IsFastIoPossible == FastIoIsQuestionable) {
  1192. PFAST_IO_DISPATCH FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch;
  1193. //
  1194. // All file system then set "Is Questionable" had better support fast I/O
  1195. //
  1196. ASSERT(FastIoDispatch != NULL);
  1197. ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);
  1198. //
  1199. // Call the file system to check for fast I/O. If the answer is anything
  1200. // other than GoForIt then we cannot take the fast I/O path.
  1201. //
  1202. if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
  1203. FileOffset,
  1204. Length,
  1205. TRUE,
  1206. LockKey,
  1207. FALSE, // write operation
  1208. IoStatus,
  1209. IoGetRelatedDeviceObject( FileObject ) )) {
  1210. //
  1211. // Fast I/O is not possible so release the Fcb and return.
  1212. //
  1213. ExReleaseResourceLite( Header->Resource );
  1214. FsRtlExitFileSystem();
  1215. return FALSE;
  1216. }
  1217. }
  1218. //
  1219. // Now see if we will change FileSize. We have to do it now so that our
  1220. // reads are not nooped.
  1221. //
  1222. if ( NewFileSize.QuadPart > Header->FileSize.QuadPart ) {
  1223. FileSizeChanged = TRUE;
  1224. OldFileSize = Header->FileSize;
  1225. OldValidDataLength = Header->ValidDataLength;
  1226. //
  1227. // Deal with an extremely rare pathalogical case here the file
  1228. // size wraps.
  1229. //
  1230. if ( (Header->FileSize.HighPart != NewFileSize.HighPart) &&
  1231. (Header->PagingIoResource != NULL) ) {
  1232. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  1233. Header->FileSize = NewFileSize;
  1234. ExReleaseResourceLite( Header->PagingIoResource );
  1235. } else {
  1236. Header->FileSize = NewFileSize;
  1237. }
  1238. }
  1239. //
  1240. // We can do fast i/o so call the cc routine to do the work and then
  1241. // release the fcb when we've done. If for whatever reason the
  1242. // copy write fails, then return FALSE to our caller.
  1243. //
  1244. //
  1245. // Also mark this as the top level "Irp" so that lower file system levels
  1246. // will not attempt a pop-up
  1247. //
  1248. PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;
  1249. try {
  1250. //
  1251. // See if we have to do some zeroing
  1252. //
  1253. if ( Offset.QuadPart > Header->ValidDataLength.QuadPart ) {
  1254. Status = CcZeroData( FileObject,
  1255. &Header->ValidDataLength,
  1256. &Offset,
  1257. TRUE );
  1258. }
  1259. if (Status) {
  1260. CcPrepareMdlWrite( FileObject, &Offset, Length, MdlChain, IoStatus );
  1261. }
  1262. } except( FsRtlIsNtstatusExpected(GetExceptionCode())
  1263. ? EXCEPTION_EXECUTE_HANDLER
  1264. : EXCEPTION_CONTINUE_SEARCH ) {
  1265. Status = FALSE;
  1266. }
  1267. PsGetCurrentThread()->TopLevelIrp = 0;
  1268. //
  1269. // If we succeeded, see if we have to update FileSize or ValidDataLength.
  1270. //
  1271. if (Status) {
  1272. //
  1273. // In the case of ValidDataLength, we really have to check again
  1274. // since we did not do this when we acquired the resource exclusive.
  1275. //
  1276. if ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart ) {
  1277. //
  1278. // Deal with an extremely rare pathalogical case here the
  1279. // ValidDataLength wraps.
  1280. //
  1281. if ( (Header->ValidDataLength.HighPart != NewFileSize.HighPart) &&
  1282. (Header->PagingIoResource != NULL) ) {
  1283. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  1284. Header->ValidDataLength = NewFileSize;
  1285. ExReleaseResourceLite( Header->PagingIoResource );
  1286. } else {
  1287. Header->ValidDataLength = NewFileSize;
  1288. }
  1289. }
  1290. //
  1291. // Set this handle as having modified the file
  1292. //
  1293. FileObject->Flags |= FO_FILE_MODIFIED;
  1294. if (FileSizeChanged) {
  1295. *CcGetFileSizePointer(FileObject) = NewFileSize;
  1296. FileObject->Flags |= FO_FILE_SIZE_CHANGED;
  1297. }
  1298. //
  1299. // If we did not succeed, then we must restore the original FileSize
  1300. // and release the resource. In the success path, the cache manager
  1301. // will release the resource.
  1302. //
  1303. } else {
  1304. if (FileSizeChanged) {
  1305. if ( Header->PagingIoResource != NULL ) {
  1306. (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
  1307. Header->FileSize = OldFileSize;
  1308. Header->ValidDataLength = OldValidDataLength;
  1309. ExReleaseResourceLite( Header->PagingIoResource );
  1310. } else {
  1311. Header->FileSize = OldFileSize;
  1312. Header->ValidDataLength = OldValidDataLength;
  1313. }
  1314. }
  1315. }
  1316. //
  1317. // Now we can release the resource.
  1318. //
  1319. ExReleaseResourceLite( Header->Resource );
  1320. FsRtlExitFileSystem();
  1321. return Status;
  1322. }
  1323. //
  1324. // The old routine will either dispatch or call FsRtlPrepareMdlWriteDev
  1325. //
  1326. BOOLEAN
  1327. FsRtlPrepareMdlWrite (
  1328. IN PFILE_OBJECT FileObject,
  1329. IN PLARGE_INTEGER FileOffset,
  1330. IN ULONG Length,
  1331. IN ULONG LockKey,
  1332. OUT PMDL *MdlChain,
  1333. OUT PIO_STATUS_BLOCK IoStatus
  1334. )
  1335. /*++
  1336. Routine Description:
  1337. This routine does a fast cached mdl read bypassing the usual file system
  1338. entry routine (i.e., without the Irp). It is used to do a copy read
  1339. of a cached file object. For a complete description of the arguments
  1340. see CcMdlRead.
  1341. Arguments:
  1342. FileObject - Pointer to the file object being read.
  1343. FileOffset - Byte offset in file for desired data.
  1344. Length - Length of desired data in bytes.
  1345. MdlChain - On output it returns a pointer to an MDL chain describing
  1346. the desired data.
  1347. IoStatus - Pointer to standard I/O status block to receive the status
  1348. for the transfer.
  1349. Return Value:
  1350. FALSE - if the data was not written, or if there is an I/O error.
  1351. TRUE - if the data is being written
  1352. --*/
  1353. {
  1354. PDEVICE_OBJECT DeviceObject, VolumeDeviceObject;
  1355. PFAST_IO_DISPATCH FastIoDispatch;
  1356. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  1357. FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
  1358. //
  1359. // See if the (top-level) FileSystem has a FastIo routine, and if so, call it.
  1360. //
  1361. if ((FastIoDispatch != NULL) &&
  1362. (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, PrepareMdlWrite)) &&
  1363. (FastIoDispatch->PrepareMdlWrite != NULL)) {
  1364. return FastIoDispatch->PrepareMdlWrite( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject );
  1365. } else {
  1366. //
  1367. // Get the DeviceObject for the volume. If that DeviceObject is different, and
  1368. // it specifies the FastIo routine, then we have to return FALSE here and cause
  1369. // an Irp to get generated.
  1370. //
  1371. VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
  1372. if ((VolumeDeviceObject != DeviceObject) &&
  1373. (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) &&
  1374. (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, PrepareMdlWrite)) &&
  1375. (FastIoDispatch->PrepareMdlWrite != NULL)) {
  1376. return FALSE;
  1377. //
  1378. // Otherwise, call the default routine.
  1379. //
  1380. } else {
  1381. return FsRtlPrepareMdlWriteDev( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject );
  1382. }
  1383. }
  1384. }
  1385. //
  1386. // The old routine will either dispatch or call FsRtlMdlWriteCompleteDev
  1387. //
  1388. BOOLEAN
  1389. FsRtlMdlWriteComplete (
  1390. IN PFILE_OBJECT FileObject,
  1391. IN PLARGE_INTEGER FileOffset,
  1392. IN PMDL MdlChain
  1393. )
  1394. /*++
  1395. Routine Description:
  1396. This routine completes an Mdl write.
  1397. Arguments:
  1398. FileObject - Pointer to the file object being read.
  1399. MdlChain - Supplies a pointer to an MDL chain returned from CcMdlPrepareMdlWrite.
  1400. Return Value:
  1401. --*/
  1402. {
  1403. PDEVICE_OBJECT DeviceObject, VolumeDeviceObject;
  1404. PFAST_IO_DISPATCH FastIoDispatch;
  1405. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  1406. FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
  1407. //
  1408. // See if the (top-level) FileSystem has a FastIo routine, and if so, call it.
  1409. //
  1410. if ((FastIoDispatch != NULL) &&
  1411. (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlWriteComplete)) &&
  1412. (FastIoDispatch->MdlWriteComplete != NULL)) {
  1413. return FastIoDispatch->MdlWriteComplete( FileObject, FileOffset, MdlChain, DeviceObject );
  1414. } else {
  1415. //
  1416. // Get the DeviceObject for the volume. If that DeviceObject is different, and
  1417. // it specifies the FastIo routine, then we have to return FALSE here and cause
  1418. // an Irp to get generated.
  1419. //
  1420. VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
  1421. if ((VolumeDeviceObject != DeviceObject) &&
  1422. (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) &&
  1423. (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlWriteComplete)) &&
  1424. (FastIoDispatch->MdlWriteComplete != NULL)) {
  1425. return FALSE;
  1426. //
  1427. // Otherwise, call the default routine.
  1428. //
  1429. } else {
  1430. return FsRtlMdlWriteCompleteDev( FileObject, FileOffset, MdlChain, DeviceObject );
  1431. }
  1432. }
  1433. }
  1434. BOOLEAN
  1435. FsRtlMdlWriteCompleteDev (
  1436. IN PFILE_OBJECT FileObject,
  1437. IN PLARGE_INTEGER FileOffset,
  1438. IN PMDL MdlChain,
  1439. IN PDEVICE_OBJECT DeviceObject
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. This routine completes an Mdl write.
  1444. Arguments:
  1445. FileObject - Pointer to the file object being read.
  1446. MdlChain - Supplies a pointer to an MDL chain returned from CcMdlPrepareMdlWrite.
  1447. DeviceObject - Supplies the DeviceObject for the callee.
  1448. Return Value:
  1449. --*/
  1450. {
  1451. //
  1452. // Do not support WRITE_THROUGH in the fast path call.
  1453. //
  1454. if (FlagOn( FileObject->Flags, FO_WRITE_THROUGH )) {
  1455. return FALSE;
  1456. }
  1457. CcMdlWriteComplete2( FileObject, FileOffset, MdlChain );
  1458. return TRUE;
  1459. }
  1460. NTKERNELAPI
  1461. NTSTATUS
  1462. FsRtlRegisterFileSystemFilterCallbacks (
  1463. IN PDRIVER_OBJECT FilterDriverObject,
  1464. IN PFS_FILTER_CALLBACKS Callbacks
  1465. )
  1466. /*++
  1467. Routine Description:
  1468. This routine registers the FilterDriverObject to receive the
  1469. notifications specified in Callbacks at the appropriate times
  1470. for the devices to which this driver is attached.
  1471. This should only be called by a file system filter during
  1472. its DriverEntry routine.
  1473. Arguments:
  1474. FileObject - Pointer to the file object being written.
  1475. EndingOffset - The offset of the last byte being written + 1.
  1476. ByteCount - Length of data in bytes.
  1477. ResourceToRelease - Returns the resource to release. Not defined if
  1478. FALSE is returned.
  1479. Return Value:
  1480. STATUS_SUCCESS - The callbacks were successfully registered
  1481. for this driver.
  1482. STATUS_INSUFFICIENT_RESOURCES - There wasn't enough memory to
  1483. store these callbacks for the driver.
  1484. STATUS_INVALID_PARAMETER - Returned in any of the parameters
  1485. are invalid.
  1486. --*/
  1487. {
  1488. PDRIVER_EXTENSION DriverExt;
  1489. PFS_FILTER_CALLBACKS FsFilterCallbacks;
  1490. PAGED_CODE();
  1491. if (!(ARGUMENT_PRESENT( FilterDriverObject ) &&
  1492. ARGUMENT_PRESENT( Callbacks ))) {
  1493. return STATUS_INVALID_PARAMETER;
  1494. }
  1495. DriverExt = FilterDriverObject->DriverExtension;
  1496. FsFilterCallbacks = ExAllocatePoolWithTag( NonPagedPool,
  1497. Callbacks->SizeOfFsFilterCallbacks,
  1498. FSRTL_FILTER_MEMORY_TAG );
  1499. if (FsFilterCallbacks == NULL) {
  1500. return STATUS_INSUFFICIENT_RESOURCES;
  1501. }
  1502. RtlCopyMemory( FsFilterCallbacks,
  1503. Callbacks,
  1504. Callbacks->SizeOfFsFilterCallbacks );
  1505. DriverExt->FsFilterCallbacks = FsFilterCallbacks;
  1506. return STATUS_SUCCESS;
  1507. }
  1508. NTKERNELAPI
  1509. BOOLEAN
  1510. FsRtlAcquireFileForModWrite (
  1511. IN PFILE_OBJECT FileObject,
  1512. IN PLARGE_INTEGER EndingOffset,
  1513. OUT PERESOURCE *ResourceToRelease
  1514. )
  1515. /*++
  1516. Routine Description:
  1517. This routine decides which file system resource the modified page
  1518. writer should acquire and acquires it if possible. Wait is always
  1519. specified as FALSE. We pass back the resource Mm has to release
  1520. when the write completes.
  1521. This routine is obsolete --- should call FsRtlAcquireFileForModWriteEx
  1522. instead.
  1523. Arguments:
  1524. FileObject - Pointer to the file object being written.
  1525. EndingOffset - The offset of the last byte being written + 1.
  1526. ByteCount - Length of data in bytes.
  1527. ResourceToRelease - Returns the resource to release. Not defined if
  1528. FALSE is returned.
  1529. Return Value:
  1530. FALSE - The resource could not be acquired without waiting.
  1531. TRUE - The returned resource has been acquired.
  1532. --*/
  1533. {
  1534. NTSTATUS Status;
  1535. //
  1536. // Just call the new version of this routine and process
  1537. // the NTSTATUS returned into TRUE for success and FALSE
  1538. // for failure.
  1539. //
  1540. Status = FsRtlAcquireFileForModWriteEx( FileObject,
  1541. EndingOffset,
  1542. ResourceToRelease );
  1543. if (!NT_SUCCESS( Status )) {
  1544. return FALSE;
  1545. }
  1546. return TRUE;
  1547. }
  1548. NTKERNELAPI
  1549. NTSTATUS
  1550. FsRtlAcquireFileForModWriteEx (
  1551. IN PFILE_OBJECT FileObject,
  1552. IN PLARGE_INTEGER EndingOffset,
  1553. OUT PERESOURCE *ResourceToRelease
  1554. )
  1555. /*++
  1556. Routine Description:
  1557. This routine decides which file system resource the modified page
  1558. writer should acquire and acquires it if possible. Wait is always
  1559. specified as FALSE. We pass back the resource Mm has to release
  1560. when the write completes.
  1561. The operation is presented to any file system filters attached to this
  1562. volume before and after the file system is asked to acquire this resource.
  1563. Arguments:
  1564. FileObject - Pointer to the file object being written.
  1565. EndingOffset - The offset of the last byte being written + 1.
  1566. ByteCount - Length of data in bytes.
  1567. ResourceToRelease - Returns the resource to release. Not defined if
  1568. FALSE is returned.
  1569. Return Value:
  1570. FALSE - The resource could not be acquired without waiting.
  1571. TRUE - The returned resource has been acquired.
  1572. --*/
  1573. {
  1574. PDEVICE_OBJECT DeviceObject;
  1575. PDEVICE_OBJECT BaseFsDeviceObject;
  1576. FS_FILTER_CTRL FsFilterCtrl;
  1577. PFS_FILTER_CALLBACK_DATA CallbackData;
  1578. PFSRTL_COMMON_FCB_HEADER Header;
  1579. PERESOURCE ResourceAcquired;
  1580. PFAST_IO_DISPATCH FastIoDispatch;
  1581. PFS_FILTER_CALLBACKS FsFilterCallbacks;
  1582. BOOLEAN AcquireExclusive;
  1583. PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
  1584. NTSTATUS Status = STATUS_SUCCESS;
  1585. BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
  1586. BOOLEAN ReleaseBaseFsDeviceReference = FALSE;
  1587. BOOLEAN BaseFsFailedOperation = FALSE;
  1588. //
  1589. // There are cases when the device that is the base fs device for
  1590. // this file object will register for the FsFilter callbacks instead of
  1591. // the legacy FastIo interfaces (DFS does this). It then can redirect
  1592. // these operations to another stack that could possibly have file system
  1593. // filter drivers correctly.
  1594. //
  1595. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  1596. BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
  1597. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  1598. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  1599. //
  1600. // The BaseFsDeviceObject should only support one of these interfaces --
  1601. // either the FastIoDispatch interface for the FsFilterCallbacks interface.
  1602. // If a device provides support for both interfaces, we will only use
  1603. // the FsFilterCallback interface.
  1604. //
  1605. ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireForModWrite ) &&
  1606. (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForModifiedPageWriter ) ||
  1607. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForModifiedPageWriter ))) );
  1608. if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForModifiedPageWriter ) ||
  1609. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForModifiedPageWriter )) {
  1610. BaseFsGetsFsFilterCallbacks = TRUE;
  1611. }
  1612. if (DeviceObject == BaseFsDeviceObject &&
  1613. !BaseFsGetsFsFilterCallbacks) {
  1614. //
  1615. // There are no filters attached to this device and the base file system
  1616. // does not want these callbacks. This quick check allows us to bypass the
  1617. // logic to see if any filters are interested.
  1618. //
  1619. CallFilters = NULL;
  1620. }
  1621. if (CallFilters) {
  1622. //
  1623. // Call routine to initialize the control structure.
  1624. //
  1625. Status = FsFilterCtrlInit( &FsFilterCtrl,
  1626. FS_FILTER_ACQUIRE_FOR_MOD_WRITE,
  1627. DeviceObject,
  1628. BaseFsDeviceObject,
  1629. FileObject,
  1630. TRUE );
  1631. if (!NT_SUCCESS( Status )) {
  1632. return Status;
  1633. }
  1634. //
  1635. // Initialize the operation-specific parameters in the callback data.
  1636. //
  1637. CallbackData = &(FsFilterCtrl.Data);
  1638. CallbackData->Parameters.AcquireForModifiedPageWriter.EndingOffset = EndingOffset;
  1639. Status = FsFilterPerformCallbacks( &FsFilterCtrl,
  1640. TRUE,
  1641. TRUE,
  1642. &BaseFsFailedOperation );
  1643. }
  1644. if (NT_SUCCESS( Status )) {
  1645. if (CallFilters && FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {
  1646. BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
  1647. ReleaseBaseFsDeviceReference = TRUE;
  1648. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  1649. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  1650. FileObject = FsFilterCtrl.Data.FileObject;
  1651. }
  1652. if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForModifiedPageWriter ) ||
  1653. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForModifiedPageWriter ))) {
  1654. //
  1655. // Call the base file system.
  1656. //
  1657. if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireForModWrite )) {
  1658. Status = FastIoDispatch->AcquireForModWrite( FileObject,
  1659. EndingOffset,
  1660. ResourceToRelease,
  1661. BaseFsDeviceObject );
  1662. } else {
  1663. Status = STATUS_INVALID_DEVICE_REQUEST;
  1664. }
  1665. //
  1666. // If there is a failure at this point, we know that the failure
  1667. // was caused by the base file system.
  1668. //
  1669. BaseFsFailedOperation = TRUE;
  1670. }
  1671. if (ReleaseBaseFsDeviceReference) {
  1672. ObDereferenceObject( BaseFsDeviceObject );
  1673. }
  1674. }
  1675. ASSERT( (Status == STATUS_SUCCESS) ||
  1676. (Status == STATUS_CANT_WAIT) ||
  1677. (Status == STATUS_INVALID_DEVICE_REQUEST) );
  1678. //
  1679. // If the base file system didn't have an AcquireForModWrite handler
  1680. // or couldn't return STATUS_SUCCESS or STATUS_CANT_WAIT,
  1681. // we need to perform the default actions here.
  1682. //
  1683. if ((Status != STATUS_SUCCESS) &&
  1684. (Status != STATUS_CANT_WAIT) &&
  1685. BaseFsFailedOperation) {
  1686. //
  1687. // We follow the following rules to determine which resource
  1688. // to acquire. We use the flags in the common header. These
  1689. // flags can't change once we have acquired any resource.
  1690. // This means we can do an unsafe test and optimisticly
  1691. // acquire a resource. At that point we can test the bits
  1692. // to see if we have what we want.
  1693. //
  1694. // 0 - If there is no main resource, acquire nothing.
  1695. //
  1696. // 1 - Acquire the main resource exclusively if the
  1697. // ACQUIRE_MAIN_RSRC_EX flag is set or we are extending
  1698. // valid data.
  1699. //
  1700. // 2 - Acquire the main resource shared if there is
  1701. // no paging io resource or the
  1702. // ACQUIRE_MAIN_RSRC_SH flag is set.
  1703. //
  1704. // 3 - Otherwise acquire the paging io resource shared.
  1705. //
  1706. Header = (PFSRTL_COMMON_FCB_HEADER) FileObject->FsContext;
  1707. if (Header->Resource == NULL) {
  1708. *ResourceToRelease = NULL;
  1709. Status = STATUS_SUCCESS;
  1710. goto FsRtlAcquireFileForModWrite_CallCompletionCallbacks;
  1711. }
  1712. if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX ) ||
  1713. (EndingOffset->QuadPart > Header->ValidDataLength.QuadPart &&
  1714. Header->ValidDataLength.QuadPart != Header->FileSize.QuadPart)) {
  1715. ResourceAcquired = Header->Resource;
  1716. AcquireExclusive = TRUE;
  1717. } else if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH ) ||
  1718. Header->PagingIoResource == NULL) {
  1719. ResourceAcquired = Header->Resource;
  1720. AcquireExclusive = FALSE;
  1721. } else {
  1722. ResourceAcquired = Header->PagingIoResource;
  1723. AcquireExclusive = FALSE;
  1724. }
  1725. //
  1726. // Perform the following in a loop in case we need to back and
  1727. // check the state of the resource acquisition. In most cases
  1728. // the initial checks will succeed and we can proceed immediately.
  1729. // We have to worry about the two FsRtl bits changing but
  1730. // if there is no paging io resource before there won't ever be
  1731. // one.
  1732. //
  1733. while (TRUE) {
  1734. //
  1735. // Now acquire the desired resource.
  1736. //
  1737. if (AcquireExclusive) {
  1738. if (!ExAcquireResourceExclusiveLite( ResourceAcquired, FALSE )) {
  1739. Status = STATUS_CANT_WAIT;
  1740. goto FsRtlAcquireFileForModWrite_CallCompletionCallbacks;
  1741. }
  1742. } else if (!ExAcquireSharedWaitForExclusive( ResourceAcquired, FALSE )) {
  1743. Status = STATUS_CANT_WAIT;
  1744. goto FsRtlAcquireFileForModWrite_CallCompletionCallbacks;
  1745. }
  1746. //
  1747. // If the valid data length is changing or the exclusive bit is
  1748. // set and we don't have the main resource exclusive then
  1749. // release the current resource and acquire the main resource
  1750. // exclusively and move to the top of the loop.
  1751. //
  1752. // We must get it exclusive in all cases where the ending offset
  1753. // is beyond vdl. It used to be allowed shared if vdl == fs, but
  1754. // this neglected the possibility that the file could be extended
  1755. // under our shared (pagingio) access.
  1756. //
  1757. if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX ) ||
  1758. EndingOffset->QuadPart > Header->ValidDataLength.QuadPart) {
  1759. //
  1760. // If we don't have the main resource exclusively then
  1761. // release the current resource and attempt to acquire
  1762. // the main resource exclusively.
  1763. //
  1764. if (!AcquireExclusive) {
  1765. ExReleaseResourceLite( ResourceAcquired );
  1766. AcquireExclusive = TRUE;
  1767. ResourceAcquired = Header->Resource;
  1768. continue;
  1769. }
  1770. //
  1771. // We have the correct resource. Exit the loop.
  1772. //
  1773. //
  1774. // If we should be acquiring the main resource shared then move
  1775. // to acquire the correct resource and proceed to the top of the loop.
  1776. //
  1777. } else if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH )) {
  1778. //
  1779. // If we have the main resource exclusively then downgrade to
  1780. // shared and exit the loop.
  1781. //
  1782. if (AcquireExclusive) {
  1783. ExConvertExclusiveToSharedLite( ResourceAcquired );
  1784. //
  1785. // If we have the paging io resource then give up this resource
  1786. // and acquire the main resource exclusively. This is going
  1787. // at it with a large hammer but is guaranteed to be resolved
  1788. // in the next pass through the loop.
  1789. //
  1790. } else if (ResourceAcquired != Header->Resource) {
  1791. ExReleaseResourceLite( ResourceAcquired );
  1792. ResourceAcquired = Header->Resource;
  1793. AcquireExclusive = TRUE;
  1794. continue;
  1795. }
  1796. //
  1797. // We have the correct resource. Exit the loop.
  1798. //
  1799. //
  1800. // At this point we should have the paging Io resource shared
  1801. // if it exists. If not then acquire it shared and release the
  1802. // other resource and exit the loop.
  1803. //
  1804. } else if (Header->PagingIoResource != NULL
  1805. && ResourceAcquired != Header->PagingIoResource) {
  1806. ResourceAcquired = NULL;
  1807. if (ExAcquireSharedWaitForExclusive( Header->PagingIoResource, FALSE )) {
  1808. ResourceAcquired = Header->PagingIoResource;
  1809. }
  1810. ExReleaseResourceLite( Header->Resource );
  1811. if (ResourceAcquired == NULL) {
  1812. Status = STATUS_CANT_WAIT;
  1813. goto FsRtlAcquireFileForModWrite_CallCompletionCallbacks;
  1814. }
  1815. //
  1816. // We now have the correct resource. Exit the loop.
  1817. //
  1818. //
  1819. // We should have the main resource shared. If we don't then
  1820. // degrade our lock to shared access.
  1821. //
  1822. } else if (AcquireExclusive) {
  1823. ExConvertExclusiveToSharedLite( ResourceAcquired );
  1824. //
  1825. // We now have the correct resource. Exit the loop.
  1826. //
  1827. }
  1828. //
  1829. // We have the correct resource. Exit the loop.
  1830. //
  1831. break;
  1832. }
  1833. *ResourceToRelease = ResourceAcquired;
  1834. Status = STATUS_SUCCESS;
  1835. }
  1836. FsRtlAcquireFileForModWrite_CallCompletionCallbacks:
  1837. //
  1838. // Again, we only want to call try to do completion callbacks
  1839. // if there are any filters attached to this device that have
  1840. // completion callbacks. In any case, if we called down to the filters
  1841. // we need to free the FsFilterCtrl.
  1842. //
  1843. if (CallFilters) {
  1844. if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {
  1845. FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
  1846. }
  1847. FsFilterCtrlFree( &FsFilterCtrl );
  1848. }
  1849. #if DBG
  1850. if (NT_SUCCESS( Status )) {
  1851. gCounter.AcquireFileForModWriteEx_Succeed ++;
  1852. } else {
  1853. gCounter.AcquireFileForModWriteEx_Fail ++;
  1854. }
  1855. #endif
  1856. return Status;
  1857. }
  1858. NTKERNELAPI
  1859. VOID
  1860. FsRtlReleaseFileForModWrite (
  1861. IN PFILE_OBJECT FileObject,
  1862. IN PERESOURCE ResourceToRelease
  1863. )
  1864. /*++
  1865. Routine Description:
  1866. This routine releases a file system resource previously acquired for
  1867. the modified page writer.
  1868. Arguments:
  1869. FileObject - Pointer to the file object being written.
  1870. ResourceToRelease - Supplies the resource to release. Not defined if
  1871. FALSE is returned.
  1872. Return Value:
  1873. None.
  1874. --*/
  1875. {
  1876. PDEVICE_OBJECT BaseFsDeviceObject, DeviceObject;
  1877. PFAST_IO_DISPATCH FastIoDispatch;
  1878. PFS_FILTER_CALLBACKS FsFilterCallbacks;
  1879. FS_FILTER_CTRL FsFilterCtrl;
  1880. PFS_FILTER_CALLBACK_DATA CallbackData;
  1881. PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
  1882. NTSTATUS Status = STATUS_SUCCESS;
  1883. BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
  1884. BOOLEAN ReleaseBaseDeviceReference = FALSE;
  1885. BOOLEAN BaseFsFailedOperation = FALSE;
  1886. #if DBG
  1887. gCounter.ReleaseFileForModWrite ++;
  1888. #endif
  1889. //
  1890. // There are cases when the device that is the base fs device for
  1891. // this file object will register for the FsFilter callbacks instead of
  1892. // the legacy FastIo interfaces (DFS does this). It then can redirect
  1893. // these operations to another stack that could possibly have file system
  1894. // filter drivers correctly.
  1895. //
  1896. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  1897. BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
  1898. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  1899. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  1900. //
  1901. // The BaseFsDeviceObject should only support one of these interfaces --
  1902. // either the FastIoDispatch interface for the FsFilterCallbacks interface.
  1903. // If a device provides support for both interfaces, we will only use
  1904. // the FsFilterCallback interface.
  1905. //
  1906. ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, ReleaseForModWrite ) &&
  1907. (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForModifiedPageWriter ) ||
  1908. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForModifiedPageWriter ))) );
  1909. if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForModifiedPageWriter ) ||
  1910. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForModifiedPageWriter )) {
  1911. BaseFsGetsFsFilterCallbacks = TRUE;
  1912. }
  1913. if (DeviceObject == BaseFsDeviceObject &&
  1914. !BaseFsGetsFsFilterCallbacks) {
  1915. //
  1916. // There are no filters attached to this device and the base file system
  1917. // does not want these callbacks. This quick check allows us to bypass the
  1918. // logic to see if any filters are interested.
  1919. //
  1920. CallFilters = NULL;
  1921. }
  1922. if (CallFilters) {
  1923. FsFilterCtrlInit( &FsFilterCtrl,
  1924. FS_FILTER_RELEASE_FOR_MOD_WRITE,
  1925. DeviceObject,
  1926. BaseFsDeviceObject,
  1927. FileObject,
  1928. FALSE );
  1929. //
  1930. // Initialize the operation-specific parameters in the callback data.
  1931. //
  1932. CallbackData = &(FsFilterCtrl.Data);
  1933. CallbackData->Parameters.ReleaseForModifiedPageWriter.ResourceToRelease = ResourceToRelease;
  1934. Status = FsFilterPerformCallbacks( &FsFilterCtrl,
  1935. FALSE,
  1936. TRUE,
  1937. &BaseFsFailedOperation );
  1938. }
  1939. if (NT_SUCCESS( Status )) {
  1940. if (CallFilters && FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {
  1941. BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
  1942. ReleaseBaseDeviceReference = TRUE;
  1943. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  1944. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  1945. FileObject = FsFilterCtrl.Data.FileObject;
  1946. }
  1947. if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForModifiedPageWriter ) ||
  1948. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForModifiedPageWriter ))) {
  1949. //
  1950. // Call the base file system.
  1951. //
  1952. if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, ReleaseForModWrite )) {
  1953. Status = FastIoDispatch->ReleaseForModWrite( FileObject,
  1954. ResourceToRelease,
  1955. BaseFsDeviceObject );
  1956. } else {
  1957. Status = STATUS_INVALID_DEVICE_REQUEST;
  1958. }
  1959. //
  1960. // If there is a failure at this point, we know that the failure
  1961. // was caused by the base file system.
  1962. //
  1963. BaseFsFailedOperation = TRUE;
  1964. }
  1965. if (ReleaseBaseDeviceReference) {
  1966. ObDereferenceObject( BaseFsDeviceObject );
  1967. }
  1968. }
  1969. ASSERT( (Status == STATUS_SUCCESS) || (Status == STATUS_INVALID_DEVICE_REQUEST) );
  1970. //
  1971. // If the base file system doesn't provide a handler for this
  1972. // operation or the handler couldn't release the lock, perform the
  1973. // default action, which is releasing the ResourceToRelease.
  1974. //
  1975. if (Status == STATUS_INVALID_DEVICE_REQUEST &&
  1976. BaseFsFailedOperation) {
  1977. ExReleaseResourceLite( ResourceToRelease );
  1978. Status = STATUS_SUCCESS;
  1979. }
  1980. //
  1981. // Again, we only want to call try to do completion callbacks
  1982. // if there are any filters attached to this device that have
  1983. // completion callbacks. In any case, if we called down to the filters
  1984. // we need to free the FsFilterCtrl.
  1985. //
  1986. if (CallFilters) {
  1987. if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {
  1988. FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
  1989. }
  1990. FsFilterCtrlFree( &FsFilterCtrl );
  1991. }
  1992. }
  1993. NTKERNELAPI
  1994. VOID
  1995. FsRtlAcquireFileForCcFlush (
  1996. IN PFILE_OBJECT FileObject
  1997. )
  1998. /*++
  1999. Routine Description:
  2000. This routine acquires a file system resource prior to a call to CcFlush.
  2001. This routine is obsolete --- FsRtlAcquireFileForCcFlushEx should
  2002. be used instead.
  2003. Arguments:
  2004. FileObject - Pointer to the file object being written.
  2005. Return Value:
  2006. None.
  2007. --*/
  2008. {
  2009. NTSTATUS Status;
  2010. PAGED_CODE();
  2011. //
  2012. // Just call the new version of this routine and ignore
  2013. // the return value. In the debug version, we will assert
  2014. // if we see a failure here to encourage people to call the
  2015. // FsRtlAcquireFileForCcFlushEx.
  2016. //
  2017. Status = FsRtlAcquireFileForCcFlushEx( FileObject );
  2018. ASSERT( NT_SUCCESS( Status ) );
  2019. }
  2020. NTKERNELAPI
  2021. NTSTATUS
  2022. FsRtlAcquireFileForCcFlushEx (
  2023. IN PFILE_OBJECT FileObject
  2024. )
  2025. /*++
  2026. Routine Description:
  2027. This routine acquires a file system resource prior to a call to CcFlush.
  2028. This operation is presented to all the file system filters in the
  2029. filter stack for this volume. If all filters success the operation,
  2030. the base file system is requested to acquire the file system resource
  2031. for CcFlush.
  2032. Arguments:
  2033. FileObject - Pointer to the file object being written.
  2034. Return Value:
  2035. None.
  2036. --*/
  2037. {
  2038. PDEVICE_OBJECT DeviceObject;
  2039. PDEVICE_OBJECT BaseFsDeviceObject;
  2040. FS_FILTER_CTRL FsFilterCtrl;
  2041. PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
  2042. NTSTATUS Status = STATUS_SUCCESS;
  2043. PFAST_IO_DISPATCH FastIoDispatch;
  2044. PFS_FILTER_CALLBACKS FsFilterCallbacks;
  2045. BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
  2046. BOOLEAN ReleaseBaseFsDeviceReference = FALSE;
  2047. BOOLEAN BaseFsFailedOperation = FALSE;
  2048. PAGED_CODE();
  2049. //
  2050. // There are cases when the device that is the base fs device for
  2051. // this file object will register for the FsFilter callbacks instead of
  2052. // the legacy FastIo interfaces (DFS does this). It then can redirect
  2053. // these operations to another stack that could possibly have file system
  2054. // filter drivers correctly.
  2055. //
  2056. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  2057. BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
  2058. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  2059. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  2060. //
  2061. // The BaseFsDeviceObject should only support one of these interfaces --
  2062. // either the FastIoDispatch interface for the FsFilterCallbacks interface.
  2063. // If a device provides support for both interfaces, we will only use
  2064. // the FsFilterCallback interface.
  2065. //
  2066. ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireForCcFlush ) &&
  2067. (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForCcFlush ) ||
  2068. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForCcFlush ))) );
  2069. if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForCcFlush ) ||
  2070. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForCcFlush )) {
  2071. BaseFsGetsFsFilterCallbacks = TRUE;
  2072. }
  2073. if (DeviceObject == BaseFsDeviceObject &&
  2074. !BaseFsGetsFsFilterCallbacks) {
  2075. //
  2076. // There are no filters attached to this device and the base file system
  2077. // does not want these callbacks. This quick check allows us to bypass the
  2078. // logic to see if any filters are interested.
  2079. //
  2080. CallFilters = NULL;
  2081. }
  2082. if (CallFilters) {
  2083. //
  2084. // Call routine to initialize the control structure.
  2085. //
  2086. Status = FsFilterCtrlInit( &FsFilterCtrl,
  2087. FS_FILTER_ACQUIRE_FOR_CC_FLUSH,
  2088. DeviceObject,
  2089. BaseFsDeviceObject,
  2090. FileObject,
  2091. TRUE );
  2092. if (!NT_SUCCESS( Status )) {
  2093. return Status;
  2094. }
  2095. //
  2096. // There are no operation specific parameters for this
  2097. // operation, so just perform the pre-callbacks.
  2098. //
  2099. FsRtlEnterFileSystem();
  2100. Status = FsFilterPerformCallbacks( &FsFilterCtrl,
  2101. TRUE,
  2102. TRUE,
  2103. &BaseFsFailedOperation );
  2104. } else {
  2105. //
  2106. // We don't have any filters to call, but we still need
  2107. // to disable APCs.
  2108. //
  2109. FsRtlEnterFileSystem();
  2110. }
  2111. if (NT_SUCCESS( Status )) {
  2112. if (CallFilters && FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {
  2113. BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
  2114. ReleaseBaseFsDeviceReference = TRUE;
  2115. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  2116. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  2117. FileObject = FsFilterCtrl.Data.FileObject;
  2118. }
  2119. if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForCcFlush ) ||
  2120. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForCcFlush))) {
  2121. //
  2122. // Call the base file system.
  2123. //
  2124. if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireForCcFlush )) {
  2125. Status = FastIoDispatch->AcquireForCcFlush( FileObject,
  2126. BaseFsDeviceObject );
  2127. } else {
  2128. Status = STATUS_INVALID_DEVICE_REQUEST;
  2129. }
  2130. //
  2131. // If there is a failure at this point, we know that the failure
  2132. // was caused by the base file system.
  2133. //
  2134. BaseFsFailedOperation = TRUE;
  2135. }
  2136. if (ReleaseBaseFsDeviceReference) {
  2137. ObDereferenceObject( BaseFsDeviceObject );
  2138. }
  2139. }
  2140. ASSERT( (Status == STATUS_SUCCESS) || (Status == STATUS_INVALID_DEVICE_REQUEST) );
  2141. //
  2142. // If the file system doesn't have a dispatch handler or failed this
  2143. // this operation, try to acquire the appropriate resources ourself.
  2144. //
  2145. if (Status == STATUS_INVALID_DEVICE_REQUEST &&
  2146. BaseFsFailedOperation) {
  2147. PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext;
  2148. //
  2149. // If not already owned get the main resource exclusive because we may
  2150. // extend ValidDataLength. Otherwise acquire it one more time recursively.
  2151. //
  2152. if (Header->Resource != NULL) {
  2153. if (!ExIsResourceAcquiredSharedLite( Header->Resource )) {
  2154. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  2155. } else {
  2156. ExAcquireResourceSharedLite( Header->Resource, TRUE );
  2157. }
  2158. }
  2159. //
  2160. // Also get the paging I/O resource ahead of any MM resources.
  2161. //
  2162. if (Header->PagingIoResource != NULL) {
  2163. ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
  2164. }
  2165. Status = STATUS_SUCCESS;
  2166. }
  2167. //
  2168. // Again, we only want to call try to do completion callbacks
  2169. // if there are any filters attached to this device that have
  2170. // completion callbacks. In any case, if we called down to the filters
  2171. // we need to free the FsFilterCtrl.
  2172. //
  2173. if (CallFilters) {
  2174. if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {
  2175. FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
  2176. }
  2177. FsFilterCtrlFree( &FsFilterCtrl );
  2178. }
  2179. //
  2180. // If this lock was not successfully acquired, then the lock
  2181. // will not need to be released. Therefore, we need to call
  2182. // FsRtlExitFileSystem now.
  2183. //
  2184. if (!NT_SUCCESS( Status )) {
  2185. FsRtlExitFileSystem();
  2186. }
  2187. #if DBG
  2188. if (NT_SUCCESS( Status )) {
  2189. gCounter.AcquireFileForCcFlushEx_Succeed ++;
  2190. } else {
  2191. gCounter.AcquireFileForCcFlushEx_Fail ++;
  2192. }
  2193. #endif
  2194. return Status;
  2195. }
  2196. NTKERNELAPI
  2197. VOID
  2198. FsRtlReleaseFileForCcFlush (
  2199. IN PFILE_OBJECT FileObject
  2200. )
  2201. /*++
  2202. Routine Description:
  2203. This routine releases a file system resource previously acquired for
  2204. the CcFlush.
  2205. Arguments:
  2206. FileObject - Pointer to the file object being written.
  2207. Return Value:
  2208. None.
  2209. --*/
  2210. {
  2211. PDEVICE_OBJECT BaseFsDeviceObject, DeviceObject;
  2212. FS_FILTER_CTRL FsFilterCtrl;
  2213. PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
  2214. NTSTATUS Status = STATUS_SUCCESS;
  2215. PFAST_IO_DISPATCH FastIoDispatch;
  2216. PFS_FILTER_CALLBACKS FsFilterCallbacks;
  2217. BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
  2218. BOOLEAN ReleaseBaseFsDeviceReference = FALSE;
  2219. BOOLEAN BaseFsFailedOperation = FALSE;
  2220. PAGED_CODE();
  2221. #if DBG
  2222. gCounter.ReleaseFileForCcFlush ++;
  2223. #endif
  2224. //
  2225. // There are cases when the device that is the base fs device for
  2226. // this file object will register for the FsFilter callbacks instead of
  2227. // the legacy FastIo interfaces (DFS does this). It then can redirect
  2228. // these operations to another stack that could possibly have file system
  2229. // filter drivers correctly.
  2230. //
  2231. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  2232. BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
  2233. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  2234. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  2235. //
  2236. // The BaseFsDeviceObject should only support one of these interfaces --
  2237. // either the FastIoDispatch interface for the FsFilterCallbacks interface.
  2238. // If a device provides support for both interfaces, we will only use
  2239. // the FsFilterCallback interface.
  2240. //
  2241. ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, ReleaseForCcFlush ) &&
  2242. (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForCcFlush ) ||
  2243. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForCcFlush ))) );
  2244. if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForCcFlush ) ||
  2245. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForCcFlush )) {
  2246. BaseFsGetsFsFilterCallbacks = TRUE;
  2247. }
  2248. if (DeviceObject == BaseFsDeviceObject &&
  2249. !BaseFsGetsFsFilterCallbacks) {
  2250. //
  2251. // There are no filters attached to this device and the base file system
  2252. // does not want these callbacks. This quick check allows us to bypass the
  2253. // logic to see if any filters are interested.
  2254. //
  2255. CallFilters = NULL;
  2256. }
  2257. if (CallFilters) {
  2258. FsFilterCtrlInit( &FsFilterCtrl,
  2259. FS_FILTER_RELEASE_FOR_CC_FLUSH,
  2260. DeviceObject,
  2261. BaseFsDeviceObject,
  2262. FileObject,
  2263. FALSE );
  2264. //
  2265. // There are no operation-specific parameters to initialize,
  2266. // so perform the preoperation callbacks.
  2267. //
  2268. Status = FsFilterPerformCallbacks( &FsFilterCtrl,
  2269. FALSE,
  2270. TRUE,
  2271. &BaseFsFailedOperation );
  2272. }
  2273. if (NT_SUCCESS( Status )) {
  2274. if (CallFilters && FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {
  2275. BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
  2276. ReleaseBaseFsDeviceReference= TRUE;
  2277. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  2278. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  2279. FileObject = FsFilterCtrl.Data.FileObject;
  2280. }
  2281. if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForCcFlush ) ||
  2282. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForCcFlush ))) {
  2283. //
  2284. // Call the base file system.
  2285. //
  2286. if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, ReleaseForCcFlush )) {
  2287. Status = FastIoDispatch->ReleaseForCcFlush( FileObject, BaseFsDeviceObject );
  2288. } else {
  2289. Status = STATUS_INVALID_DEVICE_REQUEST;
  2290. }
  2291. //
  2292. // If there is a failure at this point, we know that the failure
  2293. // was caused by the base file system.
  2294. //
  2295. BaseFsFailedOperation = TRUE;
  2296. }
  2297. if (ReleaseBaseFsDeviceReference) {
  2298. ObDereferenceObject( BaseFsDeviceObject );
  2299. }
  2300. }
  2301. ASSERT( (Status == STATUS_SUCCESS) || (Status == STATUS_INVALID_DEVICE_REQUEST) );
  2302. if (Status == STATUS_INVALID_DEVICE_REQUEST &&
  2303. BaseFsFailedOperation) {
  2304. PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext;
  2305. //
  2306. // The base file system doesn't provide a handler for this
  2307. // operation, so perform the default actions.
  2308. //
  2309. //
  2310. // Free whatever we could have acquired.
  2311. //
  2312. if (Header->PagingIoResource != NULL) {
  2313. ExReleaseResourceLite( Header->PagingIoResource );
  2314. }
  2315. if (Header->Resource != NULL) {
  2316. ExReleaseResourceLite( Header->Resource );
  2317. }
  2318. Status = STATUS_SUCCESS;
  2319. }
  2320. ASSERT( Status == STATUS_SUCCESS );
  2321. //
  2322. // Again, we only want to call try to do completion callbacks
  2323. // if there are any filters attached to this device that have
  2324. // completion callbacks. In any case, if we called down to the filters
  2325. // we need to free the FsFilterCtrl.
  2326. //
  2327. if (CallFilters) {
  2328. if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {
  2329. FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
  2330. }
  2331. FsFilterCtrlFree( &FsFilterCtrl );
  2332. }
  2333. FsRtlExitFileSystem();
  2334. }
  2335. NTKERNELAPI
  2336. VOID
  2337. FsRtlAcquireFileExclusive (
  2338. IN PFILE_OBJECT FileObject
  2339. )
  2340. /*++
  2341. Routine Description:
  2342. This routine is used by NtCreateSection to pre-acquire file system
  2343. resources in order to avoid deadlocks. If there is a FastIo entry
  2344. for AcquireFileForNtCreateSection then that routine will be called.
  2345. Otherwise, we will simply acquire the main file resource exclusive.
  2346. If there is no main resource then we acquire nothing and return
  2347. FALSE. In the cases that we acquire a resource, we also set the
  2348. TopLevelIrp field in the thread local storage to indicate to file
  2349. systems beneath us that we have acquired file system resources.
  2350. Arguments:
  2351. FileObject - Pointer to the file object being written.
  2352. Return Value:
  2353. NONE
  2354. --*/
  2355. {
  2356. NTSTATUS Status;
  2357. PAGED_CODE();
  2358. //
  2359. // Just call the common version of this function,
  2360. // FsRtlAcquireFileExclusiveCommon.
  2361. //
  2362. Status = FsRtlAcquireFileExclusiveCommon( FileObject, SyncTypeOther, 0 );
  2363. //
  2364. // This should always be STATUS_SUCCESS since we are not
  2365. // allowing failures and the file system cannot fail
  2366. // this operation...
  2367. //
  2368. ASSERT( NT_SUCCESS( Status ) );
  2369. }
  2370. NTKERNELAPI
  2371. NTSTATUS
  2372. FsRtlAcquireToCreateMappedSection (
  2373. IN PFILE_OBJECT FileObject,
  2374. IN ULONG SectionPageProtection
  2375. )
  2376. /*++
  2377. Routine Description:
  2378. This routine is meant to replace FsRtlAcquireFileExclusive for
  2379. the memory manager. Mm calls this routine to synchronize
  2380. for a mapped section create, but filters are allowed
  2381. to fail this operation. Other components that want to
  2382. synchronize with section creation should call
  2383. FsRtlAcquireFileExclusive.
  2384. This routine calls FsRtlAcquireFileExclusiveCommon to do
  2385. all the work.
  2386. This routine is used by NtCreateSection to pre-acquire file system
  2387. resources in order to avoid deadlocks. If there is a FastIo entry
  2388. for AcquireFileForNtCreateSection then that routine will be called.
  2389. Otherwise, we will simply acquire the main file resource exclusive.
  2390. If there is no main resource then we acquire nothing and return
  2391. FALSE. In the cases that we acquire a resource, we also set the
  2392. TopLevelIrp field in the thread local storage to indicate to file
  2393. systems beneath us that we have acquired file system resources.
  2394. Arguments:
  2395. FileObject - Pointer to the file object being written.
  2396. SectionPageProtection - The access requested for the section being
  2397. created.
  2398. Return Value:
  2399. The status of the operation.
  2400. --*/
  2401. {
  2402. PAGED_CODE();
  2403. return FsRtlAcquireFileExclusiveCommon( FileObject, SyncTypeCreateSection, SectionPageProtection );
  2404. }
  2405. NTKERNELAPI
  2406. NTSTATUS
  2407. FsRtlAcquireFileExclusiveCommon (
  2408. IN PFILE_OBJECT FileObject,
  2409. IN FS_FILTER_SECTION_SYNC_TYPE SyncType,
  2410. IN ULONG SectionPageProtection
  2411. )
  2412. /*++
  2413. Routine Description:
  2414. This routine is used to pre-acquire file system resources in order
  2415. to avoid deadlocks. The file system filters for this volume
  2416. will be notified about this operation, then, if there is a FastIo
  2417. entry for AcquireFileForNtCreateSection, that routine will be called.
  2418. Otherwise, we will simply acquire the main file resource exclusive.
  2419. If there is no main resource then we acquire nothing and return
  2420. STATUS_SUCCESS. Finally, the file system filters will be notified
  2421. whether or not this resource has been acquired.
  2422. Arguments:
  2423. FileObject - Pointer to the file object being written.
  2424. CreatingMappedSection - TRUE if this lock is being acquired so that
  2425. a mapped section can be created. Filters are allowed
  2426. to fail this operation. FALSE otherwise.
  2427. Return Value:
  2428. NONE
  2429. --*/
  2430. {
  2431. PDEVICE_OBJECT DeviceObject, BaseFsDeviceObject;
  2432. FS_FILTER_CTRL FsFilterCtrl;
  2433. PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
  2434. NTSTATUS Status = STATUS_SUCCESS;
  2435. BOOLEAN AllowFilterToFailOperation;
  2436. PFAST_IO_DISPATCH FastIoDispatch;
  2437. PFS_FILTER_CALLBACKS FsFilterCallbacks;
  2438. BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
  2439. BOOLEAN ReleaseBaseFsDeviceReference = FALSE;
  2440. BOOLEAN BaseFsFailedOperation = FALSE;
  2441. PAGED_CODE();
  2442. //
  2443. // There are cases when the device that is the base fs device for
  2444. // this file object will register for the FsFilter callbacks instead of
  2445. // the legacy FastIo interfaces (DFS does this). It then can redirect
  2446. // these operations to another stack that could possibly have file system
  2447. // filter drivers correctly.
  2448. //
  2449. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  2450. BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
  2451. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  2452. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  2453. //
  2454. // The BaseFsDeviceObject should only support one of these interfaces --
  2455. // either the FastIoDispatch interface for the FsFilterCallbacks interface.
  2456. // If a device provides support for both interfaces, we will only use
  2457. // the FsFilterCallback interface.
  2458. //
  2459. ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireFileForNtCreateSection ) &&
  2460. (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForSectionSynchronization ) ||
  2461. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForSectionSynchronization ))) );
  2462. if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForSectionSynchronization ) ||
  2463. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForSectionSynchronization )) {
  2464. BaseFsGetsFsFilterCallbacks = TRUE;
  2465. }
  2466. if (DeviceObject == BaseFsDeviceObject &&
  2467. !BaseFsGetsFsFilterCallbacks) {
  2468. //
  2469. // There are no filters attached to this device and the base file system
  2470. // does not want these callbacks. This quick check allows us to bypass the
  2471. // logic to see if any filters are interested.
  2472. //
  2473. CallFilters = NULL;
  2474. }
  2475. if (CallFilters) {
  2476. //
  2477. // Initialize operation specific parameters for this
  2478. // operation.
  2479. //
  2480. FsFilterCtrl.Data.Parameters.AcquireForSectionSynchronization.SyncType =
  2481. SyncType;
  2482. FsFilterCtrl.Data.Parameters.AcquireForSectionSynchronization.PageProtection =
  2483. SectionPageProtection;
  2484. switch (SyncType) {
  2485. case SyncTypeCreateSection:
  2486. AllowFilterToFailOperation = TRUE;
  2487. break;
  2488. case SyncTypeOther:
  2489. default:
  2490. AllowFilterToFailOperation = FALSE;
  2491. }
  2492. //
  2493. // Call routine to initialize the control structure.
  2494. //
  2495. Status = FsFilterCtrlInit( &FsFilterCtrl,
  2496. FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION,
  2497. DeviceObject,
  2498. BaseFsDeviceObject,
  2499. FileObject,
  2500. AllowFilterToFailOperation );
  2501. if (!NT_SUCCESS( Status )) {
  2502. return Status;
  2503. }
  2504. //
  2505. // There are no operation specific parameters for this
  2506. // operation, so just perform the pre-callbacks.
  2507. //
  2508. FsRtlEnterFileSystem();
  2509. //
  2510. // Note: If the filter is allowed to fail the operation, so is the
  2511. // base file system, so we will just use that variable for both
  2512. // parameters to FsFilterPerformCallbacks.
  2513. //
  2514. Status = FsFilterPerformCallbacks( &FsFilterCtrl,
  2515. AllowFilterToFailOperation,
  2516. AllowFilterToFailOperation,
  2517. &BaseFsFailedOperation );
  2518. } else {
  2519. //
  2520. // We don't have any filters to call, but we still need
  2521. // to disable APCs.
  2522. //
  2523. FsRtlEnterFileSystem();
  2524. }
  2525. if (NT_SUCCESS( Status )) {
  2526. if (CallFilters && FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {
  2527. BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
  2528. ReleaseBaseFsDeviceReference = TRUE;
  2529. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  2530. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  2531. FileObject = FsFilterCtrl.Data.FileObject;
  2532. }
  2533. if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForSectionSynchronization ) ||
  2534. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForSectionSynchronization ))) {
  2535. //
  2536. // Call the base file system.
  2537. //
  2538. if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireFileForNtCreateSection )) {
  2539. FastIoDispatch->AcquireFileForNtCreateSection( FileObject );
  2540. //
  2541. // The status should already be STATUS_SUCCESS if we come down
  2542. // this path. Since the FastIo handler doesn't return a value
  2543. // the status should remain STATUS_SUCCESS.
  2544. //
  2545. // Status = STATUS_SUCCESS;
  2546. } else {
  2547. Status = STATUS_INVALID_DEVICE_REQUEST;
  2548. }
  2549. //
  2550. // If there is a failure at this point, we know that the failure
  2551. // was caused by the base file system.
  2552. //
  2553. BaseFsFailedOperation = TRUE;
  2554. }
  2555. if (ReleaseBaseFsDeviceReference) {
  2556. ObDereferenceObject( BaseFsDeviceObject );
  2557. }
  2558. }
  2559. ASSERT( (Status == STATUS_SUCCESS) || (Status == STATUS_INVALID_DEVICE_REQUEST) );
  2560. if (Status == STATUS_INVALID_DEVICE_REQUEST &&
  2561. BaseFsFailedOperation) {
  2562. PFSRTL_COMMON_FCB_HEADER Header;
  2563. //
  2564. // The file system doesn't have a dispatch handler for this
  2565. // operation, so try to acquire the appropriate resources
  2566. // ourself.
  2567. //
  2568. //
  2569. // If there is a main file resource, acquire that.
  2570. //
  2571. Header = FileObject->FsContext;
  2572. if ((Header != NULL) &&
  2573. (Header->Resource != NULL)) {
  2574. ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
  2575. }
  2576. Status = STATUS_SUCCESS;
  2577. }
  2578. //
  2579. // Again, we only want to call try to do completion callbacks
  2580. // if there are any filters attached to this device that have
  2581. // completion callbacks. In any case, if we called down to the filters
  2582. // we need to free the FsFilterCtrl.
  2583. //
  2584. if (CallFilters) {
  2585. if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {
  2586. FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
  2587. }
  2588. FsFilterCtrlFree( &FsFilterCtrl );
  2589. }
  2590. //
  2591. // If this lock was not successfully acquired, then the lock
  2592. // will not need to be released. Therefore, we need to call
  2593. // FsRtlExitFileSystem now.
  2594. //
  2595. if (!NT_SUCCESS( Status )) {
  2596. FsRtlExitFileSystem();
  2597. }
  2598. #if DBG
  2599. if (NT_SUCCESS( Status )) {
  2600. gCounter.AcquireFileExclusiveEx_Succeed ++;
  2601. } else {
  2602. gCounter.AcquireFileExclusiveEx_Fail ++;
  2603. }
  2604. #endif
  2605. return Status;
  2606. }
  2607. NTKERNELAPI
  2608. VOID
  2609. FsRtlReleaseFile (
  2610. IN PFILE_OBJECT FileObject
  2611. )
  2612. /*++
  2613. Routine Description:
  2614. This routine releases resources acquired by FsRtlAcquireFileExclusive.
  2615. Arguments:
  2616. FileObject - Pointer to the file object being written.
  2617. Return Value:
  2618. None.
  2619. --*/
  2620. {
  2621. PDEVICE_OBJECT BaseFsDeviceObject, DeviceObject;
  2622. FS_FILTER_CTRL FsFilterCtrl;
  2623. PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
  2624. NTSTATUS Status = STATUS_SUCCESS;
  2625. PFAST_IO_DISPATCH FastIoDispatch;
  2626. PFS_FILTER_CALLBACKS FsFilterCallbacks;
  2627. BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
  2628. BOOLEAN ReleaseBaseFsDeviceReference = FALSE;
  2629. BOOLEAN BaseFsFailedOperation = FALSE;
  2630. PAGED_CODE();
  2631. #if DBG
  2632. gCounter.ReleaseFile ++;
  2633. #endif
  2634. //
  2635. // There are cases when the device that is the base fs device for
  2636. // this file object will register for the FsFilter callbacks instead of
  2637. // the legacy FastIo interfaces (DFS does this). It then can redirect
  2638. // these operations to another stack that could possibly have file system
  2639. // filter drivers correctly.
  2640. //
  2641. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  2642. BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
  2643. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  2644. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  2645. //
  2646. // The BaseFsDeviceObject should only support one of these interfaces --
  2647. // either the FastIoDispatch interface for the FsFilterCallbacks interface.
  2648. // If a device provides support for both interfaces, we will only use
  2649. // the FsFilterCallback interface.
  2650. //
  2651. ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, ReleaseFileForNtCreateSection ) &&
  2652. (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForSectionSynchronization ) ||
  2653. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForSectionSynchronization ))) );
  2654. if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForSectionSynchronization ) ||
  2655. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForSectionSynchronization )) {
  2656. BaseFsGetsFsFilterCallbacks = TRUE;
  2657. }
  2658. if (DeviceObject == BaseFsDeviceObject &&
  2659. !BaseFsGetsFsFilterCallbacks) {
  2660. //
  2661. // There are no filters attached to this device and the base file system
  2662. // does not want these callbacks. This quick check allows us to bypass the
  2663. // logic to see if any filters are interested.
  2664. //
  2665. CallFilters = NULL;
  2666. }
  2667. if (CallFilters) {
  2668. FsFilterCtrlInit( &FsFilterCtrl,
  2669. FS_FILTER_RELEASE_FOR_SECTION_SYNCHRONIZATION,
  2670. DeviceObject,
  2671. BaseFsDeviceObject,
  2672. FileObject,
  2673. FALSE );
  2674. //
  2675. // There are no operation-specific parameters to initialize,
  2676. // so perform the preoperation callbacks.
  2677. //
  2678. Status = FsFilterPerformCallbacks( &FsFilterCtrl,
  2679. FALSE,
  2680. FALSE,
  2681. &BaseFsFailedOperation );
  2682. }
  2683. if (NT_SUCCESS( Status )) {
  2684. if (CallFilters && FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {
  2685. BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
  2686. ReleaseBaseFsDeviceReference = TRUE;
  2687. FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
  2688. FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
  2689. FileObject = FsFilterCtrl.Data.FileObject;
  2690. }
  2691. if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForSectionSynchronization ) ||
  2692. VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForSectionSynchronization ))) {
  2693. //
  2694. // Call the base file system.
  2695. //
  2696. if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch,
  2697. ReleaseFileForNtCreateSection )) {
  2698. FastIoDispatch->ReleaseFileForNtCreateSection( FileObject );
  2699. //
  2700. // The status should already be STATUS_SUCCESS if we come down
  2701. // this path. Since the FastIo handler doesn't return a value
  2702. // the status should remain STATUS_SUCCESS.
  2703. //
  2704. // Status = STATUS_SUCCESS;
  2705. } else {
  2706. Status = STATUS_INVALID_DEVICE_REQUEST;
  2707. }
  2708. //
  2709. // If there is a failure at this point, we know that the failure
  2710. // was caused by the base file system.
  2711. //
  2712. BaseFsFailedOperation = TRUE;
  2713. }
  2714. if (ReleaseBaseFsDeviceReference) {
  2715. ObDereferenceObject( BaseFsDeviceObject );
  2716. }
  2717. }
  2718. ASSERT( (Status == STATUS_SUCCESS) || (Status == STATUS_INVALID_DEVICE_REQUEST ) );
  2719. if (Status == STATUS_INVALID_DEVICE_REQUEST &&
  2720. BaseFsFailedOperation) {
  2721. PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext;
  2722. //
  2723. // The base file system doesn't provide a handler for this
  2724. // operation, so perform the default actions.
  2725. //
  2726. //
  2727. // If there is a main file resource, release that.
  2728. //
  2729. if ((Header != NULL) && (Header->Resource != NULL)) {
  2730. ExReleaseResourceLite( Header->Resource );
  2731. }
  2732. Status = STATUS_SUCCESS;
  2733. }
  2734. //
  2735. // Again, we only want to call try to do completion callbacks
  2736. // if there are any filters attached to this device that have
  2737. // completion callbacks. In any case, if we called down to the filters
  2738. // we need to free the FsFilterCtrl.
  2739. //
  2740. if (CallFilters) {
  2741. if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {
  2742. FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
  2743. }
  2744. FsFilterCtrlFree( &FsFilterCtrl );
  2745. }
  2746. FsRtlExitFileSystem();
  2747. return;
  2748. }
  2749. NTSTATUS
  2750. FsRtlGetFileSize(
  2751. IN PFILE_OBJECT FileObject,
  2752. IN OUT PLARGE_INTEGER FileSize
  2753. )
  2754. /*++
  2755. Routine Description:
  2756. This routine is used to call the File System to get the FileSize
  2757. for a file.
  2758. It does this without acquiring the file object lock on synchronous file
  2759. objects. This routine is therefore safe to call if you already own
  2760. file system resources, while IoQueryFileInformation could (and does)
  2761. lead to deadlocks.
  2762. Arguments:
  2763. FileObject - The file to query
  2764. FileSize - Receives the file size.
  2765. Return Value:
  2766. NTSTATUS - The final I/O status of the operation. If the FileObject
  2767. refers to a directory, STATUS_FILE_IS_A_DIRECTORY is returned.
  2768. --*/
  2769. {
  2770. IO_STATUS_BLOCK IoStatus;
  2771. PDEVICE_OBJECT DeviceObject;
  2772. PFAST_IO_DISPATCH FastIoDispatch;
  2773. FILE_STANDARD_INFORMATION FileInformation;
  2774. PAGED_CODE();
  2775. //
  2776. // Get the address of the target device object.
  2777. //
  2778. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  2779. //
  2780. // Try the fast query call if it exists.
  2781. //
  2782. FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
  2783. if (FastIoDispatch &&
  2784. FastIoDispatch->FastIoQueryStandardInfo &&
  2785. FastIoDispatch->FastIoQueryStandardInfo( FileObject,
  2786. TRUE,
  2787. &FileInformation,
  2788. &IoStatus,
  2789. DeviceObject )) {
  2790. //
  2791. // Cool, it worked.
  2792. //
  2793. } else {
  2794. //
  2795. // Life's tough, take the long path.
  2796. //
  2797. PIRP Irp;
  2798. KEVENT Event;
  2799. NTSTATUS Status;
  2800. PIO_STACK_LOCATION IrpSp;
  2801. BOOLEAN HardErrorState;
  2802. //
  2803. // Initialize the event.
  2804. //
  2805. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  2806. //
  2807. // Allocate an I/O Request Packet (IRP) for this in-page operation.
  2808. //
  2809. Irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
  2810. if (Irp == NULL) {
  2811. return STATUS_INSUFFICIENT_RESOURCES;
  2812. }
  2813. //
  2814. // Disable hard errors over this call. Caller owns resources, is in a critical
  2815. // region and cannot complete hard error APCs.
  2816. //
  2817. HardErrorState = IoSetThreadHardErrorMode( FALSE );
  2818. //
  2819. // Get a pointer to the first stack location in the packet. This location
  2820. // will be used to pass the function codes and parameters to the first
  2821. // driver.
  2822. //
  2823. IrpSp = IoGetNextIrpStackLocation( Irp );
  2824. //
  2825. // Fill in the IRP according to this request, setting the flags to
  2826. // just cause IO to set the event and deallocate the Irp.
  2827. //
  2828. Irp->Flags = IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO;
  2829. Irp->RequestorMode = KernelMode;
  2830. Irp->UserIosb = &IoStatus;
  2831. Irp->UserEvent = &Event;
  2832. Irp->Tail.Overlay.OriginalFileObject = FileObject;
  2833. Irp->Tail.Overlay.Thread = PsGetCurrentThread();
  2834. Irp->AssociatedIrp.SystemBuffer = &FileInformation;
  2835. //
  2836. // Fill in the normal query parameters.
  2837. //
  2838. IrpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
  2839. IrpSp->FileObject = FileObject;
  2840. IrpSp->DeviceObject = DeviceObject;
  2841. IrpSp->Parameters.SetFile.Length = sizeof(FILE_STANDARD_INFORMATION);
  2842. IrpSp->Parameters.SetFile.FileInformationClass = FileStandardInformation;
  2843. //
  2844. // Queue the packet to the appropriate driver based. This routine
  2845. // should not raise.
  2846. //
  2847. Status = IoCallDriver( DeviceObject, Irp );
  2848. //
  2849. // If pending is returned (which is a successful status),
  2850. // we must wait for the request to complete.
  2851. //
  2852. if (Status == STATUS_PENDING) {
  2853. KeWaitForSingleObject( &Event,
  2854. Executive,
  2855. KernelMode,
  2856. FALSE,
  2857. (PLARGE_INTEGER)NULL);
  2858. }
  2859. //
  2860. // If we got an error back in Status, then the Iosb
  2861. // was not written, so we will just copy the status
  2862. // there, then test the final status after that.
  2863. //
  2864. if (!NT_SUCCESS(Status)) {
  2865. IoStatus.Status = Status;
  2866. }
  2867. //
  2868. // Reset the hard error state.
  2869. //
  2870. IoSetThreadHardErrorMode( HardErrorState );
  2871. }
  2872. //
  2873. // If the call worked, check to make sure it wasn't a directory and
  2874. // if not, fill in the FileSize parameter.
  2875. //
  2876. if (NT_SUCCESS(IoStatus.Status)) {
  2877. if (FileInformation.Directory) {
  2878. //
  2879. // Can't get file size for a directory. Return error.
  2880. //
  2881. IoStatus.Status = STATUS_FILE_IS_A_DIRECTORY;
  2882. } else {
  2883. *FileSize = FileInformation.EndOfFile;
  2884. }
  2885. }
  2886. return IoStatus.Status;
  2887. }
  2888. NTSTATUS
  2889. FsRtlSetFileSize(
  2890. IN PFILE_OBJECT FileObject,
  2891. IN OUT PLARGE_INTEGER FileSize
  2892. )
  2893. /*++
  2894. Routine Description:
  2895. This routine is used to call the File System to update FileSize
  2896. for a file.
  2897. It does this without acquiring the file object lock on synchronous file
  2898. objects. This routine is therefore safe to call if you already own
  2899. file system resources, while IoSetInformation could (and does) lead
  2900. to deadlocks.
  2901. Arguments:
  2902. FileObject - A pointer to a referenced file object.
  2903. ValidDataLength - Pointer to new FileSize.
  2904. Return Value:
  2905. Status of operation.
  2906. --*/
  2907. {
  2908. PIO_STACK_LOCATION IrpSp;
  2909. PDEVICE_OBJECT DeviceObject;
  2910. NTSTATUS Status;
  2911. FILE_END_OF_FILE_INFORMATION Buffer;
  2912. IO_STATUS_BLOCK IoStatus;
  2913. KEVENT Event;
  2914. PIRP Irp;
  2915. BOOLEAN HardErrorState;
  2916. PAGED_CODE();
  2917. //
  2918. // Copy FileSize to our buffer.
  2919. //
  2920. Buffer.EndOfFile = *FileSize;
  2921. //
  2922. // Initialize the event.
  2923. //
  2924. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  2925. //
  2926. // Begin by getting a pointer to the device object that the file resides
  2927. // on.
  2928. //
  2929. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  2930. //
  2931. // Allocate an I/O Request Packet (IRP) for this in-page operation.
  2932. //
  2933. Irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
  2934. if (Irp == NULL) {
  2935. return STATUS_INSUFFICIENT_RESOURCES;
  2936. }
  2937. //
  2938. // Disable hard errors over this call. Caller owns resources, is in a critical
  2939. // region and cannot complete hard error APCs.
  2940. //
  2941. HardErrorState = IoSetThreadHardErrorMode( FALSE );
  2942. //
  2943. // Get a pointer to the first stack location in the packet. This location
  2944. // will be used to pass the function codes and parameters to the first
  2945. // driver.
  2946. //
  2947. IrpSp = IoGetNextIrpStackLocation( Irp );
  2948. //
  2949. // Fill in the IRP according to this request, setting the flags to
  2950. // just cause IO to set the event and deallocate the Irp.
  2951. //
  2952. Irp->Flags = IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO;
  2953. Irp->RequestorMode = KernelMode;
  2954. Irp->UserIosb = &IoStatus;
  2955. Irp->UserEvent = &Event;
  2956. Irp->Tail.Overlay.OriginalFileObject = FileObject;
  2957. Irp->Tail.Overlay.Thread = PsGetCurrentThread();
  2958. Irp->AssociatedIrp.SystemBuffer = &Buffer;
  2959. //
  2960. // Fill in the normal set file parameters.
  2961. //
  2962. IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
  2963. IrpSp->FileObject = FileObject;
  2964. IrpSp->DeviceObject = DeviceObject;
  2965. IrpSp->Parameters.SetFile.Length = sizeof(FILE_END_OF_FILE_INFORMATION);
  2966. IrpSp->Parameters.SetFile.FileInformationClass = FileEndOfFileInformation;
  2967. //
  2968. // Queue the packet to the appropriate driver based on whether or not there
  2969. // is a VPB associated with the device. This routine should not raise.
  2970. //
  2971. Status = IoCallDriver( DeviceObject, Irp );
  2972. //
  2973. // If pending is returned (which is a successful status),
  2974. // we must wait for the request to complete.
  2975. //
  2976. if (Status == STATUS_PENDING) {
  2977. KeWaitForSingleObject( &Event,
  2978. Executive,
  2979. KernelMode,
  2980. FALSE,
  2981. (PLARGE_INTEGER)NULL);
  2982. }
  2983. //
  2984. // If we got an error back in Status, then the Iosb
  2985. // was not written, so we will just copy the status
  2986. // there, then test the final status after that.
  2987. //
  2988. if (!NT_SUCCESS(Status)) {
  2989. IoStatus.Status = Status;
  2990. }
  2991. //
  2992. // Reset the hard error state.
  2993. //
  2994. IoSetThreadHardErrorMode( HardErrorState );
  2995. return IoStatus.Status;
  2996. }
  2997. VOID
  2998. FsRtlIncrementCcFastReadNotPossible( VOID )
  2999. /*++
  3000. Routine Description:
  3001. This routine increments the CcFastReadNotPossible counter in the PRCB
  3002. Arguments:
  3003. Return Value:
  3004. --*/
  3005. {
  3006. HOT_STATISTIC( CcFastReadNotPossible ) += 1;
  3007. }
  3008. VOID
  3009. FsRtlIncrementCcFastReadWait( VOID )
  3010. /*++
  3011. Routine Description:
  3012. This routine increments the CcFastReadWait counter in the PRCB
  3013. Arguments:
  3014. Return Value:
  3015. --*/
  3016. {
  3017. HOT_STATISTIC(CcFastReadWait) += 1;
  3018. }
  3019. VOID
  3020. FsRtlIncrementCcFastReadNoWait( VOID )
  3021. /*++
  3022. Routine Description:
  3023. This routine increments the CcFastReadNoWait counter in the PRCB
  3024. Arguments:
  3025. Return Value:
  3026. --*/
  3027. {
  3028. HOT_STATISTIC(CcFastReadNoWait) += 1;
  3029. }
  3030. VOID
  3031. FsRtlIncrementCcFastReadResourceMiss( VOID )
  3032. /*++
  3033. Routine Description:
  3034. This routine increments the CcFastReadResourceMiss
  3035. Arguments:
  3036. Return Value:
  3037. --*/
  3038. {
  3039. CcFastReadResourceMiss += 1;
  3040. }