Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2451 lines
74 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. Flush.c
  5. Abstract:
  6. This module implements the flush buffers routine for Ntfs called by the
  7. dispatch driver.
  8. Author:
  9. Tom Miller [TomM] 18-Jan-1992
  10. Revision History:
  11. --*/
  12. #include "NtfsProc.h"
  13. //
  14. // The Bug check file id for this module
  15. //
  16. #define BugCheckFileId (NTFS_BUG_CHECK_FLUSH)
  17. //
  18. // The local debug trace level
  19. //
  20. #define Dbg (DEBUG_TRACE_FLUSH)
  21. //
  22. // Macro to attempt to flush a stream from an Scb.
  23. //
  24. #define FlushScb(IRPC,SCB,IOS) { \
  25. (IOS)->Status = NtfsFlushUserStream((IRPC),(SCB),NULL,0); \
  26. NtfsNormalizeAndCleanupTransaction( IRPC, \
  27. &(IOS)->Status, \
  28. TRUE, \
  29. STATUS_UNEXPECTED_IO_ERROR ); \
  30. if (FlagOn((SCB)->ScbState, SCB_STATE_FILE_SIZE_LOADED)) { \
  31. NtfsWriteFileSizes( (IRPC), \
  32. (SCB), \
  33. &(SCB)->Header.ValidDataLength.QuadPart, \
  34. TRUE, \
  35. TRUE, \
  36. TRUE ); \
  37. } \
  38. }
  39. //
  40. // Local procedure prototypes
  41. //
  42. NTSTATUS
  43. NtfsFlushCompletionRoutine(
  44. IN PDEVICE_OBJECT DeviceObject,
  45. IN PIRP Irp,
  46. IN PVOID Contxt
  47. );
  48. NTSTATUS
  49. NtfsFlushFcbFileRecords (
  50. IN PIRP_CONTEXT IrpContext,
  51. IN PFCB Fcb
  52. );
  53. LONG
  54. NtfsFlushVolumeExceptionFilter (
  55. IN PIRP_CONTEXT IrpContext,
  56. IN PEXCEPTION_POINTERS ExceptionPointer,
  57. IN NTSTATUS ExceptionCode
  58. );
  59. #ifdef ALLOC_PRAGMA
  60. #pragma alloc_text(PAGE, NtfsCommonFlushBuffers)
  61. #pragma alloc_text(PAGE, NtfsFlushAndPurgeFcb)
  62. #pragma alloc_text(PAGE, NtfsFlushAndPurgeScb)
  63. #pragma alloc_text(PAGE, NtfsFlushFcbFileRecords)
  64. #pragma alloc_text(PAGE, NtfsFlushLsnStreams)
  65. #pragma alloc_text(PAGE, NtfsFlushVolume)
  66. #pragma alloc_text(PAGE, NtfsFsdFlushBuffers)
  67. #pragma alloc_text(PAGE, NtfsFlushUserStream)
  68. #endif
  69. NTSTATUS
  70. NtfsFsdFlushBuffers (
  71. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  72. IN PIRP Irp
  73. )
  74. /*++
  75. Routine Description:
  76. This routine implements the FSD part of flush buffers.
  77. Arguments:
  78. VolumeDeviceObject - Supplies the volume device object where the
  79. file exists
  80. Irp - Supplies the Irp being processed
  81. Return Value:
  82. NTSTATUS - The FSD status for the IRP
  83. --*/
  84. {
  85. TOP_LEVEL_CONTEXT TopLevelContext;
  86. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  87. NTSTATUS Status = STATUS_SUCCESS;
  88. PIRP_CONTEXT IrpContext = NULL;
  89. ASSERT_IRP( Irp );
  90. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  91. PAGED_CODE();
  92. DebugTrace( +1, Dbg, ("NtfsFsdFlushBuffers\n") );
  93. //
  94. // Call the common flush buffer routine
  95. //
  96. FsRtlEnterFileSystem();
  97. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, FALSE, FALSE );
  98. do {
  99. try {
  100. //
  101. // We are either initiating this request or retrying it.
  102. //
  103. if (IrpContext == NULL) {
  104. //
  105. // Allocate and initialize the Irp.
  106. //
  107. NtfsInitializeIrpContext( Irp, CanFsdWait( Irp ), &IrpContext );
  108. //
  109. // Initialize the thread top level structure, if needed.
  110. //
  111. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  112. } else if (Status == STATUS_LOG_FILE_FULL) {
  113. NtfsCheckpointForLogFileFull( IrpContext );
  114. }
  115. Status = NtfsCommonFlushBuffers( IrpContext, Irp );
  116. break;
  117. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  118. //
  119. // We had some trouble trying to perform the requested
  120. // operation, so we'll abort the I/O request with
  121. // the error status that we get back from the
  122. // execption code
  123. //
  124. Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() );
  125. }
  126. } while (Status == STATUS_CANT_WAIT ||
  127. Status == STATUS_LOG_FILE_FULL);
  128. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  129. FsRtlExitFileSystem();
  130. //
  131. // And return to our caller
  132. //
  133. DebugTrace( -1, Dbg, ("NtfsFsdFlushBuffers -> %08lx\n", Status) );
  134. return Status;
  135. }
  136. NTSTATUS
  137. NtfsCommonFlushBuffers (
  138. IN PIRP_CONTEXT IrpContext,
  139. IN PIRP Irp
  140. )
  141. /*++
  142. Routine Description:
  143. This is the common routine for flush buffers called by both the fsd and fsp
  144. threads.
  145. Arguments:
  146. Irp - Supplies the Irp to process
  147. Return Value:
  148. NTSTATUS - The return status for the operation
  149. --*/
  150. {
  151. NTSTATUS Status;
  152. PIO_STACK_LOCATION IrpSp;
  153. PFILE_OBJECT FileObject;
  154. TYPE_OF_OPEN TypeOfOpen;
  155. PVCB Vcb;
  156. PFCB Fcb;
  157. PSCB Scb;
  158. PCCB Ccb;
  159. PLCB Lcb = NULL;
  160. PSCB ParentScb = NULL;
  161. BOOLEAN VcbAcquired = FALSE;
  162. BOOLEAN ScbAcquired = FALSE;
  163. BOOLEAN ParentScbAcquired = FALSE;
  164. ASSERT_IRP_CONTEXT( IrpContext );
  165. ASSERT_IRP( Irp );
  166. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  167. PAGED_CODE();
  168. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  169. DebugTrace( +1, Dbg, ("NtfsCommonFlushBuffers\n") );
  170. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  171. DebugTrace( 0, Dbg, ("->FileObject = %08lx\n", IrpSp->FileObject) );
  172. //
  173. // Extract and decode the file object
  174. //
  175. FileObject = IrpSp->FileObject;
  176. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  177. //
  178. // abort immediately for non files
  179. //
  180. if (UnopenedFileObject == TypeOfOpen) {
  181. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  182. return STATUS_INVALID_PARAMETER;
  183. }
  184. //
  185. // Nuthin-doing if the volume is mounted read only.
  186. //
  187. if (NtfsIsVolumeReadOnly( Vcb )) {
  188. Status = STATUS_MEDIA_WRITE_PROTECTED;
  189. NtfsCompleteRequest( IrpContext, Irp, Status );
  190. DebugTrace( -1, Dbg, ("NtfsCommonFlushBuffers -> %08lx\n", Status) );
  191. return Status;
  192. }
  193. Status = STATUS_SUCCESS;
  194. try {
  195. //
  196. // Case on the type of open that we are trying to flush
  197. //
  198. switch (TypeOfOpen) {
  199. case UserFileOpen:
  200. DebugTrace( 0, Dbg, ("Flush User File Open\n") );
  201. //
  202. // Acquire the Vcb so we can update the duplicate information as well.
  203. //
  204. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  205. VcbAcquired = TRUE;
  206. //
  207. // While we have the Vcb, let's make sure it's still mounted.
  208. //
  209. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  210. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  211. }
  212. //
  213. // Make sure the data gets out to disk.
  214. //
  215. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  216. //
  217. // Acquire exclusive access to the Scb and enqueue the irp
  218. // if we didn't get access
  219. //
  220. NtfsAcquireExclusiveScb( IrpContext, Scb );
  221. ScbAcquired = TRUE;
  222. //
  223. // Flush the stream and verify there were no errors.
  224. //
  225. FlushScb( IrpContext, Scb, &Irp->IoStatus );
  226. //
  227. // Now commit what we've done so far.
  228. //
  229. NtfsCheckpointCurrentTransaction( IrpContext );
  230. //
  231. // Update the time stamps and file sizes in the Fcb based on
  232. // the state of the File Object.
  233. //
  234. NtfsUpdateScbFromFileObject( IrpContext, FileObject, Scb, TRUE );
  235. //
  236. // If we are to update standard information then do so now.
  237. //
  238. if (FlagOn( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO )) {
  239. NtfsUpdateStandardInformation( IrpContext, Fcb );
  240. }
  241. //
  242. // If this is the system hive there is more work to do. We want to flush
  243. // all of the file records for this file as well as for the parent index
  244. // stream. We also want to flush the parent index stream. Acquire the
  245. // parent stream exclusively now so that the update duplicate call won't
  246. // acquire it shared first.
  247. //
  248. if (FlagOn( Ccb->Flags, CCB_FLAG_SYSTEM_HIVE )) {
  249. //
  250. // Start by acquiring all of the necessary files to avoid deadlocks.
  251. //
  252. if (Ccb->Lcb != NULL) {
  253. ParentScb = Ccb->Lcb->Scb;
  254. if (ParentScb != NULL) {
  255. NtfsAcquireExclusiveScb( IrpContext, ParentScb );
  256. ParentScbAcquired = TRUE;
  257. }
  258. }
  259. }
  260. //
  261. // Update the duplicate information if there are updates to apply.
  262. //
  263. if (FlagOn( Fcb->InfoFlags, FCB_INFO_DUPLICATE_FLAGS )) {
  264. Lcb = Ccb->Lcb;
  265. NtfsPrepareForUpdateDuplicate( IrpContext, Fcb, &Lcb, &ParentScb, TRUE );
  266. NtfsUpdateDuplicateInfo( IrpContext, Fcb, Lcb, ParentScb );
  267. NtfsUpdateLcbDuplicateInfo( Fcb, Lcb );
  268. if (ParentScbAcquired) {
  269. NtfsReleaseScb( IrpContext, ParentScb );
  270. ParentScbAcquired = FALSE;
  271. }
  272. }
  273. //
  274. // Now flush the file records for this stream.
  275. //
  276. if (FlagOn( Ccb->Flags, CCB_FLAG_SYSTEM_HIVE )) {
  277. //
  278. // Flush the file records for this file.
  279. //
  280. Status = NtfsFlushFcbFileRecords( IrpContext, Scb->Fcb );
  281. //
  282. // Now flush the parent index stream.
  283. //
  284. if (NT_SUCCESS(Status) && (ParentScb != NULL)) {
  285. CcFlushCache( &ParentScb->NonpagedScb->SegmentObject, NULL, 0, &Irp->IoStatus );
  286. Status = Irp->IoStatus.Status;
  287. //
  288. // Finish by flushing the file records for the parent out
  289. // to disk.
  290. //
  291. if (NT_SUCCESS( Status )) {
  292. Status = NtfsFlushFcbFileRecords( IrpContext, ParentScb->Fcb );
  293. }
  294. }
  295. }
  296. //
  297. // If our status is still success then flush the log file and
  298. // report any changes.
  299. //
  300. if (NT_SUCCESS( Status )) {
  301. ULONG FilterMatch;
  302. LfsFlushToLsn( Vcb->LogHandle, LiMax );
  303. //
  304. // We only want to do this DirNotify if we updated duplicate
  305. // info and set the ParentScb.
  306. //
  307. if (!FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_FILE_ID ) &&
  308. (Vcb->NotifyCount != 0) &&
  309. FlagOn( Fcb->InfoFlags, FCB_INFO_DUPLICATE_FLAGS )) {
  310. FilterMatch = NtfsBuildDirNotifyFilter( IrpContext, Fcb->InfoFlags );
  311. if (FilterMatch != 0) {
  312. NtfsReportDirNotify( IrpContext,
  313. Fcb->Vcb,
  314. &Ccb->FullFileName,
  315. Ccb->LastFileNameOffset,
  316. NULL,
  317. ((FlagOn( Ccb->Flags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  318. (Ccb->Lcb != NULL) &&
  319. (Ccb->Lcb->Scb->ScbType.Index.NormalizedName.Length != 0)) ?
  320. &Ccb->Lcb->Scb->ScbType.Index.NormalizedName :
  321. NULL),
  322. FilterMatch,
  323. FILE_ACTION_MODIFIED,
  324. ParentScb->Fcb );
  325. }
  326. }
  327. ClearFlag( Fcb->InfoFlags,
  328. FCB_INFO_NOTIFY_FLAGS | FCB_INFO_DUPLICATE_FLAGS );
  329. }
  330. break;
  331. case UserViewIndexOpen:
  332. case UserDirectoryOpen:
  333. //
  334. // If the user had opened the root directory then we'll
  335. // oblige by flushing the volume.
  336. //
  337. if (NodeType(Scb) != NTFS_NTC_SCB_ROOT_INDEX) {
  338. DebugTrace( 0, Dbg, ("Flush a directory does nothing\n") );
  339. break;
  340. }
  341. case UserVolumeOpen:
  342. DebugTrace( 0, Dbg, ("Flush User Volume Open\n") );
  343. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  344. VcbAcquired = TRUE;
  345. //
  346. // While we have the Vcb, let's make sure it's still mounted.
  347. //
  348. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  349. try_return( Status = STATUS_VOLUME_DISMOUNTED );
  350. }
  351. NtfsFlushVolume( IrpContext,
  352. Vcb,
  353. TRUE,
  354. FALSE,
  355. TRUE,
  356. FALSE );
  357. //
  358. // Make sure all of the data written in the flush gets to disk.
  359. //
  360. LfsFlushToLsn( Vcb->LogHandle, LiMax );
  361. break;
  362. case StreamFileOpen:
  363. //
  364. // Nothing to do here.
  365. //
  366. break;
  367. default:
  368. //
  369. // Nothing to do if we have our driver object.
  370. //
  371. break;
  372. }
  373. //
  374. // Abort transaction on error by raising.
  375. //
  376. NtfsCleanupTransaction( IrpContext, Status, FALSE );
  377. try_exit: NOTHING;
  378. } finally {
  379. DebugUnwind( NtfsCommonFlushBuffers );
  380. //
  381. // Release any resources which were acquired.
  382. //
  383. if (ScbAcquired) {
  384. NtfsReleaseScb( IrpContext, Scb );
  385. }
  386. if (ParentScbAcquired) {
  387. NtfsReleaseScb( IrpContext, ParentScb );
  388. }
  389. if (VcbAcquired) {
  390. NtfsReleaseVcb( IrpContext, Vcb );
  391. }
  392. //
  393. // If this is a normal termination then pass the request on
  394. // to the target device object.
  395. //
  396. if (!AbnormalTermination()) {
  397. NTSTATUS DriverStatus;
  398. PIO_STACK_LOCATION NextIrpSp;
  399. //
  400. // Free the IrpContext now before calling the lower driver. Do this
  401. // now in case this fails so that we won't complete the Irp in our
  402. // exception routine after passing it to the lower driver.
  403. //
  404. NtfsCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
  405. ASSERT( Vcb != NULL );
  406. //
  407. // Get the next stack location, and copy over the stack location
  408. //
  409. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  410. *NextIrpSp = *IrpSp;
  411. //
  412. // Set up the completion routine
  413. //
  414. IoSetCompletionRoutine( Irp,
  415. NtfsFlushCompletionRoutine,
  416. NULL,
  417. TRUE,
  418. TRUE,
  419. TRUE );
  420. //
  421. // Send the request.
  422. //
  423. DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp);
  424. Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ?
  425. Status : DriverStatus;
  426. }
  427. DebugTrace( -1, Dbg, ("NtfsCommonFlushBuffers -> %08lx\n", Status) );
  428. }
  429. return Status;
  430. }
  431. NTSTATUS
  432. NtfsFlushVolume (
  433. IN PIRP_CONTEXT IrpContext,
  434. IN PVCB Vcb,
  435. IN BOOLEAN FlushCache,
  436. IN BOOLEAN PurgeFromCache,
  437. IN BOOLEAN ReleaseAllFiles,
  438. IN BOOLEAN MarkFilesForDismount
  439. )
  440. /*++
  441. Routine Description:
  442. This routine non-recursively flushes a volume. This routine will always do
  443. as much of the operation as possible. It will continue until getting a logfile
  444. full. If any of the streams can't be flushed because of corruption then we
  445. will try to flush the others. We will mark the volume dirty in this case.
  446. We will pass the error code back to the caller because they often need to
  447. proceed as best as possible (i.e. shutdown).
  448. Arguments:
  449. Vcb - Supplies the volume to flush
  450. FlushCache - Supplies TRUE if the caller wants to flush the data in the
  451. cache to disk.
  452. PurgeFromCache - Supplies TRUE if the caller wants the data purged from
  453. the Cache (such as for autocheck!)
  454. ReleaseAllFiles - Indicates that our caller would like to release all Fcb's
  455. after TeardownStructures. This will prevent a deadlock when acquiring
  456. paging io resource after a main resource which is held from a previous
  457. teardown.
  458. Return Value:
  459. STATUS_SUCCESS or else the first error status.
  460. --*/
  461. {
  462. NTSTATUS Status = STATUS_SUCCESS;
  463. PFCB Fcb;
  464. PFCB NextFcb;
  465. PSCB Scb;
  466. PSCB NextScb;
  467. IO_STATUS_BLOCK IoStatus;
  468. ULONG Pass;
  469. BOOLEAN UserDataFile;
  470. BOOLEAN RemovedFcb = FALSE;
  471. BOOLEAN DecrementScbCleanup = FALSE;
  472. BOOLEAN DecrementNextFcbClose = FALSE;
  473. BOOLEAN DecrementNextScbCleanup = FALSE;
  474. BOOLEAN AcquiredFcb = FALSE;
  475. BOOLEAN PagingIoAcquired = FALSE;
  476. BOOLEAN ReleaseFiles = FALSE;
  477. LOGICAL MediaRemoved = FALSE;
  478. LONG ReleaseVcbCount = 0;
  479. PAGED_CODE();
  480. DebugTrace( +1, Dbg, ("NtfsFlushVolume, Vcb = %08lx\n", Vcb) );
  481. //
  482. // This operation must be able to wait.
  483. //
  484. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT )) {
  485. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  486. }
  487. //
  488. // Make sure there is nothing on the delayed close queue.
  489. //
  490. NtfsFspClose( Vcb );
  491. //
  492. // Acquire the Vcb exclusive. The Raise condition cannot happen.
  493. //
  494. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  495. ReleaseVcbCount += 1;
  496. try {
  497. //
  498. // We won't do any flushes, but we still have to
  499. // do the dismount/teardown processing.
  500. //
  501. if ((IrpContext->MajorFunction == IRP_MJ_PNP) &&
  502. (IrpContext->MinorFunction == IRP_MN_SURPRISE_REMOVAL)) {
  503. MediaRemoved = TRUE;
  504. }
  505. //
  506. // Don't bother flushing read only volumes
  507. //
  508. if (NtfsIsVolumeReadOnly( Vcb )) {
  509. FlushCache = FALSE;
  510. }
  511. //
  512. // Set the PURGE_IN_PROGRESS flag if this is a purge operation.
  513. //
  514. if (PurgeFromCache) {
  515. SetFlag( Vcb->VcbState, VCB_STATE_VOL_PURGE_IN_PROGRESS);
  516. }
  517. //
  518. // Start by flushing the log file to assure Write-Ahead-Logging.
  519. //
  520. if (!MediaRemoved) {
  521. LfsFlushToLsn( Vcb->LogHandle, LiMax );
  522. }
  523. //
  524. // There will be two passes through the Fcb's for the volume. On the
  525. // first pass we just want to flush/purge the user data streams. On
  526. // the second pass we want to flush the other streams. We hold off on
  527. // several of the system files until after these two passes since they
  528. // may be modified during the flush phases.
  529. //
  530. Pass = 0;
  531. do {
  532. PVOID RestartKey;
  533. //
  534. // Loop through all of the Fcb's in the Fcb table.
  535. //
  536. RestartKey = NULL;
  537. NtfsAcquireFcbTable( IrpContext, Vcb );
  538. NextFcb = Fcb = NtfsGetNextFcbTableEntry( Vcb, &RestartKey );
  539. NtfsReleaseFcbTable( IrpContext, Vcb );
  540. if (NextFcb != NULL) {
  541. InterlockedIncrement( &NextFcb->CloseCount );
  542. DecrementNextFcbClose = TRUE;
  543. }
  544. while (Fcb != NULL) {
  545. //
  546. // Acquire Paging I/O first, since we may be deleting or truncating.
  547. // Testing for the PagingIoResource is not really safe without
  548. // holding the main resource, so we correct for that below.
  549. //
  550. if (Fcb->PagingIoResource != NULL) {
  551. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  552. PagingIoAcquired = TRUE;
  553. }
  554. //
  555. // Let's acquire this Scb exclusively.
  556. //
  557. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  558. AcquiredFcb = TRUE;
  559. //
  560. // We depend on the state of the RemovedFcb flag to tell us that
  561. // we can trust the 'Acquired' booleans above.
  562. //
  563. ASSERT( !RemovedFcb );
  564. //
  565. // If we now do not see a paging I/O resource we are golden,
  566. // othewise we can absolutely release and acquire the resources
  567. // safely in the right order, since a resource in the Fcb is
  568. // not going to go away.
  569. //
  570. if (!PagingIoAcquired && (Fcb->PagingIoResource != NULL)) {
  571. NtfsReleaseFcb( IrpContext, Fcb );
  572. NtfsAcquireExclusivePagingIo( IrpContext, Fcb );
  573. PagingIoAcquired = TRUE;
  574. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  575. }
  576. //
  577. // If this is not one of the special system files then perform
  578. // the flush and purge as requested. Go ahead and test file numbers
  579. // instead of walking through the Scbs in the Vcb just in case they
  580. // have been deleted.
  581. //
  582. if (NtfsSegmentNumber( &Fcb->FileReference ) != MASTER_FILE_TABLE_NUMBER &&
  583. NtfsSegmentNumber( &Fcb->FileReference ) != LOG_FILE_NUMBER &&
  584. NtfsSegmentNumber( &Fcb->FileReference ) != VOLUME_DASD_NUMBER &&
  585. NtfsSegmentNumber( &Fcb->FileReference ) != BIT_MAP_FILE_NUMBER &&
  586. NtfsSegmentNumber( &Fcb->FileReference ) != BOOT_FILE_NUMBER &&
  587. NtfsSegmentNumber( &Fcb->FileReference ) != BAD_CLUSTER_FILE_NUMBER &&
  588. !FlagOn( Fcb->FcbState, FCB_STATE_USN_JOURNAL )) {
  589. //
  590. // We will walk through all of the Scb's for this Fcb. In
  591. // the first pass we will only deal with user data streams.
  592. // In the second pass we will do the others.
  593. //
  594. Scb = NULL;
  595. while (TRUE) {
  596. Scb = NtfsGetNextChildScb( Fcb, Scb );
  597. if (Scb == NULL) { break; }
  598. //
  599. // Reference the Scb to keep it from going away.
  600. //
  601. InterlockedIncrement( &Scb->CleanupCount );
  602. DecrementScbCleanup = TRUE;
  603. //
  604. // Check whether this is a user data file.
  605. //
  606. UserDataFile = FALSE;
  607. if ((NodeType( Scb ) == NTFS_NTC_SCB_DATA) &&
  608. (Scb->AttributeTypeCode == $DATA)) {
  609. UserDataFile = TRUE;
  610. }
  611. //
  612. // Process this Scb in the correct loop.
  613. //
  614. if ((Pass == 0) == (UserDataFile)) {
  615. //
  616. // Initialize the state of the Io to SUCCESS.
  617. //
  618. IoStatus.Status = STATUS_SUCCESS;
  619. //
  620. // Don't put this Scb on the delayed close queue.
  621. //
  622. ClearFlag( Scb->ScbState, SCB_STATE_DELAY_CLOSE );
  623. //
  624. // Flush this stream if it is not already deleted.
  625. // Also don't flush resident streams for system attributes.
  626. //
  627. if (FlushCache &&
  628. !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED ) &&
  629. (!FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT) ||
  630. (Scb->AttributeTypeCode == $DATA))) {
  631. //
  632. // Enclose the flushes with try-except, so that we can
  633. // react to log file full, and in any case keep on truckin.
  634. //
  635. try {
  636. FlushScb( IrpContext, Scb, &IoStatus );
  637. NtfsCheckpointCurrentTransaction( IrpContext );
  638. //
  639. // We will handle all errors except LOG_FILE_FULL and fatal
  640. // bugcheck errors here. In the corruption case we will
  641. // want to mark the volume dirty and continue.
  642. //
  643. } except( NtfsFlushVolumeExceptionFilter( IrpContext,
  644. GetExceptionInformation(),
  645. (IoStatus.Status = GetExceptionCode()) )) {
  646. //
  647. // To make sure that we can access all of our streams correctly,
  648. // we first restore all of the higher sizes before aborting the
  649. // transaction. Then we restore all of the lower sizes after
  650. // the abort, so that all Scbs are finally restored.
  651. //
  652. NtfsRestoreScbSnapshots( IrpContext, TRUE );
  653. NtfsAbortTransaction( IrpContext, IrpContext->Vcb, NULL );
  654. NtfsRestoreScbSnapshots( IrpContext, FALSE );
  655. //
  656. // Clear the top-level exception status so we won't raise
  657. // later.
  658. //
  659. NtfsMinimumExceptionProcessing( IrpContext );
  660. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  661. //
  662. // Remember the first error.
  663. //
  664. if (Status == STATUS_SUCCESS) {
  665. Status = IoStatus.Status;
  666. }
  667. //
  668. // If the current status is either DISK_CORRUPT or FILE_CORRUPT then
  669. // mark the volume dirty. We clear the IoStatus to allow
  670. // a corrupt file to be purged. Otherwise it will never
  671. // leave memory.
  672. //
  673. if ((IoStatus.Status == STATUS_DISK_CORRUPT_ERROR) ||
  674. (IoStatus.Status == STATUS_FILE_CORRUPT_ERROR)) {
  675. NtfsMarkVolumeDirty( IrpContext, Vcb, TRUE );
  676. IoStatus.Status = STATUS_SUCCESS;
  677. }
  678. }
  679. }
  680. //
  681. // Proceed with the purge if there are no failures. We will
  682. // purge if the flush revealed a corrupt file though.
  683. //
  684. if (PurgeFromCache
  685. && IoStatus.Status == STATUS_SUCCESS) {
  686. BOOLEAN DataSectionExists;
  687. BOOLEAN ImageSectionExists;
  688. DataSectionExists = (BOOLEAN)(Scb->NonpagedScb->SegmentObject.DataSectionObject != NULL);
  689. ImageSectionExists = (BOOLEAN)(Scb->NonpagedScb->SegmentObject.ImageSectionObject != NULL);
  690. //
  691. // Since purging the data section can cause the image
  692. // section to go away, we will flush the image section first.
  693. //
  694. if (ImageSectionExists) {
  695. (VOID)MmFlushImageSection( &Scb->NonpagedScb->SegmentObject, MmFlushForWrite );
  696. }
  697. if (DataSectionExists &&
  698. !CcPurgeCacheSection( &Scb->NonpagedScb->SegmentObject,
  699. NULL,
  700. 0,
  701. FALSE ) &&
  702. (Status == STATUS_SUCCESS)) {
  703. Status = STATUS_UNABLE_TO_DELETE_SECTION;
  704. }
  705. }
  706. if (MarkFilesForDismount) {
  707. //
  708. // Set the dismounted flag for this stream so we
  709. // know we have to fail reads & writes to it.
  710. //
  711. SetFlag( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED );
  712. // Also mark the Scb as not allowing fast io --
  713. // this ensures that the file system will get a
  714. // chance to see all reads & writes to this stream.
  715. //
  716. NtfsAcquireFsrtlHeader( Scb );
  717. Scb->Header.IsFastIoPossible = FastIoIsNotPossible;
  718. NtfsReleaseFsrtlHeader( Scb );
  719. }
  720. }
  721. //
  722. // Move to the next Scb.
  723. //
  724. InterlockedDecrement( &Scb->CleanupCount );
  725. DecrementScbCleanup = FALSE;
  726. }
  727. }
  728. //
  729. // If the current Fcb has a USN journal entry and we are forcing a dismount
  730. // then generate the close record.
  731. //
  732. if (MarkFilesForDismount &&
  733. (IoStatus.Status == STATUS_SUCCESS) &&
  734. (NextFcb->FcbUsnRecord != NULL) &&
  735. (NextFcb->FcbUsnRecord->UsnRecord.Reason != 0) &&
  736. (!NtfsIsVolumeReadOnly( Vcb ))) {
  737. //
  738. // Try to post the change but don't fail on an error like DISK_FULL.
  739. //
  740. try {
  741. //
  742. // Now try to actually post the change.
  743. //
  744. NtfsPostUsnChange( IrpContext, Fcb, USN_REASON_CLOSE );
  745. //
  746. // Now write the journal, checkpoint the transaction, and free the UsnJournal to
  747. // reduce contention. We force the write now, because the Fcb may get deleted
  748. // before we normally would write the changes when the transaction commits.
  749. //
  750. NtfsWriteUsnJournalChanges( IrpContext );
  751. NtfsCheckpointCurrentTransaction( IrpContext );
  752. } except( NtfsFlushVolumeExceptionFilter( IrpContext,
  753. GetExceptionInformation(),
  754. (IoStatus.Status = GetExceptionCode()) )) {
  755. NtfsMinimumExceptionProcessing( IrpContext );
  756. IoStatus.Status = STATUS_SUCCESS;
  757. if (IrpContext->TransactionId != 0) {
  758. //
  759. // We couldn't write the commit record, we clean up as
  760. // best we can.
  761. //
  762. NtfsCleanupFailedTransaction( IrpContext );
  763. }
  764. }
  765. }
  766. //
  767. // Remove our reference to the current Fcb.
  768. //
  769. InterlockedDecrement( &NextFcb->CloseCount );
  770. DecrementNextFcbClose = FALSE;
  771. //
  772. // Get the next Fcb and reference it so it won't go away.
  773. //
  774. NtfsAcquireFcbTable( IrpContext, Vcb );
  775. NextFcb = NtfsGetNextFcbTableEntry( Vcb, &RestartKey );
  776. NtfsReleaseFcbTable( IrpContext, Vcb );
  777. if (NextFcb != NULL) {
  778. InterlockedIncrement( &NextFcb->CloseCount );
  779. DecrementNextFcbClose = TRUE;
  780. }
  781. //
  782. // Flushing the volume can cause new file objects to be allocated.
  783. // If we are in the second pass and the Fcb is for a user file
  784. // or directory then try to perform a teardown on this.
  785. //
  786. if ((Pass == 1) &&
  787. !FlagOn(Fcb->FcbState, FCB_STATE_SYSTEM_FILE)) {
  788. ASSERT( IrpContext->TransactionId == 0 );
  789. //
  790. // We can actually get failures in this routine if we need to log standard info.
  791. //
  792. try {
  793. NtfsTeardownStructures( IrpContext,
  794. Fcb,
  795. NULL,
  796. FALSE,
  797. 0,
  798. &RemovedFcb );
  799. //
  800. // TeardownStructures can create a transaction. Commit
  801. // it if present.
  802. //
  803. if (IrpContext->TransactionId != 0) {
  804. NtfsCheckpointCurrentTransaction( IrpContext );
  805. }
  806. } except( NtfsFlushVolumeExceptionFilter( IrpContext,
  807. GetExceptionInformation(),
  808. GetExceptionCode() )) {
  809. NtfsMinimumExceptionProcessing( IrpContext );
  810. if (IrpContext->TransactionId != 0) {
  811. //
  812. // We couldn't write the commit record, we clean up as
  813. // best we can.
  814. //
  815. NtfsCleanupFailedTransaction( IrpContext );
  816. }
  817. }
  818. }
  819. //
  820. // If the Fcb is still around then free any of the the other
  821. // resources we have acquired.
  822. //
  823. if (!RemovedFcb) {
  824. //
  825. // Free the snapshots for the current Fcb. This will keep us
  826. // from having a snapshot for all open attributes in the
  827. // system.
  828. //
  829. NtfsFreeSnapshotsForFcb( IrpContext, Fcb );
  830. if (PagingIoAcquired) {
  831. ASSERT( IrpContext->TransactionId == 0 );
  832. NtfsReleasePagingIo( IrpContext, Fcb );
  833. }
  834. if (AcquiredFcb) {
  835. NtfsReleaseFcb( IrpContext, Fcb );
  836. }
  837. }
  838. //
  839. // If our caller wants to insure that all files are released
  840. // between flushes then walk through the exclusive Fcb list
  841. // and free everything.
  842. //
  843. if (ReleaseAllFiles) {
  844. while (!IsListEmpty( &IrpContext->ExclusiveFcbList )) {
  845. NtfsReleaseFcb( IrpContext,
  846. (PFCB)CONTAINING_RECORD( IrpContext->ExclusiveFcbList.Flink,
  847. FCB,
  848. ExclusiveFcbLinks ));
  849. }
  850. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RELEASE_USN_JRNL |
  851. IRP_CONTEXT_FLAG_RELEASE_MFT );
  852. }
  853. PagingIoAcquired = FALSE;
  854. AcquiredFcb = FALSE;
  855. //
  856. // Always set this back to FALSE to indicate that we can trust the
  857. // 'Acquired' flags above.
  858. //
  859. RemovedFcb = FALSE;
  860. //
  861. // Now move to the next Fcb.
  862. //
  863. Fcb = NextFcb;
  864. }
  865. } while (++Pass < 2);
  866. //
  867. // The root directory is the only fcb with a mixture of user
  868. // streams that should be torn down now and system streams that
  869. // can't be torn down now.
  870. // When we tried to teardown the whole Fcb, we might have run
  871. // into the index root attribute and stopped our teardown, in
  872. // which case we may leave a close count on the Vcb which will
  873. // keep autochk from being able to lock the volume. We need to
  874. // make sure the root directory indeed exists, and this isn't
  875. // the call to flush the volume during mount when we haven't yet
  876. // opened the root directory.
  877. //
  878. if (Vcb->RootIndexScb != NULL) {
  879. Fcb = Vcb->RootIndexScb->Fcb;
  880. //
  881. // Get the first Scb for the root directory Fcb.
  882. //
  883. Scb = NtfsGetNextChildScb( Fcb, NULL );
  884. while (Scb != NULL) {
  885. NextScb = NtfsGetNextChildScb( Fcb, Scb );
  886. if (NextScb != NULL) {
  887. InterlockedIncrement( &NextScb->CleanupCount );
  888. DecrementNextScbCleanup = TRUE;
  889. }
  890. //
  891. // We can actually get failures in this routine if we need to log standard info.
  892. //
  893. try {
  894. if (NtfsIsTypeCodeUserData( Scb->AttributeTypeCode )) {
  895. //
  896. // Notice that we don't bother passing RemovedFcb, since
  897. // the root directory Fcb isn't going to go away.
  898. //
  899. NtfsTeardownStructures( IrpContext,
  900. Scb,
  901. NULL,
  902. FALSE,
  903. 0,
  904. NULL );
  905. }
  906. //
  907. // TeardownStructures can create a transaction. Commit
  908. // it if present.
  909. //
  910. if (IrpContext->TransactionId != 0) {
  911. NtfsCheckpointCurrentTransaction( IrpContext );
  912. }
  913. } except( NtfsFlushVolumeExceptionFilter( IrpContext,
  914. GetExceptionInformation(),
  915. GetExceptionCode() )) {
  916. NtfsMinimumExceptionProcessing( IrpContext );
  917. if (IrpContext->TransactionId != 0) {
  918. //
  919. // We couldn't write the commit record, we clean up as
  920. // best we can.
  921. //
  922. NtfsCleanupFailedTransaction( IrpContext );
  923. }
  924. }
  925. //
  926. // Decrement the cleanup count of the next Scb if we incremented it.
  927. //
  928. if (DecrementNextScbCleanup) {
  929. InterlockedDecrement( &NextScb->CleanupCount );
  930. DecrementNextScbCleanup = FALSE;
  931. }
  932. //
  933. // Move to the next Scb.
  934. //
  935. Scb = NextScb;
  936. }
  937. }
  938. //
  939. // Make sure that all of the delayed or async closes for this Vcb are gone.
  940. //
  941. if (PurgeFromCache) {
  942. NtfsFspClose( Vcb );
  943. }
  944. //
  945. // If we are to mark the files for dismount then do the Volume Dasd file now.
  946. //
  947. if (MarkFilesForDismount) {
  948. NtfsAcquireExclusiveFcb( IrpContext, Vcb->VolumeDasdScb->Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  949. SetFlag( Vcb->VolumeDasdScb->ScbState, SCB_STATE_VOLUME_DISMOUNTED );
  950. NtfsReleaseFcb( IrpContext, Vcb->VolumeDasdScb->Fcb );
  951. }
  952. //
  953. // Now we want to flush/purge the streams for volume bitmap and then the Usn
  954. // journal and Scb.
  955. //
  956. {
  957. PFCB SystemFcbs[3];
  958. PSCB ThisScb;
  959. //
  960. // Store the volume bitmap, usn journal and Mft into the array.
  961. //
  962. RtlZeroMemory( SystemFcbs, sizeof( SystemFcbs ));
  963. if (Vcb->BitmapScb != NULL) {
  964. SystemFcbs[0] = Vcb->BitmapScb->Fcb;
  965. }
  966. if (Vcb->UsnJournal != NULL) {
  967. SystemFcbs[1] = Vcb->UsnJournal->Fcb;
  968. }
  969. if (Vcb->MftScb != NULL) {
  970. SystemFcbs[2] = Vcb->MftScb->Fcb;
  971. }
  972. Pass = 0;
  973. do {
  974. Fcb = SystemFcbs[Pass];
  975. if (Fcb != NULL) {
  976. //
  977. // Purge the Mft cache if we are at the Mft.
  978. //
  979. if (Pass == 2) {
  980. //
  981. // If we are operating on the MFT, make sure we don't have any
  982. // cached maps lying around...
  983. //
  984. NtfsPurgeFileRecordCache( IrpContext );
  985. //
  986. // If we are purging the MFT then acquire all files to
  987. // avoid a purge deadlock. If someone create an MFT mapping
  988. // between the flush and purge then the purge can spin
  989. // indefinitely in CC.
  990. //
  991. if (PurgeFromCache && !ReleaseFiles) {
  992. NtfsAcquireAllFiles( IrpContext, Vcb, TRUE, FALSE, FALSE );
  993. ReleaseFiles = TRUE;
  994. //
  995. // NtfsAcquireAllFiles acquired the Vcb one more time.
  996. //
  997. ReleaseVcbCount += 1;
  998. }
  999. //
  1000. // For the other Fcb's we still need to synchronize the flush and
  1001. // purge so acquire and drop the Fcb.
  1002. //
  1003. } else {
  1004. NextFcb = Fcb;
  1005. InterlockedIncrement( &NextFcb->CloseCount );
  1006. DecrementNextFcbClose = TRUE;
  1007. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  1008. AcquiredFcb = TRUE;
  1009. }
  1010. //
  1011. // Go through each Scb for each of these Fcb's.
  1012. //
  1013. ThisScb = NtfsGetNextChildScb( Fcb, NULL );
  1014. while (ThisScb != NULL) {
  1015. Scb = NtfsGetNextChildScb( Fcb, ThisScb );
  1016. //
  1017. // Initialize the state of the Io to SUCCESS.
  1018. //
  1019. IoStatus.Status = STATUS_SUCCESS;
  1020. //
  1021. // Reference the next Scb to keep it from going away if
  1022. // we purge the current one.
  1023. //
  1024. if (Scb != NULL) {
  1025. InterlockedIncrement( &Scb->CleanupCount );
  1026. DecrementScbCleanup = TRUE;
  1027. }
  1028. if (FlushCache) {
  1029. //
  1030. // Flush the stream. No need to update file sizes because these
  1031. // are all logged streams.
  1032. //
  1033. CcFlushCache( &ThisScb->NonpagedScb->SegmentObject, NULL, 0, &IoStatus );
  1034. if (!NT_SUCCESS( IoStatus.Status )) {
  1035. Status = IoStatus.Status;
  1036. }
  1037. //
  1038. // Use a try-except to commit the current transaction.
  1039. //
  1040. try {
  1041. NtfsCleanupTransaction( IrpContext, IoStatus.Status, TRUE );
  1042. NtfsCheckpointCurrentTransaction( IrpContext );
  1043. //
  1044. // We will handle all errors except LOG_FILE_FULL and fatal
  1045. // bugcheck errors here. In the corruption case we will
  1046. // want to mark the volume dirty and continue.
  1047. //
  1048. } except( NtfsFlushVolumeExceptionFilter( IrpContext,
  1049. GetExceptionInformation(),
  1050. (IoStatus.Status = GetExceptionCode()) )) {
  1051. //
  1052. // To make sure that we can access all of our streams correctly,
  1053. // we first restore all of the higher sizes before aborting the
  1054. // transaction. Then we restore all of the lower sizes after
  1055. // the abort, so that all Scbs are finally restored.
  1056. //
  1057. NtfsRestoreScbSnapshots( IrpContext, TRUE );
  1058. NtfsAbortTransaction( IrpContext, IrpContext->Vcb, NULL );
  1059. NtfsRestoreScbSnapshots( IrpContext, FALSE );
  1060. //
  1061. // Clear the top-level exception status so we won't raise
  1062. // later.
  1063. //
  1064. NtfsMinimumExceptionProcessing( IrpContext );
  1065. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  1066. //
  1067. // Remember the first error.
  1068. //
  1069. if (Status == STATUS_SUCCESS) {
  1070. Status = IoStatus.Status;
  1071. }
  1072. //
  1073. // If the current status is either DISK_CORRUPT or FILE_CORRUPT then
  1074. // mark the volume dirty. We clear the IoStatus to allow
  1075. // a corrupt file to be purged. Otherwise it will never
  1076. // leave memory.
  1077. //
  1078. if ((IoStatus.Status == STATUS_DISK_CORRUPT_ERROR) ||
  1079. (IoStatus.Status == STATUS_FILE_CORRUPT_ERROR)) {
  1080. NtfsMarkVolumeDirty( IrpContext, Vcb, TRUE );
  1081. IoStatus.Status = STATUS_SUCCESS;
  1082. }
  1083. }
  1084. }
  1085. //
  1086. // Purge this stream if there have been no errors.
  1087. //
  1088. if (PurgeFromCache
  1089. && IoStatus.Status == STATUS_SUCCESS) {
  1090. if (!CcPurgeCacheSection( &ThisScb->NonpagedScb->SegmentObject,
  1091. NULL,
  1092. 0,
  1093. FALSE ) &&
  1094. (Status == STATUS_SUCCESS)) {
  1095. Status = STATUS_UNABLE_TO_DELETE_SECTION;
  1096. }
  1097. }
  1098. //
  1099. // Remove any reference we have to the next Scb and move
  1100. // forward to the next Scb.
  1101. //
  1102. if (DecrementScbCleanup) {
  1103. InterlockedDecrement( &Scb->CleanupCount );
  1104. DecrementScbCleanup = FALSE;
  1105. }
  1106. ThisScb = Scb;
  1107. }
  1108. //
  1109. // Purge the Mft cache if we are at the Mft. Do this before and
  1110. // after dealing with the Mft.
  1111. //
  1112. if (Pass == 2) {
  1113. //
  1114. // If we are operating on the MFT, make sure we don't have any
  1115. // cached maps lying around...
  1116. //
  1117. NtfsPurgeFileRecordCache( IrpContext );
  1118. //
  1119. // If we are purging the MFT then acquire all files to
  1120. // avoid a purge deadlock. If someone create an MFT mapping
  1121. // between the flush and purge then the purge can spin
  1122. // indefinitely in CC.
  1123. //
  1124. if (PurgeFromCache && !ReleaseFiles) {
  1125. NtfsAcquireAllFiles( IrpContext, Vcb, TRUE, FALSE, FALSE );
  1126. ReleaseFiles = TRUE;
  1127. //
  1128. // NtfsAcquireAllFiles acquired the Vcb one more time.
  1129. //
  1130. ReleaseVcbCount += 1;
  1131. }
  1132. //
  1133. // Release the volume bitmap and Usn journal.
  1134. //
  1135. } else {
  1136. InterlockedDecrement( &NextFcb->CloseCount );
  1137. DecrementNextFcbClose = FALSE;
  1138. NtfsReleaseFcb( IrpContext, Fcb );
  1139. AcquiredFcb = FALSE;
  1140. }
  1141. }
  1142. Pass += 1;
  1143. } while (Pass != 3);
  1144. //
  1145. // Also flag as dismounted the usnjournal and volume bitmap.
  1146. //
  1147. if (MarkFilesForDismount) {
  1148. if (Vcb->BitmapScb != NULL) {
  1149. NtfsAcquireExclusiveFcb( IrpContext, Vcb->BitmapScb->Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  1150. SetFlag( Vcb->BitmapScb->ScbState, SCB_STATE_VOLUME_DISMOUNTED );
  1151. NtfsReleaseFcb( IrpContext, Vcb->BitmapScb->Fcb );
  1152. }
  1153. if (Vcb->UsnJournal != NULL) {
  1154. NtfsAcquireExclusiveFcb( IrpContext, Vcb->UsnJournal->Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  1155. SetFlag( Vcb->UsnJournal->ScbState, SCB_STATE_VOLUME_DISMOUNTED );
  1156. NtfsReleaseFcb( IrpContext, Vcb->UsnJournal->Fcb );
  1157. }
  1158. }
  1159. }
  1160. } finally {
  1161. //
  1162. // If this is a purge then clear the purge flag.
  1163. //
  1164. if (PurgeFromCache) {
  1165. ClearFlag( Vcb->VcbState, VCB_STATE_VOL_PURGE_IN_PROGRESS );
  1166. }
  1167. //
  1168. // Restore any counts we may have incremented to reference
  1169. // in-memory structures.
  1170. //
  1171. if (DecrementScbCleanup) {
  1172. InterlockedDecrement( &Scb->CleanupCount );
  1173. }
  1174. if (DecrementNextFcbClose) {
  1175. InterlockedDecrement( &NextFcb->CloseCount );
  1176. }
  1177. if (DecrementNextScbCleanup) {
  1178. InterlockedDecrement( &NextScb->CleanupCount );
  1179. }
  1180. //
  1181. // We would've released our resources if we had
  1182. // successfully removed the fcb.
  1183. //
  1184. if (!RemovedFcb) {
  1185. if (PagingIoAcquired) {
  1186. NtfsReleasePagingIo( IrpContext, Fcb );
  1187. }
  1188. if (AcquiredFcb) {
  1189. NtfsReleaseFcb( IrpContext, Fcb );
  1190. }
  1191. }
  1192. if (ReleaseFiles) {
  1193. //
  1194. // NtfsReleaseAllFiles is going to release the Vcb. We'd
  1195. // better have it acquired at least once.
  1196. //
  1197. ASSERT( ReleaseVcbCount >= 1 );
  1198. NtfsReleaseAllFiles( IrpContext, Vcb, FALSE );
  1199. ReleaseVcbCount -= 1;
  1200. }
  1201. //
  1202. // Release the Vcb now. We'd better have the Vcb acquired at least once.
  1203. //
  1204. ASSERTMSG( "Ignore this assert, 96773 is truly fixed",
  1205. (ReleaseVcbCount >= 1) );
  1206. if (ReleaseVcbCount >= 1) {
  1207. NtfsReleaseVcb( IrpContext, Vcb );
  1208. }
  1209. }
  1210. DebugTrace( -1, Dbg, ("NtfsFlushVolume -> %08lx\n", Status) );
  1211. return Status;
  1212. }
  1213. NTSTATUS
  1214. NtfsFlushLsnStreams (
  1215. IN PVCB Vcb
  1216. )
  1217. /*++
  1218. Routine Description:
  1219. This routine non-recursively flushes all of the Lsn streams in the open
  1220. attribute table. It assumes that the files have all been acquired
  1221. exclusive prior to this call. It also assumes our caller will provide the
  1222. synchronization for the open attribute table.
  1223. Arguments:
  1224. Vcb - Supplies the volume to flush
  1225. Return Value:
  1226. STATUS_SUCCESS or else the most recent error status
  1227. --*/
  1228. {
  1229. NTSTATUS Status = STATUS_SUCCESS;
  1230. IO_STATUS_BLOCK IoStatus;
  1231. POPEN_ATTRIBUTE_ENTRY AttributeEntry;
  1232. PSCB Scb;
  1233. PAGED_CODE();
  1234. DebugTrace( +1, Dbg, ("NtfsFlushLsnStreams, Vcb = %08lx\n", Vcb) );
  1235. //
  1236. // Start by flushing the log file to assure Write-Ahead-Logging.
  1237. //
  1238. LfsFlushToLsn( Vcb->LogHandle, LiMax );
  1239. //
  1240. // Loop through to flush all of the streams in the open attribute table.
  1241. // We skip the Mft and mirror so they get flushed last.
  1242. //
  1243. AttributeEntry = NtfsGetFirstRestartTable( &Vcb->OpenAttributeTable );
  1244. while (AttributeEntry != NULL) {
  1245. Scb = AttributeEntry->OatData->Overlay.Scb;
  1246. //
  1247. // Skip the Mft, its mirror and any deleted streams. If the header
  1248. // is uninitialized for this stream then it means that the
  1249. // attribute doesn't exist (INDEX_ALLOCATION where the create failed)
  1250. // or the attribute is now resident. Streams with paging resources
  1251. // (except for the volume bitmap) are skipped to prevent a possible
  1252. // deadlock (normally only seen in the hot fix path -- that's the
  1253. // only time an ordinary user stream ends up in the open attribute
  1254. // table) when this routine acquires the main resource without
  1255. // holding the paging resource. The easiest way to avoid this is
  1256. // to skip such files, since it's user data, not logged metadata,
  1257. // that's going to be flushed anyway, and flushing user data
  1258. // doesn't help a checkpoint at all.
  1259. //
  1260. if (Scb != NULL
  1261. && Scb != Vcb->MftScb
  1262. && Scb != Vcb->Mft2Scb
  1263. && Scb != Vcb->BadClusterFileScb
  1264. && !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )
  1265. && FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )
  1266. && ((Scb == Vcb->BitmapScb) || (Scb->Header.PagingIoResource == NULL))) {
  1267. IoStatus.Status = STATUS_SUCCESS;
  1268. //
  1269. // Now flush the stream. We don't worry about file sizes because
  1270. // any logged stream should have the file size already in the log.
  1271. //
  1272. CcFlushCache( &Scb->NonpagedScb->SegmentObject, NULL, 0, &IoStatus );
  1273. if (!NT_SUCCESS( IoStatus.Status )) {
  1274. Status = IoStatus.Status;
  1275. }
  1276. }
  1277. AttributeEntry = NtfsGetNextRestartTable( &Vcb->OpenAttributeTable,
  1278. AttributeEntry );
  1279. }
  1280. //
  1281. // Now we do the Mft. Flushing the Mft will automatically update the mirror.
  1282. //
  1283. if (Vcb->MftScb != NULL) {
  1284. IoStatus.Status = STATUS_SUCCESS;
  1285. CcFlushCache( &Vcb->MftScb->NonpagedScb->SegmentObject, NULL, 0, &IoStatus );
  1286. if (!NT_SUCCESS( IoStatus.Status )) {
  1287. Status = IoStatus.Status;
  1288. }
  1289. }
  1290. DebugTrace( -1, Dbg, ("NtfsFlushLsnStreams -> %08lx\n", Status) );
  1291. return Status;
  1292. }
  1293. VOID
  1294. NtfsFlushAndPurgeFcb (
  1295. IN PIRP_CONTEXT IrpContext,
  1296. IN PFCB Fcb
  1297. )
  1298. /*++
  1299. Routine Description:
  1300. This routine will flush and purge all of the open streams for an
  1301. Fcb. It is indended to prepare this Fcb such that a teardown will
  1302. remove this Fcb for the tree. The caller has guaranteed that the
  1303. Fcb can't go away.
  1304. Arguments:
  1305. Fcb - Supplies the Fcb to flush
  1306. Return Value:
  1307. None. The caller calls teardown structures and checks the result.
  1308. --*/
  1309. {
  1310. IO_STATUS_BLOCK IoStatus;
  1311. BOOLEAN DecrementNextScbCleanup = FALSE;
  1312. PSCB Scb;
  1313. PSCB NextScb;
  1314. PAGED_CODE();
  1315. //
  1316. // Use a try-finally to facilitate cleanup.
  1317. //
  1318. try {
  1319. //
  1320. // Get the first Scb for the Fcb.
  1321. //
  1322. Scb = NtfsGetNextChildScb( Fcb, NULL );
  1323. while (Scb != NULL) {
  1324. BOOLEAN DataSectionExists;
  1325. BOOLEAN ImageSectionExists;
  1326. NextScb = NtfsGetNextChildScb( Fcb, Scb );
  1327. //
  1328. // Save the attribute list for last so we don't purge it
  1329. // and then bring it back for another attribute.
  1330. //
  1331. if ((Scb->AttributeTypeCode == $ATTRIBUTE_LIST) &&
  1332. (NextScb != NULL)) {
  1333. RemoveEntryList( &Scb->FcbLinks );
  1334. InsertTailList( &Fcb->ScbQueue, &Scb->FcbLinks );
  1335. Scb = NextScb;
  1336. continue;
  1337. }
  1338. if (!FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )) {
  1339. FlushScb( IrpContext, Scb, &IoStatus );
  1340. }
  1341. //
  1342. // The call to purge below may generate a close call.
  1343. // We increment the cleanup count of the next Scb to prevent
  1344. // it from going away in a TearDownStructures as part of that
  1345. // close.
  1346. //
  1347. DataSectionExists = (BOOLEAN)(Scb->NonpagedScb->SegmentObject.DataSectionObject != NULL);
  1348. ImageSectionExists = (BOOLEAN)(Scb->NonpagedScb->SegmentObject.ImageSectionObject != NULL);
  1349. if (NextScb != NULL) {
  1350. InterlockedIncrement( &NextScb->CleanupCount );
  1351. DecrementNextScbCleanup = TRUE;
  1352. }
  1353. if (ImageSectionExists) {
  1354. (VOID)MmFlushImageSection( &Scb->NonpagedScb->SegmentObject, MmFlushForWrite );
  1355. }
  1356. if (DataSectionExists) {
  1357. CcPurgeCacheSection( &Scb->NonpagedScb->SegmentObject,
  1358. NULL,
  1359. 0,
  1360. FALSE );
  1361. }
  1362. //
  1363. // Decrement the cleanup count of the next Scb if we incremented
  1364. // it.
  1365. //
  1366. if (DecrementNextScbCleanup) {
  1367. InterlockedDecrement( &NextScb->CleanupCount );
  1368. DecrementNextScbCleanup = FALSE;
  1369. }
  1370. //
  1371. // Move to the next Scb.
  1372. //
  1373. Scb = NextScb;
  1374. }
  1375. } finally {
  1376. //
  1377. // Restore any counts we may have incremented to reference
  1378. // in-memory structures.
  1379. //
  1380. if (DecrementNextScbCleanup) {
  1381. InterlockedDecrement( &NextScb->CleanupCount );
  1382. }
  1383. }
  1384. return;
  1385. }
  1386. VOID
  1387. NtfsFlushAndPurgeScb (
  1388. IN PIRP_CONTEXT IrpContext,
  1389. IN PSCB Scb,
  1390. IN PSCB ParentScb OPTIONAL
  1391. )
  1392. /*++
  1393. Routine Description:
  1394. This routine is called to flush and purge a stream. It is used
  1395. when there are now only non-cached handles on a file and there is
  1396. a data section. Flushing and purging the data section will mean that
  1397. the user non-cached io won't have to block for the cache coherency calls.
  1398. We want to remove all of the Fcb's from the exclusive list so that the
  1399. lower level flush will be its own transaction. We don't want to drop
  1400. any of the resources however so we acquire the Scb's above explicitly
  1401. and then empty the exclusive list. In all cases we will reacquire the
  1402. Scb's before raising out of this routine.
  1403. Because this routines causes the write out of all data to disk its critical
  1404. that it also updates the filesizes on disk. If NtfsWriteFileSizes raises logfile full
  1405. the caller (create, cleanup etc.) must recall this routine or update the filesizes
  1406. itself. To help with doing this we set the irpcontext state that we attemted a
  1407. flushandpurge. Also note because we purged the section on a retry it may no longer
  1408. be there so a test on (SectionObjectPointer->DataSection != NULL) will miss retrying
  1409. Arguments:
  1410. Scb - Scb for the stream to flush and purge. The reference count on this
  1411. stream will prevent it from going away.
  1412. ParentScb - If specified then this is the parent for the stream being flushed.
  1413. Return Value:
  1414. None.
  1415. --*/
  1416. {
  1417. IO_STATUS_BLOCK Iosb;
  1418. BOOLEAN PurgeResult;
  1419. PAGED_CODE();
  1420. //
  1421. // Only actually flush and purge if there is a data section
  1422. //
  1423. if (Scb->NonpagedScb->SegmentObject.DataSectionObject) {
  1424. //
  1425. // Commit the current transaction.
  1426. //
  1427. NtfsCheckpointCurrentTransaction( IrpContext );
  1428. //
  1429. // Acquire the Scb explicitly. We don't bother to do the same for the
  1430. // parent SCB here; we'll just acquire it on our way out.
  1431. //
  1432. NtfsAcquireResourceExclusive( IrpContext, Scb, TRUE );
  1433. //
  1434. // Walk through and release all of the Fcb's in the Fcb list.
  1435. //
  1436. while (!IsListEmpty( &IrpContext->ExclusiveFcbList )) {
  1437. NtfsReleaseFcb( IrpContext,
  1438. (PFCB)CONTAINING_RECORD( IrpContext->ExclusiveFcbList.Flink,
  1439. FCB,
  1440. ExclusiveFcbLinks ));
  1441. }
  1442. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RELEASE_USN_JRNL |
  1443. IRP_CONTEXT_FLAG_RELEASE_MFT );
  1444. //
  1445. // Use a try-finally to reacquire the Scbs.
  1446. //
  1447. try {
  1448. //
  1449. // Perform the flush, raise on error.
  1450. //
  1451. #ifdef COMPRESS_ON_WIRE
  1452. if (Scb->Header.FileObjectC != NULL) {
  1453. PCOMPRESSION_SYNC CompressionSync = NULL;
  1454. //
  1455. // Use a try-finally to clean up the compression sync.
  1456. //
  1457. try {
  1458. Iosb.Status = NtfsSynchronizeUncompressedIo( Scb,
  1459. NULL,
  1460. 0,
  1461. TRUE,
  1462. &CompressionSync );
  1463. } finally {
  1464. NtfsReleaseCompressionSync( CompressionSync );
  1465. }
  1466. NtfsNormalizeAndCleanupTransaction( IrpContext, &Iosb.Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  1467. }
  1468. #endif
  1469. //
  1470. // After doing the work of the flush we must update the ondisk sizes either
  1471. // here or in close if we fail logfile full
  1472. //
  1473. NtfsPurgeFileRecordCache( IrpContext );
  1474. SetFlag( Scb->ScbState, SCB_STATE_WRITE_FILESIZE_ON_CLOSE );
  1475. CcFlushCache( &Scb->NonpagedScb->SegmentObject, NULL, 0, &Iosb );
  1476. #ifdef SYSCACHE_DEBUG
  1477. if (ScbIsBeingLogged( Scb )) {
  1478. ASSERT( Scb->Fcb->PagingIoResource != NULL );
  1479. ASSERT( NtfsIsExclusiveScbPagingIo( Scb ) );
  1480. FsRtlLogSyscacheEvent( Scb, SCE_CC_FLUSH, 0, 0, 0, Iosb.Status );
  1481. }
  1482. #endif
  1483. NtfsNormalizeAndCleanupTransaction( IrpContext, &Iosb.Status, TRUE, STATUS_UNEXPECTED_IO_ERROR );
  1484. //
  1485. // If no error, then purge the section
  1486. //
  1487. PurgeResult = CcPurgeCacheSection( &Scb->NonpagedScb->SegmentObject, NULL, 0, FALSE );
  1488. #ifdef SYSCACHE_DEBUG
  1489. if (ScbIsBeingLogged( Scb )) {
  1490. ASSERT( (Scb->Fcb->PagingIoResource != NULL) && NtfsIsExclusiveScbPagingIo( Scb ) );
  1491. FsRtlLogSyscacheEvent( Scb, SCE_CC_FLUSH_AND_PURGE, 0, 0, (DWORD_PTR)(Scb->NonpagedScb->SegmentObject.SharedCacheMap), PurgeResult );
  1492. }
  1493. #endif
  1494. } finally {
  1495. //
  1496. // Reacquire the Scb and it's parent..
  1497. //
  1498. NtfsAcquireExclusiveScb( IrpContext, Scb );
  1499. NtfsReleaseResource( IrpContext, Scb );
  1500. if (ARGUMENT_PRESENT( ParentScb )) {
  1501. NtfsAcquireExclusiveScb( IrpContext, ParentScb );
  1502. }
  1503. }
  1504. } // endif DataSection existed
  1505. //
  1506. // Write the file sizes to the attribute. Commit the transaction since the
  1507. // file sizes must get to disk.
  1508. //
  1509. ASSERT( FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED ) );
  1510. NtfsWriteFileSizes( IrpContext, Scb, &Scb->Header.ValidDataLength.QuadPart, TRUE, TRUE, FALSE );
  1511. NtfsCheckpointCurrentTransaction( IrpContext );
  1512. ClearFlag( Scb->ScbState, SCB_STATE_WRITE_FILESIZE_ON_CLOSE );
  1513. return;
  1514. }
  1515. //
  1516. // Local support routine
  1517. //
  1518. NTSTATUS
  1519. NtfsFlushCompletionRoutine(
  1520. IN PDEVICE_OBJECT DeviceObject,
  1521. IN PIRP Irp,
  1522. IN PVOID Contxt
  1523. )
  1524. {
  1525. UNREFERENCED_PARAMETER( DeviceObject );
  1526. UNREFERENCED_PARAMETER( Contxt );
  1527. //
  1528. // Add the hack-o-ramma to fix formats.
  1529. //
  1530. if ( Irp->PendingReturned ) {
  1531. IoMarkIrpPending( Irp );
  1532. }
  1533. //
  1534. // If the Irp got STATUS_INVALID_DEVICE_REQUEST, normalize it
  1535. // to STATUS_SUCCESS.
  1536. //
  1537. if (Irp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) {
  1538. Irp->IoStatus.Status = STATUS_SUCCESS;
  1539. }
  1540. return STATUS_SUCCESS;
  1541. }
  1542. //
  1543. // Local support routine
  1544. //
  1545. NTSTATUS
  1546. NtfsFlushFcbFileRecords (
  1547. IN PIRP_CONTEXT IrpContext,
  1548. IN PFCB Fcb
  1549. )
  1550. /*++
  1551. Routine Description:
  1552. This routine is called to flush the file records for a given file. It is
  1553. intended to flush the critical file records for the system hives.
  1554. Arguments:
  1555. Fcb - This is the Fcb to flush.
  1556. Return Value:
  1557. NTSTATUS - The status returned from the flush operation.
  1558. --*/
  1559. {
  1560. IO_STATUS_BLOCK IoStatus;
  1561. BOOLEAN MoreToGo;
  1562. LONGLONG LastFileOffset = MAXLONGLONG;
  1563. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  1564. PAGED_CODE();
  1565. NtfsInitializeAttributeContext( &AttrContext );
  1566. IoStatus.Status = STATUS_SUCCESS;
  1567. //
  1568. // Use a try-finally to cleanup the context.
  1569. //
  1570. try {
  1571. //
  1572. // Find the first. It should be there.
  1573. //
  1574. MoreToGo = NtfsLookupAttribute( IrpContext,
  1575. Fcb,
  1576. &Fcb->FileReference,
  1577. &AttrContext );
  1578. if (!MoreToGo) {
  1579. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  1580. }
  1581. while (MoreToGo) {
  1582. if (AttrContext.FoundAttribute.MftFileOffset != LastFileOffset) {
  1583. LastFileOffset = AttrContext.FoundAttribute.MftFileOffset;
  1584. CcFlushCache( &Fcb->Vcb->MftScb->NonpagedScb->SegmentObject,
  1585. (PLARGE_INTEGER) &LastFileOffset,
  1586. Fcb->Vcb->BytesPerFileRecordSegment,
  1587. &IoStatus );
  1588. if (!NT_SUCCESS( IoStatus.Status )) {
  1589. IoStatus.Status = FsRtlNormalizeNtstatus( IoStatus.Status,
  1590. STATUS_UNEXPECTED_IO_ERROR );
  1591. break;
  1592. }
  1593. }
  1594. MoreToGo = NtfsLookupNextAttribute( IrpContext,
  1595. Fcb,
  1596. &AttrContext );
  1597. }
  1598. } finally {
  1599. DebugUnwind( NtfsFlushFcbFileRecords );
  1600. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  1601. }
  1602. return IoStatus.Status;
  1603. }
  1604. NTSTATUS
  1605. NtfsFlushUserStream (
  1606. IN PIRP_CONTEXT IrpContext,
  1607. IN PSCB Scb,
  1608. IN PLONGLONG FileOffset OPTIONAL,
  1609. IN ULONG Length
  1610. )
  1611. /*++
  1612. Routine Description:
  1613. This routine flushes a user stream as a top-level action. To do so
  1614. it checkpoints the current transaction first and frees all of the
  1615. caller's snapshots. After doing the flush, it snapshots the input
  1616. Scb again, just in case the caller plans to do any more work on that
  1617. stream. If the caller needs to modify any other streams (presumably
  1618. metadata), it must know to snapshot them itself after calling this
  1619. routine.
  1620. Arguments:
  1621. Scb - Stream to flush
  1622. FileOffset - FileOffset at which the flush is to start, or NULL for
  1623. entire stream.
  1624. Length - Number of bytes to flush. Ignored if FileOffset not specified.
  1625. Return Value:
  1626. Status of the flush
  1627. --*/
  1628. {
  1629. IO_STATUS_BLOCK IoStatus;
  1630. BOOLEAN ScbAcquired = FALSE;
  1631. PAGED_CODE();
  1632. //
  1633. // Checkpoint the current transaction and free all of its snapshots,
  1634. // in order to treat the flush as a top-level action with his own
  1635. // snapshots, etc.
  1636. //
  1637. NtfsCheckpointCurrentTransaction( IrpContext );
  1638. NtfsFreeSnapshotsForFcb( IrpContext, NULL );
  1639. //
  1640. // Set the wait flag in the IrpContext so we don't hit a case where the
  1641. // reacquire below fails because we can't wait. If our caller was asynchronous
  1642. // and we get this far we will continue synchronously.
  1643. //
  1644. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT );
  1645. //
  1646. // We must free the Scb now before calling through MM to prevent
  1647. // collided page deadlocks.
  1648. //
  1649. //
  1650. // We are about to flush the stream. The Scb may be acquired exclusive
  1651. // and, thus, is linked onto the IrpContext or onto one higher
  1652. // up in the IoCallDriver stack. We are about to make a
  1653. // call back into Ntfs which may acquire the Scb exclusive, but
  1654. // NOT put it onto the nested IrpContext exclusive queue which prevents
  1655. // the nested completion from freeing the Scb.
  1656. //
  1657. // This is only a problem for Scb's without a paging resource.
  1658. //
  1659. // We acquire the Scb via ExAcquireResourceExclusiveLite, sidestepping
  1660. // Ntfs bookkeeping, and release it via NtfsReleaseScb.
  1661. //
  1662. ScbAcquired = NtfsIsExclusiveScb( Scb );
  1663. if (ScbAcquired) {
  1664. if (Scb->Header.PagingIoResource == NULL) {
  1665. NtfsAcquireResourceExclusive( IrpContext, Scb, TRUE );
  1666. }
  1667. NtfsReleaseScb( IrpContext, Scb );
  1668. }
  1669. #ifdef COMPRESS_ON_WIRE
  1670. if (Scb->Header.FileObjectC != NULL) {
  1671. PCOMPRESSION_SYNC CompressionSync = NULL;
  1672. //
  1673. // Use a try-finally to clean up the compression sync.
  1674. //
  1675. try {
  1676. NtfsSynchronizeUncompressedIo( Scb,
  1677. NULL,
  1678. 0,
  1679. TRUE,
  1680. &CompressionSync );
  1681. } finally {
  1682. NtfsReleaseCompressionSync( CompressionSync );
  1683. }
  1684. }
  1685. #endif
  1686. //
  1687. // Clear the file record cache before doing the flush. Otherwise FlushVolume may hold this
  1688. // file and be purging the Mft at the same time this thread has a Vacb in the Mft and is
  1689. // trying to reacquire the file in the recursive IO thread.
  1690. //
  1691. NtfsPurgeFileRecordCache( IrpContext );
  1692. //
  1693. // Now do the flush he wanted as a top-level action
  1694. //
  1695. CcFlushCache( &Scb->NonpagedScb->SegmentObject, (PLARGE_INTEGER)FileOffset, Length, &IoStatus );
  1696. //
  1697. // Now reacquire for the caller.
  1698. //
  1699. if (ScbAcquired) {
  1700. NtfsAcquireExclusiveScb( IrpContext, Scb );
  1701. if (Scb->Header.PagingIoResource == NULL) {
  1702. NtfsReleaseResource( IrpContext, Scb );
  1703. }
  1704. }
  1705. return IoStatus.Status;
  1706. }
  1707. //
  1708. // Local support routine
  1709. //
  1710. LONG
  1711. NtfsFlushVolumeExceptionFilter (
  1712. IN PIRP_CONTEXT IrpContext,
  1713. IN PEXCEPTION_POINTERS ExceptionPointer,
  1714. IN NTSTATUS ExceptionCode
  1715. )
  1716. {
  1717. //
  1718. // Swallow any errors except LOG_FILE_FULL, CANT_WAIT and anything else not expected.
  1719. //
  1720. if ((ExceptionCode == STATUS_LOG_FILE_FULL) ||
  1721. (ExceptionCode == STATUS_CANT_WAIT) ||
  1722. !FsRtlIsNtstatusExpected( ExceptionCode )) {
  1723. return EXCEPTION_CONTINUE_SEARCH;
  1724. } else {
  1725. return EXCEPTION_EXECUTE_HANDLER;
  1726. }
  1727. UNREFERENCED_PARAMETER( IrpContext );
  1728. UNREFERENCED_PARAMETER( ExceptionPointer );
  1729. }