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.

1262 lines
29 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. Flush.c
  5. Abstract:
  6. This module implements the File Flush buffers routine for Fat called by the
  7. dispatch driver.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Gary Kimura [GaryKi] 28-Dec-1989
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "FatProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (FAT_BUG_CHECK_FLUSH)
  19. //
  20. // The local debug trace level
  21. //
  22. #define Dbg (DEBUG_TRACE_FLUSH)
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, FatCommonFlushBuffers)
  25. #pragma alloc_text(PAGE, FatFlushDirectory)
  26. #pragma alloc_text(PAGE, FatFlushFat)
  27. #pragma alloc_text(PAGE, FatFlushFile)
  28. #pragma alloc_text(PAGE, FatFlushVolume)
  29. #pragma alloc_text(PAGE, FatFsdFlushBuffers)
  30. #pragma alloc_text(PAGE, FatFlushDirentForFile)
  31. #pragma alloc_text(PAGE, FatFlushFatEntries)
  32. #pragma alloc_text(PAGE, FatHijackIrpAndFlushDevice)
  33. #endif
  34. //
  35. // Local procedure prototypes
  36. //
  37. NTSTATUS
  38. FatFlushCompletionRoutine (
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN PIRP Irp,
  41. IN PVOID Contxt
  42. );
  43. NTSTATUS
  44. FatHijackCompletionRoutine (
  45. IN PDEVICE_OBJECT DeviceObject,
  46. IN PIRP Irp,
  47. IN PVOID Contxt
  48. );
  49. NTSTATUS
  50. FatFsdFlushBuffers (
  51. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  52. IN PIRP Irp
  53. )
  54. /*++
  55. Routine Description:
  56. This routine implements the FSD part of Flush buffers.
  57. Arguments:
  58. VolumeDeviceObject - Supplies the volume device object where the
  59. file being flushed exists
  60. Irp - Supplies the Irp being processed
  61. Return Value:
  62. NTSTATUS - The FSD status for the IRP
  63. --*/
  64. {
  65. NTSTATUS Status;
  66. PIRP_CONTEXT IrpContext = NULL;
  67. BOOLEAN TopLevel;
  68. PAGED_CODE();
  69. DebugTrace(+1, Dbg, "FatFsdFlushBuffers\n", 0);
  70. //
  71. // Call the common Cleanup routine, with blocking allowed if synchronous
  72. //
  73. FsRtlEnterFileSystem();
  74. TopLevel = FatIsIrpTopLevel( Irp );
  75. try {
  76. IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
  77. Status = FatCommonFlushBuffers( IrpContext, Irp );
  78. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  79. //
  80. // We had some trouble trying to perform the requested
  81. // operation, so we'll abort the I/O request with
  82. // the error status that we get back from the
  83. // execption code
  84. //
  85. Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
  86. }
  87. if (TopLevel) { IoSetTopLevelIrp( NULL ); }
  88. FsRtlExitFileSystem();
  89. //
  90. // And return to our caller
  91. //
  92. DebugTrace(-1, Dbg, "FatFsdFlushBuffers -> %08lx\n", Status);
  93. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  94. return Status;
  95. }
  96. NTSTATUS
  97. FatCommonFlushBuffers (
  98. IN PIRP_CONTEXT IrpContext,
  99. IN PIRP Irp
  100. )
  101. /*++
  102. Routine Description:
  103. This is the common routine for flushing a buffer.
  104. Arguments:
  105. Irp - Supplies the Irp to process
  106. Return Value:
  107. NTSTATUS - The return status for the operation
  108. --*/
  109. {
  110. NTSTATUS Status;
  111. PIO_STACK_LOCATION IrpSp;
  112. PFILE_OBJECT FileObject;
  113. TYPE_OF_OPEN TypeOfOpen;
  114. PVCB Vcb;
  115. PFCB Fcb;
  116. PCCB Ccb;
  117. BOOLEAN VcbAcquired = FALSE;
  118. BOOLEAN FcbAcquired = FALSE;
  119. PDIRENT Dirent;
  120. PBCB DirentBcb = NULL;
  121. PAGED_CODE();
  122. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  123. DebugTrace(+1, Dbg, "FatCommonFlushBuffers\n", 0);
  124. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  125. DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject);
  126. //
  127. // Extract and decode the file object
  128. //
  129. FileObject = IrpSp->FileObject;
  130. TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
  131. //
  132. // CcFlushCache is always synchronous, so if we can't wait enqueue
  133. // the irp to the Fsp.
  134. //
  135. if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) {
  136. Status = FatFsdPostRequest( IrpContext, Irp );
  137. DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status );
  138. return Status;
  139. }
  140. Status = STATUS_SUCCESS;
  141. try {
  142. //
  143. // Case on the type of open that we are trying to flush
  144. //
  145. switch (TypeOfOpen) {
  146. case VirtualVolumeFile:
  147. case EaFile:
  148. case DirectoryFile:
  149. DebugTrace(0, Dbg, "Flush that does nothing\n", 0);
  150. break;
  151. case UserFileOpen:
  152. DebugTrace(0, Dbg, "Flush User File Open\n", 0);
  153. (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
  154. FcbAcquired = TRUE;
  155. FatVerifyFcb( IrpContext, Fcb );
  156. //
  157. // If the file is cached then flush its cache
  158. //
  159. Status = FatFlushFile( IrpContext, Fcb, Flush );
  160. //
  161. // Also update and flush the file's dirent in the parent directory if the
  162. // file flush worked.
  163. //
  164. if (NT_SUCCESS( Status )) {
  165. //
  166. // Insure that we get the filesize to disk correctly. This is
  167. // benign if it was already good.
  168. //
  169. // (why do we need to do this?)
  170. //
  171. SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
  172. FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
  173. //
  174. // Flush the volume file to get any allocation information
  175. // updates to disk.
  176. //
  177. if (FlagOn(Fcb->FcbState, FCB_STATE_FLUSH_FAT)) {
  178. Status = FatFlushFat( IrpContext, Vcb );
  179. ClearFlag(Fcb->FcbState, FCB_STATE_FLUSH_FAT);
  180. }
  181. //
  182. // Set the write through bit so that these modifications
  183. // will be completed with the request.
  184. //
  185. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
  186. }
  187. break;
  188. case UserDirectoryOpen:
  189. //
  190. // If the user had opened the root directory then we'll
  191. // oblige by flushing the volume.
  192. //
  193. if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) {
  194. DebugTrace(0, Dbg, "Flush a directory does nothing\n", 0);
  195. break;
  196. }
  197. case UserVolumeOpen:
  198. DebugTrace(0, Dbg, "Flush User Volume Open, or root dcb\n", 0);
  199. //
  200. // Acquire exclusive access to the Vcb.
  201. //
  202. {
  203. BOOLEAN Finished;
  204. Finished = FatAcquireExclusiveVcb( IrpContext, Vcb );
  205. ASSERT( Finished );
  206. }
  207. VcbAcquired = TRUE;
  208. //
  209. // Mark the volume clean and then flush the volume file,
  210. // and then all directories
  211. //
  212. Status = FatFlushVolume( IrpContext, Vcb, Flush );
  213. //
  214. // If the volume was dirty, do the processing that the delayed
  215. // callback would have done.
  216. //
  217. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) {
  218. //
  219. // Cancel any pending clean volumes.
  220. //
  221. (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
  222. (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
  223. //
  224. // The volume is now clean, note it.
  225. //
  226. if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
  227. FatMarkVolume( IrpContext, Vcb, VolumeClean );
  228. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
  229. }
  230. //
  231. // Unlock the volume if it is removable.
  232. //
  233. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
  234. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
  235. FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
  236. }
  237. }
  238. break;
  239. default:
  240. FatBugCheck( TypeOfOpen, 0, 0 );
  241. }
  242. FatUnpinBcb( IrpContext, DirentBcb );
  243. FatUnpinRepinnedBcbs( IrpContext );
  244. } finally {
  245. DebugUnwind( FatCommonFlushBuffers );
  246. FatUnpinBcb( IrpContext, DirentBcb );
  247. if (VcbAcquired) { FatReleaseVcb( IrpContext, Vcb ); }
  248. if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); }
  249. //
  250. // If this is a normal termination then pass the request on
  251. // to the target device object.
  252. //
  253. if (!AbnormalTermination()) {
  254. NTSTATUS DriverStatus;
  255. PIO_STACK_LOCATION NextIrpSp;
  256. //
  257. // Get the next stack location, and copy over the stack location
  258. //
  259. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  260. *NextIrpSp = *IrpSp;
  261. //
  262. // Set up the completion routine
  263. //
  264. IoSetCompletionRoutine( Irp,
  265. FatFlushCompletionRoutine,
  266. ULongToPtr( Status ),
  267. TRUE,
  268. TRUE,
  269. TRUE );
  270. //
  271. // Send the request.
  272. //
  273. DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp);
  274. Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ?
  275. Status : DriverStatus;
  276. //
  277. // Free the IrpContext and return to the caller.
  278. //
  279. FatCompleteRequest( IrpContext, FatNull, STATUS_SUCCESS );
  280. }
  281. DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status);
  282. }
  283. return Status;
  284. }
  285. NTSTATUS
  286. FatFlushDirectory (
  287. IN PIRP_CONTEXT IrpContext,
  288. IN PDCB Dcb,
  289. IN FAT_FLUSH_TYPE FlushType
  290. )
  291. /*++
  292. Routine Description:
  293. This routine non-recursively flushes a dcb tree.
  294. Arguments:
  295. Dcb - Supplies the Dcb being flushed
  296. FlushType - Specifies the kind of flushing to perform
  297. Return Value:
  298. VOID
  299. --*/
  300. {
  301. PFCB Fcb;
  302. PVCB Vcb;
  303. PFCB NextFcb;
  304. PDIRENT Dirent;
  305. PBCB DirentBcb = NULL;
  306. NTSTATUS Status;
  307. NTSTATUS ReturnStatus = STATUS_SUCCESS;
  308. BOOLEAN ClearWriteThroughOnExit = FALSE;
  309. BOOLEAN ClearWaitOnExit = FALSE;
  310. PAGED_CODE();
  311. ASSERT( FatVcbAcquiredExclusive(IrpContext, Dcb->Vcb) );
  312. DebugTrace(+1, Dbg, "FatFlushDirectory, Dcb = %08lx\n", Dcb);
  313. //
  314. // First flush all the files, then the directories, to make sure all the
  315. // file sizes and times get sets correctly on disk.
  316. //
  317. // We also have to check here if the "Ea Data. Sf" fcb really
  318. // corressponds to an existing file.
  319. //
  320. if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) {
  321. ClearWriteThroughOnExit = TRUE;
  322. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
  323. }
  324. if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
  325. ClearWaitOnExit = TRUE;
  326. SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
  327. }
  328. Vcb = Dcb->Vcb;
  329. Fcb = Dcb;
  330. while (Fcb != NULL) {
  331. NextFcb = FatGetNextFcbTopDown(IrpContext, Fcb, Dcb);
  332. if ( (NodeType( Fcb ) == FAT_NTC_FCB) &&
  333. (Vcb->EaFcb != Fcb) &&
  334. !IsFileDeleted(IrpContext, Fcb)) {
  335. (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
  336. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
  337. //
  338. // Exception handler to catch and commute errors encountered
  339. // doing the flush dance. We may encounter corruption, and
  340. // should continue flushing the volume as much as possible.
  341. //
  342. try {
  343. //
  344. // Standard handler to release resources, etc.
  345. //
  346. try {
  347. //
  348. // Make sure the Fcb is OK.
  349. //
  350. try {
  351. FatVerifyFcb( IrpContext, Fcb );
  352. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  353. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  354. FatResetExceptionState( IrpContext );
  355. }
  356. //
  357. // If this Fcb is not good skip it. Note that a 'continue'
  358. // here would be very expensive as we inside a try{} body.
  359. //
  360. if (Fcb->FcbCondition != FcbGood) {
  361. goto NextFcb;
  362. }
  363. //
  364. // In case a handle was never closed and the FS and AS are more
  365. // than a cluster different, do this truncate.
  366. //
  367. if ( FlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE) ) {
  368. FatTruncateFileAllocation( IrpContext,
  369. Fcb,
  370. Fcb->Header.FileSize.LowPart );
  371. }
  372. //
  373. // Also compare the file's dirent in the parent directory
  374. // with the size information in the Fcb and update
  375. // it if neccessary. Note that we don't mark the Bcb dirty
  376. // because we will be flushing the file object presently, and
  377. // Mm knows what's really dirty.
  378. //
  379. FatGetDirentFromFcbOrDcb( IrpContext,
  380. Fcb,
  381. &Dirent,
  382. &DirentBcb );
  383. if (Dirent->FileSize != Fcb->Header.FileSize.LowPart) {
  384. Dirent->FileSize = Fcb->Header.FileSize.LowPart;
  385. }
  386. //
  387. // We must unpin the Bcb before the flush since we recursively tear up
  388. // the tree if Mm decides that the data section is no longer referenced
  389. // and the final close comes in for this file. If this parent has no
  390. // more children as a result, we will try to initiate teardown on it
  391. // and Cc will deadlock against the active count of this Bcb.
  392. //
  393. FatUnpinBcb( IrpContext, DirentBcb );
  394. //
  395. // Now flush the file. Note that this may make the Fcb
  396. // go away if Mm dereferences its file object.
  397. //
  398. Status = FatFlushFile( IrpContext, Fcb, FlushType );
  399. if (!NT_SUCCESS(Status)) {
  400. ReturnStatus = Status;
  401. }
  402. NextFcb: NOTHING;
  403. } finally {
  404. FatUnpinBcb( IrpContext, DirentBcb );
  405. //
  406. // Since we have the Vcb exclusive we know that if any closes
  407. // come in it is because the CcPurgeCacheSection caused the
  408. // Fcb to go away.
  409. //
  410. if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB) ) {
  411. FatReleaseFcb( (IRPCONTEXT), Fcb );
  412. }
  413. }
  414. } except( (ReturnStatus = FsRtlIsNtstatusExpected(GetExceptionCode())) ?
  415. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  416. FatResetExceptionState( IrpContext );
  417. }
  418. }
  419. Fcb = NextFcb;
  420. }
  421. //
  422. // OK, now flush the directories.
  423. //
  424. Fcb = Dcb;
  425. while (Fcb != NULL) {
  426. NextFcb = FatGetNextFcbTopDown(IrpContext, Fcb, Dcb);
  427. if ( (NodeType( Fcb ) != FAT_NTC_FCB) &&
  428. !IsFileDeleted(IrpContext, Fcb) ) {
  429. //
  430. // Make sure the Fcb is OK.
  431. //
  432. try {
  433. FatVerifyFcb( IrpContext, Fcb );
  434. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  435. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  436. FatResetExceptionState( IrpContext );
  437. }
  438. if (Fcb->FcbCondition == FcbGood) {
  439. Status = FatFlushFile( IrpContext, Fcb, FlushType );
  440. if (!NT_SUCCESS(Status)) {
  441. ReturnStatus = Status;
  442. }
  443. }
  444. }
  445. Fcb = NextFcb;
  446. }
  447. try {
  448. FatUnpinRepinnedBcbs( IrpContext );
  449. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  450. ReturnStatus = IrpContext->ExceptionStatus;
  451. }
  452. if (ClearWriteThroughOnExit) {
  453. ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
  454. }
  455. if (ClearWaitOnExit) {
  456. ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
  457. }
  458. DebugTrace(-1, Dbg, "FatFlushDirectory -> 0x%08lx\n", ReturnStatus);
  459. return ReturnStatus;
  460. }
  461. NTSTATUS
  462. FatFlushFat (
  463. IN PIRP_CONTEXT IrpContext,
  464. IN PVCB Vcb
  465. )
  466. /*++
  467. Routine Description:
  468. The function carefully flushes the entire FAT for a volume. It is
  469. nessecary to dance around a bit because of complicated synchronization
  470. reasons.
  471. Arguments:
  472. Vcb - Supplies the Vcb whose FAT is being flushed
  473. Return Value:
  474. VOID
  475. --*/
  476. {
  477. PBCB Bcb;
  478. PVOID DontCare;
  479. IO_STATUS_BLOCK Iosb;
  480. LARGE_INTEGER Offset;
  481. NTSTATUS ReturnStatus = STATUS_SUCCESS;
  482. PAGED_CODE();
  483. //
  484. // If this volume is write protected, no need to flush.
  485. //
  486. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  487. return STATUS_SUCCESS;
  488. }
  489. //
  490. // Make sure the Vcb is OK.
  491. //
  492. try {
  493. FatVerifyVcb( IrpContext, Vcb );
  494. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  495. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  496. FatResetExceptionState( IrpContext );
  497. }
  498. if (Vcb->VcbCondition != VcbGood) {
  499. return STATUS_FILE_INVALID;
  500. }
  501. //
  502. // The only way we have to correctly synchronize things is to
  503. // repin stuff, and then unpin repin it.
  504. //
  505. // With NT 5.0, we can use some new cache manager support to make
  506. // this a lot more efficient (important for FAT32). Since we're
  507. // only worried about ranges that are dirty - and since we're a
  508. // modified-no-write stream - we can assume that if there is no
  509. // BCB, there is no work to do in the range. I.e., the lazy writer
  510. // beat us to it.
  511. //
  512. // This is much better than reading the entire FAT in and trying
  513. // to punch it out (see the test in the write path to blow
  514. // off writes that don't correspond to dirty ranges of the FAT).
  515. // For FAT32, this would be a *lot* of reading.
  516. //
  517. if (Vcb->AllocationSupport.FatIndexBitSize != 12) {
  518. //
  519. // Walk through the Fat, one page at a time.
  520. //
  521. ULONG NumberOfPages;
  522. ULONG Page;
  523. NumberOfPages = ( FatReservedBytes(&Vcb->Bpb) +
  524. FatBytesPerFat(&Vcb->Bpb) +
  525. (PAGE_SIZE - 1) ) / PAGE_SIZE;
  526. for ( Page = 0, Offset.QuadPart = 0;
  527. Page < NumberOfPages;
  528. Page++, Offset.LowPart += PAGE_SIZE ) {
  529. try {
  530. if (CcPinRead( Vcb->VirtualVolumeFile,
  531. &Offset,
  532. PAGE_SIZE,
  533. PIN_WAIT | PIN_IF_BCB,
  534. &Bcb,
  535. &DontCare )) {
  536. CcSetDirtyPinnedData( Bcb, NULL );
  537. CcRepinBcb( Bcb );
  538. CcUnpinData( Bcb );
  539. CcUnpinRepinnedBcb( Bcb, TRUE, &Iosb );
  540. if (!NT_SUCCESS(Iosb.Status)) {
  541. ReturnStatus = Iosb.Status;
  542. }
  543. }
  544. } except(FatExceptionFilter(IrpContext, GetExceptionInformation())) {
  545. ReturnStatus = IrpContext->ExceptionStatus;
  546. continue;
  547. }
  548. }
  549. } else {
  550. //
  551. // We read in the entire fat in the 12 bit case.
  552. //
  553. Offset.QuadPart = FatReservedBytes( &Vcb->Bpb );
  554. try {
  555. if (CcPinRead( Vcb->VirtualVolumeFile,
  556. &Offset,
  557. FatBytesPerFat( &Vcb->Bpb ),
  558. PIN_WAIT | PIN_IF_BCB,
  559. &Bcb,
  560. &DontCare )) {
  561. CcSetDirtyPinnedData( Bcb, NULL );
  562. CcRepinBcb( Bcb );
  563. CcUnpinData( Bcb );
  564. CcUnpinRepinnedBcb( Bcb, TRUE, &Iosb );
  565. if (!NT_SUCCESS(Iosb.Status)) {
  566. ReturnStatus = Iosb.Status;
  567. }
  568. }
  569. } except(FatExceptionFilter(IrpContext, GetExceptionInformation())) {
  570. ReturnStatus = IrpContext->ExceptionStatus;
  571. }
  572. }
  573. return ReturnStatus;
  574. }
  575. NTSTATUS
  576. FatFlushVolume (
  577. IN PIRP_CONTEXT IrpContext,
  578. IN PVCB Vcb,
  579. IN FAT_FLUSH_TYPE FlushType
  580. )
  581. /*++
  582. Routine Description:
  583. The following routine is used to flush a volume to disk, including the
  584. volume file, and ea file.
  585. Arguments:
  586. Vcb - Supplies the volume being flushed
  587. FlushType - Specifies the kind of flushing to perform
  588. Return Value:
  589. NTSTATUS - The Status from the flush.
  590. --*/
  591. {
  592. NTSTATUS Status;
  593. NTSTATUS ReturnStatus = STATUS_SUCCESS;
  594. PAGED_CODE();
  595. //
  596. // If this volume is write protected, no need to flush.
  597. //
  598. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  599. return STATUS_SUCCESS;
  600. }
  601. //
  602. // Flush all the files and directories.
  603. //
  604. Status = FatFlushDirectory( IrpContext, Vcb->RootDcb, FlushType );
  605. if (!NT_SUCCESS(Status)) {
  606. ReturnStatus = Status;
  607. }
  608. //
  609. // Now Flush the FAT
  610. //
  611. Status = FatFlushFat( IrpContext, Vcb );
  612. if (!NT_SUCCESS(Status)) {
  613. ReturnStatus = Status;
  614. }
  615. //
  616. // Unlock the volume if it is removable.
  617. //
  618. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
  619. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
  620. FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
  621. }
  622. return ReturnStatus;
  623. }
  624. NTSTATUS
  625. FatFlushFile (
  626. IN PIRP_CONTEXT IrpContext,
  627. IN PFCB Fcb,
  628. IN FAT_FLUSH_TYPE FlushType
  629. )
  630. /*++
  631. Routine Description:
  632. This routine simply flushes the data section on a file.
  633. Arguments:
  634. Fcb - Supplies the file being flushed
  635. FlushType - Specifies the kind of flushing to perform
  636. Return Value:
  637. NTSTATUS - The Status from the flush.
  638. --*/
  639. {
  640. IO_STATUS_BLOCK Iosb;
  641. PVCB Vcb = Fcb->Vcb;
  642. PAGED_CODE();
  643. CcFlushCache( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, &Iosb );
  644. if ( !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB )) {
  645. //
  646. // Grab and release PagingIo to serialize ourselves with the lazy writer.
  647. // This will work to ensure that all IO has completed on the cached
  648. // data.
  649. //
  650. // If we are to invalidate the file, now is the right time to do it. Do
  651. // it non-recursively so we don't thump children before their time.
  652. //
  653. ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE);
  654. if (FlushType == FlushAndInvalidate) {
  655. FatMarkFcbCondition( IrpContext, Fcb, FcbBad, FALSE );
  656. }
  657. ExReleaseResourceLite( Fcb->Header.PagingIoResource );
  658. }
  659. return Iosb.Status;
  660. }
  661. NTSTATUS
  662. FatHijackIrpAndFlushDevice (
  663. IN PIRP_CONTEXT IrpContext,
  664. IN PIRP Irp,
  665. IN PDEVICE_OBJECT TargetDeviceObject
  666. )
  667. /*++
  668. Routine Description:
  669. This routine is called when we need to send a flush to a device but
  670. we don't have a flush Irp. What this routine does is make a copy
  671. of its current Irp stack location, but changes the Irp Major code
  672. to a IRP_MJ_FLUSH_BUFFERS amd then send it down, but cut it off at
  673. the knees in the completion routine, fix it up and return to the
  674. user as if nothing had happened.
  675. Arguments:
  676. Irp - The Irp to hijack
  677. TargetDeviceObject - The device to send the request to.
  678. Return Value:
  679. NTSTATUS - The Status from the flush in case anybody cares.
  680. --*/
  681. {
  682. KEVENT Event;
  683. NTSTATUS Status;
  684. PIO_STACK_LOCATION NextIrpSp;
  685. PAGED_CODE();
  686. //
  687. // Get the next stack location, and copy over the stack location
  688. //
  689. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  690. *NextIrpSp = *IoGetCurrentIrpStackLocation( Irp );
  691. NextIrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
  692. NextIrpSp->MinorFunction = 0;
  693. //
  694. // Set up the completion routine
  695. //
  696. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  697. IoSetCompletionRoutine( Irp,
  698. FatHijackCompletionRoutine,
  699. &Event,
  700. TRUE,
  701. TRUE,
  702. TRUE );
  703. //
  704. // Send the request.
  705. //
  706. Status = IoCallDriver( TargetDeviceObject, Irp );
  707. if (Status == STATUS_PENDING) {
  708. KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
  709. Status = Irp->IoStatus.Status;
  710. }
  711. //
  712. // If the driver doesn't support flushes, return SUCCESS.
  713. //
  714. if (Status == STATUS_INVALID_DEVICE_REQUEST) {
  715. Status = STATUS_SUCCESS;
  716. }
  717. Irp->IoStatus.Status = 0;
  718. Irp->IoStatus.Information = 0;
  719. return Status;
  720. }
  721. VOID
  722. FatFlushFatEntries (
  723. IN PIRP_CONTEXT IrpContext,
  724. IN PVCB Vcb,
  725. IN ULONG Cluster,
  726. IN ULONG Count
  727. )
  728. /*++
  729. Routine Description:
  730. This macro flushes the FAT page(s) containing the passed in run.
  731. Arguments:
  732. Vcb - Supplies the volume being flushed
  733. Cluster - The starting cluster
  734. Count - The number of FAT entries in the run
  735. Return Value:
  736. VOID
  737. --*/
  738. {
  739. ULONG ByteCount;
  740. LARGE_INTEGER FileOffset;
  741. IO_STATUS_BLOCK Iosb;
  742. PAGED_CODE();
  743. FileOffset.HighPart = 0;
  744. FileOffset.LowPart = FatReservedBytes( &Vcb->Bpb );
  745. if (Vcb->AllocationSupport.FatIndexBitSize == 12) {
  746. FileOffset.LowPart += Cluster * 3 / 2;
  747. ByteCount = (Count * 3 / 2) + 1;
  748. } else if (Vcb->AllocationSupport.FatIndexBitSize == 32) {
  749. FileOffset.LowPart += Cluster * sizeof(ULONG);
  750. ByteCount = Count * sizeof(ULONG);
  751. } else {
  752. FileOffset.LowPart += Cluster * sizeof( USHORT );
  753. ByteCount = Count * sizeof( USHORT );
  754. }
  755. CcFlushCache( &Vcb->SectionObjectPointers,
  756. &FileOffset,
  757. ByteCount,
  758. &Iosb );
  759. if (NT_SUCCESS(Iosb.Status)) {
  760. Iosb.Status = FatHijackIrpAndFlushDevice( IrpContext,
  761. IrpContext->OriginatingIrp,
  762. Vcb->TargetDeviceObject );
  763. }
  764. if (!NT_SUCCESS(Iosb.Status)) {
  765. FatNormalizeAndRaiseStatus(IrpContext, Iosb.Status);
  766. }
  767. }
  768. VOID
  769. FatFlushDirentForFile (
  770. IN PIRP_CONTEXT IrpContext,
  771. IN PFCB Fcb
  772. )
  773. /*++
  774. Routine Description:
  775. This macro flushes the page containing a file's DIRENT in its parent.
  776. Arguments:
  777. Fcb - Supplies the file whose DIRENT is being flushed
  778. Return Value:
  779. VOID
  780. --*/
  781. {
  782. LARGE_INTEGER FileOffset;
  783. IO_STATUS_BLOCK Iosb;
  784. PAGED_CODE();
  785. FileOffset.QuadPart = Fcb->DirentOffsetWithinDirectory;
  786. CcFlushCache( &Fcb->ParentDcb->NonPaged->SectionObjectPointers,
  787. &FileOffset,
  788. sizeof( DIRENT ),
  789. &Iosb );
  790. if (NT_SUCCESS(Iosb.Status)) {
  791. Iosb.Status = FatHijackIrpAndFlushDevice( IrpContext,
  792. IrpContext->OriginatingIrp,
  793. Fcb->Vcb->TargetDeviceObject );
  794. }
  795. if (!NT_SUCCESS(Iosb.Status)) {
  796. FatNormalizeAndRaiseStatus(IrpContext, Iosb.Status);
  797. }
  798. }
  799. //
  800. // Local support routine
  801. //
  802. NTSTATUS
  803. FatFlushCompletionRoutine (
  804. IN PDEVICE_OBJECT DeviceObject,
  805. IN PIRP Irp,
  806. IN PVOID Contxt
  807. )
  808. {
  809. NTSTATUS Status = (NTSTATUS) (ULONG_PTR) Contxt;
  810. //
  811. // Add the hack-o-ramma to fix formats.
  812. //
  813. if ( Irp->PendingReturned ) {
  814. IoMarkIrpPending( Irp );
  815. }
  816. //
  817. // If the Irp got STATUS_INVALID_DEVICE_REQUEST, normalize it
  818. // to STATUS_SUCCESS.
  819. //
  820. if (Irp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) {
  821. Irp->IoStatus.Status = Status;
  822. }
  823. UNREFERENCED_PARAMETER( DeviceObject );
  824. UNREFERENCED_PARAMETER( Contxt );
  825. return STATUS_SUCCESS;
  826. }
  827. //
  828. // Local support routine
  829. //
  830. NTSTATUS
  831. FatHijackCompletionRoutine (
  832. IN PDEVICE_OBJECT DeviceObject,
  833. IN PIRP Irp,
  834. IN PVOID Contxt
  835. )
  836. {
  837. //
  838. // Set the event so that our call will wake up.
  839. //
  840. KeSetEvent( (PKEVENT)Contxt, 0, FALSE );
  841. UNREFERENCED_PARAMETER( DeviceObject );
  842. UNREFERENCED_PARAMETER( Irp );
  843. return STATUS_MORE_PROCESSING_REQUIRED;
  844. }