Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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