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.

1784 lines
47 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. cache.c
  5. Abstract:
  6. This module implements the cache management routines for the Fat
  7. FSD and FSP, by calling the Common Cache Manager.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Tom Miller [TomM] 26-Jan-1990
  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_CACHESUP)
  19. //
  20. // Local debug trace level
  21. //
  22. #define Dbg (DEBUG_TRACE_CACHESUP)
  23. #if DBG
  24. BOOLEAN
  25. FatIsCurrentOperationSynchedForDcbTeardown (
  26. IN PIRP_CONTEXT IrpContext,
  27. IN PDCB Dcb
  28. );
  29. #endif
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text(PAGE, FatCloseEaFile)
  32. #pragma alloc_text(PAGE, FatCompleteMdl)
  33. #pragma alloc_text(PAGE, FatOpenDirectoryFile)
  34. #pragma alloc_text(PAGE, FatOpenEaFile)
  35. #pragma alloc_text(PAGE, FatPinMappedData)
  36. #pragma alloc_text(PAGE, FatPrepareWriteDirectoryFile)
  37. #pragma alloc_text(PAGE, FatPrepareWriteVolumeFile)
  38. #pragma alloc_text(PAGE, FatReadDirectoryFile)
  39. #pragma alloc_text(PAGE, FatReadVolumeFile)
  40. #pragma alloc_text(PAGE, FatRepinBcb)
  41. #pragma alloc_text(PAGE, FatSyncUninitializeCacheMap)
  42. #pragma alloc_text(PAGE, FatUnpinRepinnedBcbs)
  43. #pragma alloc_text(PAGE, FatZeroData)
  44. #if DBG
  45. #pragma alloc_text(PAGE, FatIsCurrentOperationSynchedForDcbTeardown)
  46. #endif
  47. #endif
  48. VOID
  49. FatReadVolumeFile (
  50. IN PIRP_CONTEXT IrpContext,
  51. IN PVCB Vcb,
  52. IN VBO StartingVbo,
  53. IN ULONG ByteCount,
  54. OUT PBCB *Bcb,
  55. OUT PVOID *Buffer
  56. )
  57. /*++
  58. Routine Description:
  59. This routine is called when the specified range of sectors is to be
  60. read into the cache. In fat, the volume file only contains the boot
  61. sector, reserved sectors, and the "fat(s)." Thus the volume file is
  62. of fixed size and only extends up to (but not not including) the root
  63. directory entry, and will never move or change size.
  64. The fat volume file is also peculiar in that, since it starts at the
  65. logical beginning of the disk, Vbo == Lbo.
  66. Arguments:
  67. Vcb - Pointer to the VCB for the volume
  68. StartingVbo - The virtual offset of the first desired byte
  69. ByteCount - Number of bytes desired
  70. Bcb - Returns a pointer to the BCB which is valid until unpinned
  71. Buffer - Returns a pointer to the sectors, which is valid until unpinned
  72. --*/
  73. {
  74. LARGE_INTEGER Vbo;
  75. PAGED_CODE();
  76. //
  77. // Check to see that all references are within the Bios Parameter Block
  78. // or the fat(s). A special case is made when StartingVbo == 0 at
  79. // mounting time since we do not know how big the fat is.
  80. //
  81. ASSERT( ((StartingVbo == 0) || ((StartingVbo + ByteCount) <= (ULONG)
  82. (FatRootDirectoryLbo( &Vcb->Bpb ) + PAGE_SIZE))));
  83. DebugTrace(+1, Dbg, "FatReadVolumeFile\n", 0);
  84. DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb);
  85. DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo);
  86. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
  87. //
  88. // Call the Cache manager to attempt the transfer.
  89. //
  90. Vbo.QuadPart = StartingVbo;
  91. if (!CcMapData( Vcb->VirtualVolumeFile,
  92. &Vbo,
  93. ByteCount,
  94. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
  95. Bcb,
  96. Buffer )) {
  97. ASSERT( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
  98. //
  99. // Could not read the data without waiting (cache miss).
  100. //
  101. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  102. }
  103. DbgDoit( IrpContext->PinCount += 1 )
  104. DebugTrace(-1, Dbg, "FatReadVolumeFile -> VOID, *BCB = %08lx\n", *Bcb);
  105. return;
  106. }
  107. VOID
  108. FatPrepareWriteVolumeFile (
  109. IN PIRP_CONTEXT IrpContext,
  110. IN PVCB Vcb,
  111. IN VBO StartingVbo,
  112. IN ULONG ByteCount,
  113. OUT PBCB *Bcb,
  114. OUT PVOID *Buffer,
  115. IN BOOLEAN Reversible,
  116. IN BOOLEAN Zero
  117. )
  118. /*++
  119. Routine Description:
  120. This routine first looks to see if the specified range of sectors,
  121. is already in the cache. If so, it increments the BCB PinCount,
  122. sets the BCB dirty, and returns with the location of the sectors.
  123. If the sectors are not in the cache and Wait is TRUE, it finds a
  124. free BCB (potentially causing a flush), and clears out the entire
  125. buffer. Once this is done, it increments the BCB PinCount, sets the
  126. BCB dirty, and returns with the location of the sectors.
  127. If the sectors are not in the cache and Wait is FALSE, this routine
  128. raises STATUS_CANT_WAIT.
  129. Arguments:
  130. Vcb - Pointer to the VCB for the volume
  131. StartingVbo - The virtual offset of the first byte to be written
  132. ByteCount - Number of bytes to be written
  133. Bcb - Returns a pointer to the BCB which is valid until unpinned
  134. Buffer - Returns a pointer to the sectors, which is valid until unpinned
  135. Reversible - Supplies TRUE if the specified range of modification should
  136. be repinned so that the operation can be reversed in a controlled
  137. fashion if errors are encountered.
  138. Zero - Supplies TRUE if the specified range of bytes should be zeroed
  139. --*/
  140. {
  141. LARGE_INTEGER Vbo;
  142. PAGED_CODE();
  143. //
  144. // Check to see that all references are within the Bios Parameter Block
  145. // or the fat(s).
  146. //
  147. ASSERT( ((StartingVbo + ByteCount) <= (ULONG)
  148. (FatRootDirectoryLbo( &Vcb->Bpb ))));
  149. DebugTrace(+1, Dbg, "FatPrepareWriteVolumeFile\n", 0);
  150. DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb);
  151. DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", (ULONG)StartingVbo);
  152. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
  153. DebugTrace( 0, Dbg, "Zero = %08lx\n", Zero);
  154. //
  155. // Call the Cache manager to attempt the transfer.
  156. //
  157. Vbo.QuadPart = StartingVbo;
  158. if (!CcPinRead( Vcb->VirtualVolumeFile,
  159. &Vbo,
  160. ByteCount,
  161. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
  162. Bcb,
  163. Buffer )) {
  164. ASSERT( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
  165. //
  166. // Could not read the data without waiting (cache miss).
  167. //
  168. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  169. }
  170. //
  171. // This keeps the data pinned until we complete the request
  172. // and writes the dirty bit through to the disk.
  173. //
  174. DbgDoit( IrpContext->PinCount += 1 )
  175. try {
  176. if (Zero) {
  177. RtlZeroMemory( *Buffer, ByteCount );
  178. }
  179. FatSetDirtyBcb( IrpContext, *Bcb, Vcb, Reversible );
  180. } finally {
  181. if (AbnormalTermination()) {
  182. FatUnpinBcb(IrpContext, *Bcb);
  183. }
  184. }
  185. DebugTrace(-1, Dbg, "FatPrepareWriteVolumeFile -> VOID, *Bcb = %08lx\n", *Bcb);
  186. return;
  187. }
  188. VOID
  189. FatReadDirectoryFile (
  190. IN PIRP_CONTEXT IrpContext,
  191. IN PDCB Dcb,
  192. IN VBO StartingVbo,
  193. IN ULONG ByteCount,
  194. IN BOOLEAN Pin,
  195. OUT PBCB *Bcb,
  196. OUT PVOID *Buffer,
  197. OUT PNTSTATUS Status
  198. )
  199. /*++
  200. Routine Description:
  201. This routine is called when the specified range of sectors is to be
  202. read into the cache. If the desired range falls beyond the current
  203. cache mapping, the fat will be searched, and if the desired range can
  204. be satisfied, the cache mapping will be extended and the MCB updated
  205. accordingly.
  206. Arguments:
  207. Dcb - Pointer to the DCB for the directory
  208. StartingVbo - The virtual offset of the first desired byte
  209. ByteCount - Number of bytes desired
  210. Pin - Tells us if we should pin instead of just mapping.
  211. Bcb - Returns a pointer to the BCB which is valid until unpinned
  212. Buffer - Returns a pointer to the sectors, which is valid until unpinned
  213. Status - Returns the status of the operation.
  214. --*/
  215. {
  216. LARGE_INTEGER Vbo;
  217. PAGED_CODE();
  218. DebugTrace(+1, Dbg, "FatReadDirectoryFile\n", 0);
  219. DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb);
  220. DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo);
  221. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
  222. //
  223. // Check for the zero case
  224. //
  225. if (ByteCount == 0) {
  226. DebugTrace(0, Dbg, "Nothing to read\n", 0);
  227. *Bcb = NULL;
  228. *Buffer = NULL;
  229. *Status = STATUS_SUCCESS;
  230. DebugTrace(-1, Dbg, "FatReadDirectoryFile -> VOID\n", 0);
  231. return;
  232. }
  233. //
  234. // If we need to create a directory file and initialize the
  235. // cachemap, do so.
  236. //
  237. FatOpenDirectoryFile( IrpContext, Dcb );
  238. //
  239. // Now if the transfer is beyond the allocation size return EOF.
  240. //
  241. if (StartingVbo >= Dcb->Header.AllocationSize.LowPart) {
  242. DebugTrace(0, Dbg, "End of file read for directory\n", 0);
  243. *Bcb = NULL;
  244. *Buffer = NULL;
  245. *Status = STATUS_END_OF_FILE;
  246. DebugTrace(-1, Dbg, "FatReadDirectoryFile -> VOID\n", 0);
  247. return;
  248. }
  249. //
  250. // If the caller is trying to read past the EOF, truncate the
  251. // read.
  252. //
  253. ByteCount = (Dcb->Header.AllocationSize.LowPart - StartingVbo < ByteCount) ?
  254. Dcb->Header.AllocationSize.LowPart - StartingVbo : ByteCount;
  255. ASSERT( ByteCount != 0 );
  256. //
  257. // Call the Cache manager to attempt the transfer.
  258. //
  259. Vbo.QuadPart = StartingVbo;
  260. if (Pin ?
  261. !CcPinRead( Dcb->Specific.Dcb.DirectoryFile,
  262. &Vbo,
  263. ByteCount,
  264. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
  265. Bcb,
  266. Buffer )
  267. :
  268. !CcMapData( Dcb->Specific.Dcb.DirectoryFile,
  269. &Vbo,
  270. ByteCount,
  271. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
  272. Bcb,
  273. Buffer ) ) {
  274. //
  275. // Could not read the data without waiting (cache miss).
  276. //
  277. *Bcb = NULL;
  278. *Buffer = NULL;
  279. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  280. }
  281. DbgDoit( IrpContext->PinCount += 1 )
  282. *Status = STATUS_SUCCESS;
  283. DebugTrace(-1, Dbg, "FatReadDirectoryFile -> VOID, *BCB = %08lx\n", *Bcb);
  284. return;
  285. }
  286. VOID
  287. FatPrepareWriteDirectoryFile (
  288. IN PIRP_CONTEXT IrpContext,
  289. IN PDCB Dcb,
  290. IN VBO StartingVbo,
  291. IN ULONG ByteCount,
  292. OUT PBCB *Bcb,
  293. OUT PVOID *Buffer,
  294. IN BOOLEAN Zero,
  295. IN BOOLEAN Reversible,
  296. OUT PNTSTATUS Status
  297. )
  298. /*++
  299. Routine Description:
  300. This routine first looks to see if the specified range of sectors
  301. is already in the cache. If so, it increments the BCB PinCount,
  302. sets the BCB dirty, and returns TRUE with the location of the sectors.
  303. The IrpContext->Flags .. Wait == TRUE/FALSE actions of this routine are identical to
  304. FatPrepareWriteVolumeFile() above.
  305. Arguments:
  306. Dcb - Pointer to the DCB for the directory
  307. StartingVbo - The virtual offset of the first byte to be written
  308. ByteCount - Number of bytes to be written
  309. Bcb - Returns a pointer to the BCB which is valid until unpinned
  310. Buffer - Returns a pointer to the sectors, which is valid until unpinned
  311. Zero - Supplies TRUE if the specified range of bytes should be zeroed
  312. Reversible - Supplies TRUE if the specified range of modification should
  313. be repinned so that the operation can be reversed in a controlled
  314. fashion if errors are encountered.
  315. Status - Returns the status of the operation.
  316. --*/
  317. {
  318. LARGE_INTEGER Vbo;
  319. ULONG InitialAllocation;
  320. BOOLEAN UnwindWeAllocatedDiskSpace = FALSE;
  321. ULONG ClusterSize;
  322. PVOID LocalBuffer;
  323. PAGED_CODE();
  324. DebugTrace(+1, Dbg, "FatPrepareWriteDirectoryFile\n", 0);
  325. DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb);
  326. DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", (ULONG)StartingVbo);
  327. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
  328. DebugTrace( 0, Dbg, "Zero = %08lx\n", Zero);
  329. *Bcb = NULL;
  330. *Buffer = NULL;
  331. //
  332. // If we need to create a directory file and initialize the
  333. // cachemap, do so.
  334. //
  335. FatOpenDirectoryFile( IrpContext, Dcb );
  336. //
  337. // If the transfer is beyond the allocation size we need to
  338. // extend the directory's allocation. The call to
  339. // AddFileAllocation will raise a condition if
  340. // it runs out of disk space. Note that the root directory
  341. // cannot be extended.
  342. //
  343. Vbo.QuadPart = StartingVbo;
  344. try {
  345. if (StartingVbo + ByteCount > Dcb->Header.AllocationSize.LowPart) {
  346. if (NodeType(Dcb) == FAT_NTC_ROOT_DCB &&
  347. !FatIsFat32(Dcb->Vcb)) {
  348. FatRaiseStatus( IrpContext, STATUS_DISK_FULL );
  349. }
  350. DebugTrace(0, Dbg, "Try extending normal directory\n", 0);
  351. InitialAllocation = Dcb->Header.AllocationSize.LowPart;
  352. FatAddFileAllocation( IrpContext,
  353. Dcb,
  354. Dcb->Specific.Dcb.DirectoryFile,
  355. StartingVbo + ByteCount );
  356. UnwindWeAllocatedDiskSpace = TRUE;
  357. //
  358. // Inform the cache manager of the new allocation
  359. //
  360. Dcb->Header.FileSize.LowPart =
  361. Dcb->Header.AllocationSize.LowPart;
  362. CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile,
  363. (PCC_FILE_SIZES)&Dcb->Header.AllocationSize );
  364. //
  365. // Set up the Bitmap buffer if it is not big enough already
  366. //
  367. FatCheckFreeDirentBitmap( IrpContext, Dcb );
  368. //
  369. // The newly allocated clusters should be zeroed starting at
  370. // the previous allocation size
  371. //
  372. Zero = TRUE;
  373. Vbo.QuadPart = InitialAllocation;
  374. ByteCount = Dcb->Header.AllocationSize.LowPart - InitialAllocation;
  375. }
  376. //
  377. // Call the Cache Manager to attempt the transfer, going one cluster
  378. // at a time to avoid pinning across a page boundary.
  379. //
  380. ClusterSize =
  381. 1 << Dcb->Vcb->AllocationSupport.LogOfBytesPerCluster;
  382. while (ByteCount > 0) {
  383. ULONG BytesToPin;
  384. *Bcb = NULL;
  385. if (ByteCount > ClusterSize) {
  386. BytesToPin = ClusterSize;
  387. } else {
  388. BytesToPin = ByteCount;
  389. }
  390. ASSERT( (Vbo.QuadPart / ClusterSize) ==
  391. (Vbo.QuadPart + BytesToPin - 1)/ClusterSize );
  392. if (!CcPinRead( Dcb->Specific.Dcb.DirectoryFile,
  393. &Vbo,
  394. BytesToPin,
  395. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
  396. Bcb,
  397. &LocalBuffer )) {
  398. //
  399. // Could not read the data without waiting (cache miss).
  400. //
  401. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  402. }
  403. //
  404. // Update our caller with the beginning of their request.
  405. //
  406. if (*Buffer == NULL) {
  407. *Buffer = LocalBuffer;
  408. }
  409. DbgDoit( IrpContext->PinCount += 1 )
  410. if (Zero) {
  411. //
  412. // We set this guy dirty right now so that we can raise CANT_WAIT when
  413. // it needs to be done. It'd be beautiful if we could noop the read IO
  414. // since we know we don't care about it.
  415. //
  416. RtlZeroMemory( LocalBuffer, BytesToPin );
  417. CcSetDirtyPinnedData( *Bcb, NULL );
  418. }
  419. ByteCount -= BytesToPin;
  420. Vbo.QuadPart += BytesToPin;
  421. if (ByteCount > 0) {
  422. FatUnpinBcb( IrpContext, *Bcb );
  423. }
  424. }
  425. //
  426. // This lets us get the data pinned until we complete the request
  427. // and writes the dirty bit through to the disk.
  428. //
  429. FatSetDirtyBcb( IrpContext, *Bcb, Dcb->Vcb, Reversible );
  430. *Status = STATUS_SUCCESS;
  431. } finally {
  432. DebugUnwind( FatPrepareWriteDirectoryFile );
  433. if (AbnormalTermination()) {
  434. //
  435. // These steps are carefully arranged - FatTruncateFileAllocation can raise.
  436. // Make sure we unpin the buffer. If FTFA raises, the effect should be benign.
  437. //
  438. FatUnpinBcb(IrpContext, *Bcb);
  439. if (UnwindWeAllocatedDiskSpace == TRUE) {
  440. //
  441. // Inform the cache manager of the change.
  442. //
  443. FatTruncateFileAllocation( IrpContext, Dcb, InitialAllocation );
  444. Dcb->Header.FileSize.LowPart =
  445. Dcb->Header.AllocationSize.LowPart;
  446. CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile,
  447. (PCC_FILE_SIZES)&Dcb->Header.AllocationSize );
  448. }
  449. }
  450. DebugTrace(-1, Dbg, "FatPrepareWriteDirectoryFile -> (VOID), *Bcb = %08lx\n", *Bcb);
  451. }
  452. return;
  453. }
  454. #if DBG
  455. BOOLEAN FatDisableParentCheck = 0;
  456. BOOLEAN
  457. FatIsCurrentOperationSynchedForDcbTeardown (
  458. IN PIRP_CONTEXT IrpContext,
  459. IN PDCB Dcb
  460. )
  461. {
  462. PIRP Irp = IrpContext->OriginatingIrp;
  463. PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation( Irp ) ;
  464. PFILE_OBJECT FileObject = Stack->FileObject;
  465. PVCB Vcb;
  466. PFCB Fcb;
  467. PCCB Ccb;
  468. PFILE_OBJECT ToCheck[3];
  469. ULONG Index = 0;
  470. PAGED_CODE();
  471. //
  472. // While mounting, we're OK without having to own anything.
  473. //
  474. if (Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  475. Stack->MinorFunction == IRP_MN_MOUNT_VOLUME) {
  476. return TRUE;
  477. }
  478. //
  479. // With the Vcb held, the close path is blocked out.
  480. //
  481. if (ExIsResourceAcquiredSharedLite( &Dcb->Vcb->Resource ) ||
  482. ExIsResourceAcquiredExclusiveLite( &Dcb->Vcb->Resource )) {
  483. return TRUE;
  484. }
  485. //
  486. // Accept this assertion at face value. It comes from GetDirentForFcbOrDcb,
  487. // and is reliable.
  488. //
  489. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_PARENT_BY_CHILD )) {
  490. return TRUE;
  491. }
  492. //
  493. // Determine which fileobjects are around on this operation.
  494. //
  495. if (Stack->MajorFunction == IRP_MJ_SET_INFORMATION &&
  496. Stack->Parameters.SetFile.FileObject) {
  497. ToCheck[Index++] = Stack->Parameters.SetFile.FileObject;
  498. }
  499. if (Stack->FileObject) {
  500. ToCheck[Index++] = Stack->FileObject;
  501. }
  502. ToCheck[Index] = NULL;
  503. //
  504. // If the fileobjects we have are for this dcb or a child of it, we are
  505. // also guaranteed that this dcb isn't going anywhere (even without
  506. // the Vcb).
  507. //
  508. for (Index = 0; ToCheck[Index] != NULL; Index++) {
  509. (VOID) FatDecodeFileObject( ToCheck[Index], &Vcb, &Fcb, &Ccb );
  510. while ( Fcb ) {
  511. if (Fcb == Dcb) {
  512. return TRUE;
  513. }
  514. Fcb = Fcb->ParentDcb;
  515. }
  516. }
  517. return FatDisableParentCheck;
  518. }
  519. #endif // DBG
  520. VOID
  521. FatOpenDirectoryFile (
  522. IN PIRP_CONTEXT IrpContext,
  523. IN PDCB Dcb
  524. )
  525. /*++
  526. Routine Description:
  527. This routine opens a new directory file if one is not already open.
  528. Arguments:
  529. Dcb - Pointer to the DCB for the directory
  530. Return Value:
  531. None.
  532. --*/
  533. {
  534. PAGED_CODE();
  535. DebugTrace(+1, Dbg, "FatOpenDirectoryFile\n", 0);
  536. DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb);
  537. //
  538. // If we don't have some hold on this Dcb (there are several ways), there is nothing
  539. // to prevent child files from closing and tearing this branch of the tree down in the
  540. // midst of our slapping this reference onto it.
  541. //
  542. // I really wish we had a proper Fcb synchronization model (like CDFS/UDFS/NTFS).
  543. //
  544. ASSERT( FatIsCurrentOperationSynchedForDcbTeardown( IrpContext, Dcb ));
  545. //
  546. // If we haven't yet set the correct AllocationSize, do so.
  547. //
  548. if (Dcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
  549. FatLookupFileAllocationSize( IrpContext, Dcb );
  550. Dcb->Header.FileSize.LowPart =
  551. Dcb->Header.AllocationSize.LowPart;
  552. }
  553. //
  554. // Setup the Bitmap buffer if it is not big enough already
  555. //
  556. FatCheckFreeDirentBitmap( IrpContext, Dcb );
  557. //
  558. // Check if we need to create a directory file.
  559. //
  560. // We first do a spot check and then synchronize and check again.
  561. //
  562. if (Dcb->Specific.Dcb.DirectoryFile == NULL) {
  563. PFILE_OBJECT DirectoryFileObject = NULL;
  564. FatAcquireDirectoryFileMutex( Dcb->Vcb );
  565. try {
  566. if (Dcb->Specific.Dcb.DirectoryFile == NULL) {
  567. PDEVICE_OBJECT RealDevice;
  568. //
  569. // Create the special file object for the directory file, and set
  570. // up its pointers back to the Dcb and the section object pointer.
  571. // Note that setting the DirectoryFile pointer in the Dcb has
  572. // to be the last thing done.
  573. //
  574. // Preallocate a close context since we have no Ccb for this object.
  575. //
  576. RealDevice = Dcb->Vcb->CurrentDevice;
  577. DirectoryFileObject = IoCreateStreamFileObject( NULL, RealDevice );
  578. FatPreallocateCloseContext( Dcb->Vcb);
  579. FatSetFileObject( DirectoryFileObject,
  580. DirectoryFile,
  581. Dcb,
  582. NULL );
  583. DirectoryFileObject->SectionObjectPointer = &Dcb->NonPaged->SectionObjectPointers;
  584. DirectoryFileObject->ReadAccess = TRUE;
  585. DirectoryFileObject->WriteAccess = TRUE;
  586. DirectoryFileObject->DeleteAccess = TRUE;
  587. InterlockedIncrement( &Dcb->Specific.Dcb.DirectoryFileOpenCount );
  588. Dcb->Specific.Dcb.DirectoryFile = DirectoryFileObject;
  589. //
  590. // Indicate we're happy with the fileobject now.
  591. //
  592. DirectoryFileObject = NULL;
  593. }
  594. } finally {
  595. FatReleaseDirectoryFileMutex( Dcb->Vcb );
  596. //
  597. // Rip the object up if we couldn't get the close context.
  598. //
  599. if (DirectoryFileObject) {
  600. ObDereferenceObject( DirectoryFileObject );
  601. }
  602. }
  603. }
  604. //
  605. // Finally check if we need to initialize the Cache Map for the
  606. // directory file. The size of the section we are going to map
  607. // the current allocation size for the directory. Note that the
  608. // cache manager will provide syncronization for us.
  609. //
  610. if ( Dcb->Specific.Dcb.DirectoryFile->PrivateCacheMap == NULL ) {
  611. Dcb->Header.ValidDataLength = FatMaxLarge;
  612. Dcb->ValidDataToDisk = MAXULONG;
  613. CcInitializeCacheMap( Dcb->Specific.Dcb.DirectoryFile,
  614. (PCC_FILE_SIZES)&Dcb->Header.AllocationSize,
  615. TRUE,
  616. &FatData.CacheManagerNoOpCallbacks,
  617. Dcb );
  618. }
  619. DebugTrace(-1, Dbg, "FatOpenDirectoryFile -> VOID\n", 0);
  620. return;
  621. }
  622. PFILE_OBJECT
  623. FatOpenEaFile (
  624. IN PIRP_CONTEXT IrpContext,
  625. IN PFCB EaFcb
  626. )
  627. /*++
  628. Routine Description:
  629. This routine opens the Ea file.
  630. Arguments:
  631. EaFcb - Pointer to the Fcb for the Ea file.
  632. Return Value:
  633. Pointer to the new file object.
  634. --*/
  635. {
  636. PFILE_OBJECT EaFileObject = NULL;
  637. PDEVICE_OBJECT RealDevice;
  638. PAGED_CODE();
  639. DebugTrace(+1, Dbg, "FatOpenEaFile\n", 0);
  640. DebugTrace( 0, Dbg, "EaFcb = %08lx\n", EaFcb);
  641. //
  642. // Create the special file object for the ea file, and set
  643. // up its pointers back to the Fcb and the section object pointer
  644. //
  645. RealDevice = EaFcb->Vcb->CurrentDevice;
  646. EaFileObject = IoCreateStreamFileObject( NULL, RealDevice );
  647. try {
  648. FatPreallocateCloseContext( IrpContext->Vcb);
  649. FatSetFileObject( EaFileObject,
  650. EaFile,
  651. EaFcb,
  652. NULL );
  653. EaFileObject->SectionObjectPointer = &EaFcb->NonPaged->SectionObjectPointers;
  654. EaFileObject->ReadAccess = TRUE;
  655. EaFileObject->WriteAccess = TRUE;
  656. //
  657. // Finally check if we need to initialize the Cache Map for the
  658. // ea file. The size of the section we are going to map
  659. // the current allocation size for the Fcb.
  660. //
  661. EaFcb->Header.ValidDataLength = FatMaxLarge;
  662. CcInitializeCacheMap( EaFileObject,
  663. (PCC_FILE_SIZES)&EaFcb->Header.AllocationSize,
  664. TRUE,
  665. &FatData.CacheManagerCallbacks,
  666. EaFcb );
  667. CcSetAdditionalCacheAttributes( EaFileObject, TRUE, TRUE );
  668. } finally {
  669. //
  670. // Drop the fileobject if we're raising. Two cases: couldn't get
  671. // the close context, and it is still an UnopenedFileObject, or
  672. // we lost trying to build the cache map - in which case we're
  673. // OK for the close context if we have to.
  674. //
  675. if (AbnormalTermination()) {
  676. ObDereferenceObject( EaFileObject );
  677. }
  678. }
  679. DebugTrace(-1, Dbg, "FatOpenEaFile -> %08lx\n", EaFileObject);
  680. UNREFERENCED_PARAMETER( IrpContext );
  681. return EaFileObject;
  682. }
  683. VOID
  684. FatCloseEaFile (
  685. IN PIRP_CONTEXT IrpContext,
  686. IN PVCB Vcb,
  687. IN BOOLEAN FlushFirst
  688. )
  689. /*++
  690. Routine Description:
  691. This routine shuts down the ea file. Usually this is required when the volume
  692. begins to leave the system: after verify, dismount, deletion, pnp.
  693. Arguments:
  694. Vcb - the volume to close the ea file on
  695. FlushFirst - whether the file should be flushed
  696. Return Value:
  697. None. As a side effect, the EA fileobject in the Vcb is cleared.
  698. Caller must have the Vcb exclusive.
  699. --*/
  700. {
  701. PFILE_OBJECT EaFileObject = Vcb->VirtualEaFile;
  702. PAGED_CODE();
  703. DebugTrace(+1, Dbg, "FatCloseEaFile\n", 0);
  704. DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb);
  705. ASSERT( FatVcbAcquiredExclusive(IrpContext, Vcb) );
  706. if (EaFileObject != NULL) {
  707. EaFileObject = Vcb->VirtualEaFile;
  708. if (FlushFirst) {
  709. CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL );
  710. }
  711. Vcb->VirtualEaFile = NULL;
  712. //
  713. // Empty the Mcb for the Ea file.
  714. //
  715. FatRemoveMcbEntry( Vcb, &Vcb->EaFcb->Mcb, 0, 0xFFFFFFFF );
  716. //
  717. // Set the file object type to unopened file object
  718. // and dereference it.
  719. //
  720. FatSetFileObject( EaFileObject,
  721. UnopenedFileObject,
  722. NULL,
  723. NULL );
  724. FatSyncUninitializeCacheMap( IrpContext, EaFileObject );
  725. ObDereferenceObject( EaFileObject );
  726. ExFreePool( FatAllocateCloseContext( Vcb));
  727. }
  728. DebugTrace(-1, Dbg, "FatCloseEaFile -> %08lx\n", EaFileObject);
  729. }
  730. VOID
  731. FatSetDirtyBcb (
  732. IN PIRP_CONTEXT IrpContext,
  733. IN PBCB Bcb,
  734. IN PVCB Vcb OPTIONAL,
  735. IN BOOLEAN Reversible
  736. )
  737. /*++
  738. Routine Description:
  739. This routine saves a reference to the bcb in the irp context and
  740. sets the bcb dirty. This will have the affect of keeping the page in
  741. memory until we complete the request
  742. In addition, a DPC is set to fire in 5 seconds (or if one is pending,
  743. pushed back 5 seconds) to mark the volume clean.
  744. Arguments:
  745. Bcb - Supplies the Bcb being set dirty
  746. Vcb - Supplies the volume being marked dirty
  747. Reversible - Supplies TRUE if the specified range of bcb should be repinned
  748. so that the changes can be reversed in a controlled fashion if errors
  749. are encountered.
  750. Return Value:
  751. None.
  752. --*/
  753. {
  754. DebugTrace(+1, Dbg, "FatSetDirtyBcb\n", 0 );
  755. DebugTrace( 0, Dbg, "IrpContext = %08lx\n", IrpContext );
  756. DebugTrace( 0, Dbg, "Bcb = %08lx\n", Bcb );
  757. DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
  758. //
  759. // Repin the bcb as required
  760. //
  761. if (Reversible) {
  762. FatRepinBcb( IrpContext, Bcb );
  763. }
  764. //
  765. // Set the bcb dirty
  766. //
  767. CcSetDirtyPinnedData( Bcb, NULL );
  768. //
  769. // If volume dirtying isn't disabled for this operation (for
  770. // instance, when we're changing the dirty state), set the
  771. // volume dirty if we were given a Vcb that we want to perform
  772. // clean volume processing on, and return.
  773. //
  774. // As a historical note, we used to key off of the old floppy
  775. // (now deferred flush) bit to disable dirtying behavior. Since
  776. // hotpluggable media can still be yanked while operations are
  777. // in flight, recognize that its really the case that FAT12
  778. // doesn't have the dirty bit.
  779. //
  780. if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_DIRTY) &&
  781. ARGUMENT_PRESENT(Vcb) &&
  782. !FatIsFat12(Vcb)) {
  783. KIRQL SavedIrql;
  784. BOOLEAN SetTimer;
  785. LARGE_INTEGER TimeSincePreviousCall;
  786. LARGE_INTEGER CurrentTime;
  787. //
  788. // "Borrow" the irp context spinlock.
  789. //
  790. KeQuerySystemTime( &CurrentTime );
  791. KeAcquireSpinLock( &FatData.GeneralSpinLock, &SavedIrql );
  792. TimeSincePreviousCall.QuadPart =
  793. CurrentTime.QuadPart - Vcb->LastFatMarkVolumeDirtyCall.QuadPart;
  794. //
  795. // If more than one second has elapsed since the prior call
  796. // to here, bump the timer up again and see if we need to
  797. // physically mark the volume dirty.
  798. //
  799. if ( (TimeSincePreviousCall.HighPart != 0) ||
  800. (TimeSincePreviousCall.LowPart > (1000 * 1000 * 10)) ) {
  801. SetTimer = TRUE;
  802. } else {
  803. SetTimer = FALSE;
  804. }
  805. KeReleaseSpinLock( &FatData.GeneralSpinLock, SavedIrql );
  806. if ( SetTimer ) {
  807. LARGE_INTEGER CleanVolumeTimer;
  808. //
  809. // We use a shorter volume clean timer for hot plug volumes.
  810. //
  811. CleanVolumeTimer.QuadPart = FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH)
  812. ? (LONG)-1500*1000*10
  813. : (LONG)-8*1000*1000*10;
  814. (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
  815. (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
  816. //
  817. // We have now synchronized with anybody clearing the dirty
  818. // flag, so we can now see if we really have to actually write
  819. // out the physical bit.
  820. //
  821. if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY) ) {
  822. //
  823. // We want to really mark the volume dirty now.
  824. //
  825. if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
  826. FatMarkVolume( IrpContext, Vcb, VolumeDirty );
  827. }
  828. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
  829. //
  830. // Lock the volume if it is removable.
  831. //
  832. if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) {
  833. FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE );
  834. }
  835. }
  836. KeAcquireSpinLock( &FatData.GeneralSpinLock, &SavedIrql );
  837. KeQuerySystemTime( &Vcb->LastFatMarkVolumeDirtyCall );
  838. KeReleaseSpinLock( &FatData.GeneralSpinLock, SavedIrql );
  839. KeSetTimer( &Vcb->CleanVolumeTimer,
  840. CleanVolumeTimer,
  841. &Vcb->CleanVolumeDpc );
  842. }
  843. }
  844. DebugTrace(-1, Dbg, "FatSetDirtyBcb -> VOID\n", 0 );
  845. }
  846. VOID
  847. FatRepinBcb (
  848. IN PIRP_CONTEXT IrpContext,
  849. IN PBCB Bcb
  850. )
  851. /*++
  852. Routine Description:
  853. This routine saves a reference to the bcb in the irp context. This will
  854. have the affect of keeping the page in memory until we complete the
  855. request
  856. Arguments:
  857. Bcb - Supplies the Bcb being referenced
  858. Return Value:
  859. None.
  860. --*/
  861. {
  862. PREPINNED_BCBS Repinned;
  863. ULONG i;
  864. PAGED_CODE();
  865. DebugTrace(+1, Dbg, "FatRepinBcb\n", 0 );
  866. DebugTrace( 0, Dbg, "IrpContext = %08lx\n", IrpContext );
  867. DebugTrace( 0, Dbg, "Bcb = %08lx\n", Bcb );
  868. //
  869. // The algorithm is to search the list of repinned records until
  870. // we either find a match for the bcb or we find a null slot.
  871. //
  872. Repinned = &IrpContext->Repinned;
  873. while (TRUE) {
  874. //
  875. // For every entry in the repinned record check if the bcb's
  876. // match or if the entry is null. If the bcb's match then
  877. // we've done because we've already repinned this bcb, if
  878. // the entry is null then we know, because it's densely packed,
  879. // that the bcb is not in the list so add it to the repinned
  880. // record and repin it.
  881. //
  882. for (i = 0; i < REPINNED_BCBS_ARRAY_SIZE; i += 1) {
  883. if (Repinned->Bcb[i] == Bcb) {
  884. DebugTrace(-1, Dbg, "FatRepinBcb -> VOID\n", 0 );
  885. return;
  886. }
  887. if (Repinned->Bcb[i] == NULL) {
  888. Repinned->Bcb[i] = Bcb;
  889. CcRepinBcb( Bcb );
  890. DebugTrace(-1, Dbg, "FatRepinBcb -> VOID\n", 0 );
  891. return;
  892. }
  893. }
  894. //
  895. // We finished checking one repinned record so now locate the next
  896. // repinned record, If there isn't one then allocate and zero out
  897. // a new one.
  898. //
  899. if (Repinned->Next == NULL) {
  900. Repinned->Next = FsRtlAllocatePoolWithTag( PagedPool,
  901. sizeof(REPINNED_BCBS),
  902. TAG_REPINNED_BCB );
  903. RtlZeroMemory( Repinned->Next, sizeof(REPINNED_BCBS) );
  904. }
  905. Repinned = Repinned->Next;
  906. }
  907. }
  908. VOID
  909. FatUnpinRepinnedBcbs (
  910. IN PIRP_CONTEXT IrpContext
  911. )
  912. /*++
  913. Routine Description:
  914. This routine frees all of the repinned bcbs, stored in an IRP context.
  915. Arguments:
  916. Return Value:
  917. None.
  918. --*/
  919. {
  920. IO_STATUS_BLOCK RaiseIosb;
  921. PREPINNED_BCBS Repinned;
  922. BOOLEAN WriteThroughToDisk;
  923. PFILE_OBJECT FileObject = NULL;
  924. BOOLEAN ForceVerify = FALSE;
  925. ULONG i;
  926. PAGED_CODE();
  927. DebugTrace(+1, Dbg, "FatUnpinRepinnedBcbs\n", 0 );
  928. DebugTrace( 0, Dbg, "IrpContext = %08lx\n", IrpContext );
  929. //
  930. // The algorithm for this procedure is to scan the entire list of
  931. // repinned records unpinning any repinned bcbs. We start off
  932. // with the first record in the irp context, and while there is a
  933. // record to scan we do the following loop.
  934. //
  935. Repinned = &IrpContext->Repinned;
  936. RaiseIosb.Status = STATUS_SUCCESS;
  937. //
  938. // If the request is write through or the media is deferred flush,
  939. // unpin the bcb's write through.
  940. //
  941. WriteThroughToDisk = (BOOLEAN) (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH) &&
  942. IrpContext->Vcb != NULL &&
  943. (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH) ||
  944. FlagOn(IrpContext->Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH)));
  945. while (Repinned != NULL) {
  946. //
  947. // For every non-null entry in the repinned record unpin the
  948. // repinned entry.
  949. //
  950. // If the this is removable media (therefore all requests write-
  951. // through) and the write fails, purge the cache so that we throw
  952. // away the modifications as we will be returning an error to the
  953. // user.
  954. //
  955. for (i = 0; i < REPINNED_BCBS_ARRAY_SIZE; i += 1) {
  956. if (Repinned->Bcb[i] != NULL) {
  957. IO_STATUS_BLOCK Iosb;
  958. if (WriteThroughToDisk &&
  959. FlagOn(IrpContext->Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH)) {
  960. FileObject = CcGetFileObjectFromBcb( Repinned->Bcb[i] );
  961. }
  962. CcUnpinRepinnedBcb( Repinned->Bcb[i],
  963. WriteThroughToDisk,
  964. &Iosb );
  965. if ( !NT_SUCCESS(Iosb.Status) ) {
  966. if (RaiseIosb.Status == STATUS_SUCCESS) {
  967. RaiseIosb = Iosb;
  968. }
  969. //
  970. // If this was a writethrough device, purge the cache,
  971. // except for Irp major codes that either don't handle
  972. // the error paths correctly or are simple victims like
  973. // cleanup.c.
  974. //
  975. if (FileObject &&
  976. (IrpContext->MajorFunction != IRP_MJ_CLEANUP) &&
  977. (IrpContext->MajorFunction != IRP_MJ_FLUSH_BUFFERS) &&
  978. (IrpContext->MajorFunction != IRP_MJ_SET_INFORMATION)) {
  979. //
  980. // The call to CcPurgeCacheSection() below will
  981. // purge the entire file from memory. It will also
  982. // block until all the file's BCB's are pinned.
  983. //
  984. // We end up in a deadlock situation of there
  985. // are any other pinned BCB's in this IRP context
  986. // so the first thing we do is search the list
  987. // for BCB's pinned in the same file and unpin
  988. // them.
  989. //
  990. // We are probably not going to lose data because
  991. // it's safe to assume that all flushes will
  992. // fail after the first one fails.
  993. //
  994. ULONG j;
  995. for (j = i + 1; j < REPINNED_BCBS_ARRAY_SIZE; j++) {
  996. if (Repinned->Bcb[j] != NULL) {
  997. if (CcGetFileObjectFromBcb( Repinned->Bcb[j] ) == FileObject) {
  998. CcUnpinRepinnedBcb( Repinned->Bcb[j],
  999. FALSE,
  1000. &Iosb );
  1001. Repinned->Bcb[j] = NULL;
  1002. }
  1003. }
  1004. }
  1005. CcPurgeCacheSection( FileObject->SectionObjectPointer,
  1006. NULL,
  1007. 0,
  1008. FALSE );
  1009. //
  1010. // Force a verify operation here since who knows
  1011. // what state things are in.
  1012. //
  1013. ForceVerify = TRUE;
  1014. }
  1015. }
  1016. Repinned->Bcb[i] = NULL;
  1017. }
  1018. }
  1019. //
  1020. // Now find the next repinned record in the list, and possibly
  1021. // delete the one we've just processed.
  1022. //
  1023. if (Repinned != &IrpContext->Repinned) {
  1024. PREPINNED_BCBS Saved;
  1025. Saved = Repinned->Next;
  1026. ExFreePool( Repinned );
  1027. Repinned = Saved;
  1028. } else {
  1029. Repinned = Repinned->Next;
  1030. IrpContext->Repinned.Next = NULL;
  1031. }
  1032. }
  1033. //
  1034. // Now if we weren't completely successful in the our unpin
  1035. // then raise the iosb we got
  1036. //
  1037. if (!NT_SUCCESS(RaiseIosb.Status)) {
  1038. if (ForceVerify && FileObject) {
  1039. SetFlag(FileObject->DeviceObject->Flags, DO_VERIFY_VOLUME);
  1040. IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
  1041. FileObject->DeviceObject );
  1042. }
  1043. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE )) {
  1044. IrpContext->OriginatingIrp->IoStatus = RaiseIosb;
  1045. FatNormalizeAndRaiseStatus( IrpContext, RaiseIosb.Status );
  1046. }
  1047. }
  1048. DebugTrace(-1, Dbg, "FatUnpinRepinnedBcbs -> VOID\n", 0 );
  1049. return;
  1050. }
  1051. FINISHED
  1052. FatZeroData (
  1053. IN PIRP_CONTEXT IrpContext,
  1054. IN PVCB Vcb,
  1055. IN PFILE_OBJECT FileObject,
  1056. IN ULONG StartingZero,
  1057. IN ULONG ByteCount
  1058. )
  1059. /*++
  1060. **** Temporary function - Remove when CcZeroData is capable of handling
  1061. non sector aligned requests.
  1062. --*/
  1063. {
  1064. LARGE_INTEGER ZeroStart = {0,0};
  1065. LARGE_INTEGER BeyondZeroEnd = {0,0};
  1066. ULONG SectorSize;
  1067. BOOLEAN Finished;
  1068. PAGED_CODE();
  1069. SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
  1070. ZeroStart.LowPart = (StartingZero + (SectorSize - 1)) & ~(SectorSize - 1);
  1071. //
  1072. // Detect overflow if we were asked to zero in the last sector of the file,
  1073. // which must be "zeroed" already (or we're in trouble).
  1074. //
  1075. if (StartingZero != 0 && ZeroStart.LowPart == 0) {
  1076. return TRUE;
  1077. }
  1078. //
  1079. // Note that BeyondZeroEnd can take the value 4gb.
  1080. //
  1081. BeyondZeroEnd.QuadPart = ((ULONGLONG) StartingZero + ByteCount + (SectorSize - 1))
  1082. & (~((LONGLONG) SectorSize - 1));
  1083. //
  1084. // If we were called to just zero part of a sector we are in trouble.
  1085. //
  1086. if ( ZeroStart.QuadPart == BeyondZeroEnd.QuadPart ) {
  1087. return TRUE;
  1088. }
  1089. Finished = CcZeroData( FileObject,
  1090. &ZeroStart,
  1091. &BeyondZeroEnd,
  1092. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
  1093. return Finished;
  1094. }
  1095. NTSTATUS
  1096. FatCompleteMdl (
  1097. IN PIRP_CONTEXT IrpContext,
  1098. IN PIRP Irp
  1099. )
  1100. /*++
  1101. Routine Description:
  1102. This routine performs the function of completing Mdl read and write
  1103. requests. It should be called only from FatFsdRead and FatFsdWrite.
  1104. Arguments:
  1105. Irp - Supplies the originating Irp.
  1106. Return Value:
  1107. NTSTATUS - Will always be STATUS_PENDING or STATUS_SUCCESS.
  1108. --*/
  1109. {
  1110. PFILE_OBJECT FileObject;
  1111. PIO_STACK_LOCATION IrpSp;
  1112. PAGED_CODE();
  1113. DebugTrace(+1, Dbg, "FatCompleteMdl\n", 0 );
  1114. DebugTrace( 0, Dbg, "IrpContext = %08lx\n", IrpContext );
  1115. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  1116. //
  1117. // Do completion processing.
  1118. //
  1119. FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject;
  1120. switch( IrpContext->MajorFunction ) {
  1121. case IRP_MJ_READ:
  1122. CcMdlReadComplete( FileObject, Irp->MdlAddress );
  1123. break;
  1124. case IRP_MJ_WRITE:
  1125. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1126. ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ));
  1127. CcMdlWriteComplete( FileObject, &IrpSp->Parameters.Write.ByteOffset, Irp->MdlAddress );
  1128. Irp->IoStatus.Status = STATUS_SUCCESS;
  1129. break;
  1130. default:
  1131. DebugTrace( DEBUG_TRACE_ERROR, 0, "Illegal Mdl Complete.\n", 0);
  1132. FatBugCheck( IrpContext->MajorFunction, 0, 0 );
  1133. }
  1134. //
  1135. // Mdl is now deallocated.
  1136. //
  1137. Irp->MdlAddress = NULL;
  1138. //
  1139. // Complete the request and exit right away.
  1140. //
  1141. FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  1142. DebugTrace(-1, Dbg, "FatCompleteMdl -> STATUS_SUCCESS\n", 0 );
  1143. return STATUS_SUCCESS;
  1144. }
  1145. VOID
  1146. FatSyncUninitializeCacheMap (
  1147. IN PIRP_CONTEXT IrpContext,
  1148. IN PFILE_OBJECT FileObject
  1149. )
  1150. /*++
  1151. Routine Description:
  1152. The routine performs a CcUnitializeCacheMap to LargeZero synchronously. That
  1153. is it waits on the Cc event. This call is useful when we want to be certain
  1154. when a close will actually some in.
  1155. Return Value:
  1156. None.
  1157. --*/
  1158. {
  1159. CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent;
  1160. NTSTATUS WaitStatus;
  1161. PAGED_CODE();
  1162. KeInitializeEvent( &UninitializeCompleteEvent.Event,
  1163. SynchronizationEvent,
  1164. FALSE);
  1165. CcUninitializeCacheMap( FileObject,
  1166. &FatLargeZero,
  1167. &UninitializeCompleteEvent );
  1168. //
  1169. // Now wait for the cache manager to finish purging the file.
  1170. // This will garentee that Mm gets the purge before we
  1171. // delete the Vcb.
  1172. //
  1173. WaitStatus = KeWaitForSingleObject( &UninitializeCompleteEvent.Event,
  1174. Executive,
  1175. KernelMode,
  1176. FALSE,
  1177. NULL);
  1178. ASSERT(WaitStatus == STATUS_SUCCESS);
  1179. }
  1180. VOID
  1181. FatPinMappedData (
  1182. IN PIRP_CONTEXT IrpContext,
  1183. IN PDCB Dcb,
  1184. IN VBO StartingVbo,
  1185. IN ULONG ByteCount,
  1186. OUT PBCB *Bcb
  1187. )
  1188. /*++
  1189. Routine Description:
  1190. This routine pins data that was previously mapped before setting it dirty.
  1191. Arguments:
  1192. Dcb - Pointer to the DCB for the directory
  1193. StartingVbo - The virtual offset of the first desired byte
  1194. ByteCount - Number of bytes desired
  1195. Bcb - Returns a pointer to the BCB which is valid until unpinned
  1196. --*/
  1197. {
  1198. LARGE_INTEGER Vbo;
  1199. PAGED_CODE();
  1200. DebugTrace(+1, Dbg, "FatPinMappedData\n", 0);
  1201. DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb);
  1202. DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo);
  1203. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
  1204. //
  1205. // Call the Cache manager to perform the operation.
  1206. //
  1207. Vbo.QuadPart = StartingVbo;
  1208. if (!CcPinMappedData( Dcb->Specific.Dcb.DirectoryFile,
  1209. &Vbo,
  1210. ByteCount,
  1211. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
  1212. Bcb )) {
  1213. //
  1214. // Could not pin the data without waiting (cache miss).
  1215. //
  1216. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  1217. }
  1218. DebugTrace(-1, Dbg, "FatReadDirectoryFile -> VOID, *BCB = %08lx\n", *Bcb);
  1219. return;
  1220. }