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.

3286 lines
91 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. DevIoSup.c
  5. Abstract:
  6. This module implements the low lever disk read/write support for Fat.
  7. // @@BEGIN_DDKSPLIT
  8. Author:
  9. Gary Kimura [GaryKi] 22-Jan-1990
  10. Revision History:
  11. David Goebel [DavidGoe] 05-Oct-1990
  12. Major changes for the new FAT
  13. Tom Miller [TomM] 22-Apr-1990
  14. Added User Buffer Locking and Mapping routines
  15. Modified behavior of async I/O routines to use completion routines
  16. // @@END_DDKSPLIT
  17. --*/
  18. #include "FatProcs.h"
  19. //
  20. // The Bug check file id for this module
  21. //
  22. #define BugCheckFileId (FAT_BUG_CHECK_DEVIOSUP)
  23. //
  24. // Local debug trace level
  25. //
  26. #define Dbg (DEBUG_TRACE_DEVIOSUP)
  27. #define CollectDiskIoStats(VCB,FUNCTION,IS_USER_IO,COUNT) { \
  28. PFILESYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()].Common; \
  29. if (IS_USER_IO) { \
  30. if ((FUNCTION) == IRP_MJ_WRITE) { \
  31. Stats->UserDiskWrites += (COUNT); \
  32. } else { \
  33. Stats->UserDiskReads += (COUNT); \
  34. } \
  35. } else { \
  36. if ((FUNCTION) == IRP_MJ_WRITE) { \
  37. Stats->MetaDataDiskWrites += (COUNT); \
  38. } else { \
  39. Stats->MetaDataDiskReads += (COUNT); \
  40. } \
  41. } \
  42. }
  43. //
  44. // Completion Routine declarations
  45. //
  46. NTSTATUS
  47. FatMultiSyncCompletionRoutine (
  48. IN PDEVICE_OBJECT DeviceObject,
  49. IN PIRP Irp,
  50. IN PVOID Contxt
  51. );
  52. NTSTATUS
  53. FatMultiAsyncCompletionRoutine (
  54. IN PDEVICE_OBJECT DeviceObject,
  55. IN PIRP Irp,
  56. IN PVOID Contxt
  57. );
  58. NTSTATUS
  59. FatSpecialSyncCompletionRoutine (
  60. IN PDEVICE_OBJECT DeviceObject,
  61. IN PIRP Irp,
  62. IN PVOID Contxt
  63. );
  64. NTSTATUS
  65. FatSingleSyncCompletionRoutine (
  66. IN PDEVICE_OBJECT DeviceObject,
  67. IN PIRP Irp,
  68. IN PVOID Contxt
  69. );
  70. NTSTATUS
  71. FatSingleAsyncCompletionRoutine (
  72. IN PDEVICE_OBJECT DeviceObject,
  73. IN PIRP Irp,
  74. IN PVOID Contxt
  75. );
  76. NTSTATUS
  77. FatPagingFileCompletionRoutine (
  78. IN PDEVICE_OBJECT DeviceObject,
  79. IN PIRP Irp,
  80. IN PVOID MasterIrp
  81. );
  82. NTSTATUS
  83. FatPagingFileCompletionRoutineCatch (
  84. IN PDEVICE_OBJECT DeviceObject,
  85. IN PIRP Irp,
  86. IN PVOID Contxt
  87. );
  88. VOID
  89. FatSingleNonAlignedSync (
  90. IN PIRP_CONTEXT IrpContext,
  91. IN PVCB Vcb,
  92. IN PUCHAR Buffer,
  93. IN LBO Lbo,
  94. IN ULONG ByteCount,
  95. IN PIRP Irp
  96. );
  97. //
  98. // The following macro decides whether to send a request directly to
  99. // the device driver, or to other routines. It was meant to
  100. // replace IoCallDriver as transparently as possible. It must only be
  101. // called with a read or write Irp.
  102. //
  103. // NTSTATUS
  104. // FatLowLevelReadWrite (
  105. // PIRP_CONTEXT IrpContext,
  106. // PDEVICE_OBJECT DeviceObject,
  107. // PIRP Irp,
  108. // PVCB Vcb
  109. // );
  110. //
  111. #define FatLowLevelReadWrite(IRPCONTEXT,DO,IRP,VCB) ( \
  112. IoCallDriver((DO),(IRP)) \
  113. )
  114. //
  115. // The following macro handles completion-time zeroing of buffers.
  116. //
  117. #define FatDoCompletionZero( I, C ) \
  118. if ((C)->ZeroMdl) { \
  119. ASSERT( (C)->ZeroMdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | \
  120. MDL_SOURCE_IS_NONPAGED_POOL));\
  121. if (NT_SUCCESS((I)->IoStatus.Status)) { \
  122. RtlZeroMemory( (C)->ZeroMdl->MappedSystemVa, \
  123. (C)->ZeroMdl->ByteCount ); \
  124. } \
  125. IoFreeMdl((C)->ZeroMdl); \
  126. (C)->ZeroMdl = NULL; \
  127. }
  128. #ifdef ALLOC_PRAGMA
  129. #pragma alloc_text(PAGE, FatMultipleAsync)
  130. #pragma alloc_text(PAGE, FatSingleAsync)
  131. #pragma alloc_text(PAGE, FatSingleNonAlignedSync)
  132. #pragma alloc_text(PAGE, FatWaitSync)
  133. #pragma alloc_text(PAGE, FatLockUserBuffer)
  134. #pragma alloc_text(PAGE, FatBufferUserBuffer)
  135. #pragma alloc_text(PAGE, FatMapUserBuffer)
  136. #pragma alloc_text(PAGE, FatNonCachedIo)
  137. #pragma alloc_text(PAGE, FatSingleNonAlignedSync)
  138. #pragma alloc_text(PAGE, FatNonCachedNonAlignedRead)
  139. #endif
  140. typedef struct FAT_PAGING_FILE_CONTEXT {
  141. KEVENT Event;
  142. PMDL RestoreMdl;
  143. } FAT_PAGING_FILE_CONTEXT, *PFAT_PAGING_FILE_CONTEXT;
  144. VOID
  145. FatPagingFileIo (
  146. IN PIRP Irp,
  147. IN PFCB Fcb
  148. )
  149. /*++
  150. Routine Description:
  151. This routine performs the non-cached disk io described in its parameters.
  152. This routine nevers blocks, and should only be used with the paging
  153. file since no completion processing is performed.
  154. Arguments:
  155. Irp - Supplies the requesting Irp.
  156. Fcb - Supplies the file to act on.
  157. Return Value:
  158. None.
  159. --*/
  160. {
  161. //
  162. // Declare some local variables for enumeration through the
  163. // runs of the file.
  164. //
  165. VBO Vbo;
  166. ULONG ByteCount;
  167. PMDL Mdl;
  168. LBO NextLbo;
  169. VBO NextVbo;
  170. ULONG NextByteCount;
  171. ULONG RemainingByteCount;
  172. BOOLEAN MustSucceed;
  173. ULONG FirstIndex;
  174. ULONG CurrentIndex;
  175. ULONG LastIndex;
  176. LBO LastLbo;
  177. ULONG LastByteCount;
  178. BOOLEAN MdlIsReserve = FALSE;
  179. BOOLEAN IrpIsMaster = FALSE;
  180. FAT_PAGING_FILE_CONTEXT Context;
  181. LONG IrpCount;
  182. PIRP AssocIrp;
  183. PIO_STACK_LOCATION IrpSp;
  184. PIO_STACK_LOCATION NextIrpSp;
  185. ULONG BufferOffset;
  186. PDEVICE_OBJECT DeviceObject;
  187. DebugTrace(+1, Dbg, "FatPagingFileIo\n", 0);
  188. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  189. DebugTrace( 0, Dbg, "Fcb = %08lx\n", Fcb );
  190. ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE ));
  191. //
  192. // Initialize some locals.
  193. //
  194. BufferOffset = 0;
  195. DeviceObject = Fcb->Vcb->TargetDeviceObject;
  196. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  197. Vbo = IrpSp->Parameters.Read.ByteOffset.LowPart;
  198. ByteCount = IrpSp->Parameters.Read.Length;
  199. MustSucceed = FatLookupMcbEntry( Fcb->Vcb, &Fcb->Mcb,
  200. Vbo,
  201. &NextLbo,
  202. &NextByteCount,
  203. &FirstIndex);
  204. //
  205. // If this run isn't present, something is very wrong.
  206. //
  207. if (!MustSucceed) {
  208. FatBugCheck( Vbo, ByteCount, 0 );
  209. }
  210. //
  211. // See if the write covers a single valid run, and if so pass
  212. // it on.
  213. //
  214. if ( NextByteCount >= ByteCount ) {
  215. DebugTrace( 0, Dbg, "Passing Irp on to Disk Driver\n", 0 );
  216. //
  217. // Setup the next IRP stack location for the disk driver beneath us.
  218. //
  219. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  220. NextIrpSp->MajorFunction = IrpSp->MajorFunction;
  221. NextIrpSp->Parameters.Read.Length = ByteCount;
  222. NextIrpSp->Parameters.Read.ByteOffset.QuadPart = NextLbo;
  223. //
  224. // Since this is Paging file IO, we'll just ignore the verify bit.
  225. //
  226. SetFlag( NextIrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  227. //
  228. // Set up the completion routine address in our stack frame.
  229. // This is only invoked on error or cancel, and just copies
  230. // the error Status into master irp's iosb.
  231. //
  232. // If the error implies a media problem, it also enqueues a
  233. // worker item to write out the dirty bit so that the next
  234. // time we run we will do a autochk /r
  235. //
  236. IoSetCompletionRoutine( Irp,
  237. &FatPagingFileCompletionRoutine,
  238. Irp,
  239. FALSE,
  240. TRUE,
  241. TRUE );
  242. //
  243. // Issue the read/write request
  244. //
  245. // If IoCallDriver returns an error, it has completed the Irp
  246. // and the error will be dealt with as a normal IO error.
  247. //
  248. (VOID)IoCallDriver( DeviceObject, Irp );
  249. DebugTrace(-1, Dbg, "FatPagingFileIo -> VOID\n", 0);
  250. return;
  251. }
  252. //
  253. // Find out how may runs there are.
  254. //
  255. MustSucceed = FatLookupMcbEntry( Fcb->Vcb, &Fcb->Mcb,
  256. Vbo + ByteCount - 1,
  257. &LastLbo,
  258. &LastByteCount,
  259. &LastIndex);
  260. //
  261. // If this run isn't present, something is very wrong.
  262. //
  263. if (!MustSucceed) {
  264. FatBugCheck( Vbo + ByteCount - 1, 1, 0 );
  265. }
  266. CurrentIndex = FirstIndex;
  267. //
  268. // Now set up the Irp->IoStatus. It will be modified by the
  269. // multi-completion routine in case of error or verify required.
  270. //
  271. Irp->IoStatus.Status = STATUS_SUCCESS;
  272. Irp->IoStatus.Information = ByteCount;
  273. //
  274. // Loop while there are still byte writes to satisfy. The way we'll work this
  275. // is to hope for the best - one associated IRP per run, which will let us be
  276. // completely async after launching all the IO.
  277. //
  278. // IrpCount will indicate the remaining number of associated Irps to launch.
  279. //
  280. // All we have to do is make sure IrpCount doesn't hit zero before we're building
  281. // the very last Irp. If it is positive when we're done, it means we have to
  282. // wait for the rest of the associated Irps to come back before we complete the
  283. // master by hand.
  284. //
  285. // This will keep the master from completing early.
  286. //
  287. Irp->AssociatedIrp.IrpCount = IrpCount = LastIndex - FirstIndex + 1;
  288. while (CurrentIndex <= LastIndex) {
  289. //
  290. // Reset this for unwinding purposes
  291. //
  292. AssocIrp = NULL;
  293. //
  294. // If next run is larger than we need, "ya get what ya need".
  295. //
  296. if (NextByteCount > ByteCount) {
  297. NextByteCount = ByteCount;
  298. }
  299. RemainingByteCount = 0;
  300. //
  301. // Allocate and build a partial Mdl for the request.
  302. //
  303. Mdl = IoAllocateMdl( (PCHAR)Irp->UserBuffer + BufferOffset,
  304. NextByteCount,
  305. FALSE,
  306. FALSE,
  307. AssocIrp );
  308. if (Mdl == NULL) {
  309. //
  310. // Pick up the reserve MDL
  311. //
  312. KeWaitForSingleObject( &FatReserveEvent, Executive, KernelMode, FALSE, NULL );
  313. Mdl = FatReserveMdl;
  314. MdlIsReserve = TRUE;
  315. //
  316. // Trim to fit the size of the reserve MDL.
  317. //
  318. if (NextByteCount > FAT_RESERVE_MDL_SIZE * PAGE_SIZE) {
  319. RemainingByteCount = NextByteCount - FAT_RESERVE_MDL_SIZE * PAGE_SIZE;
  320. NextByteCount = FAT_RESERVE_MDL_SIZE * PAGE_SIZE;
  321. }
  322. }
  323. IoBuildPartialMdl( Irp->MdlAddress,
  324. Mdl,
  325. (PCHAR)Irp->UserBuffer + BufferOffset,
  326. NextByteCount );
  327. //
  328. // Now that we have properly bounded this piece of the transfer, it is
  329. // time to read/write it. We can simplify life slightly by always
  330. // re-using the master IRP for cases where we use the reserve MDL,
  331. // since we'll always be synchronous for those and can use a single
  332. // completion context on our local stack.
  333. //
  334. // We also must prevent ourselves from issuing an associated IRP that would
  335. // complete the master UNLESS this is the very last IRP we'll issue.
  336. //
  337. // This logic looks a bit nasty, but is hopefully straightforward.
  338. //
  339. if (!MdlIsReserve &&
  340. (IrpCount != 1 ||
  341. (CurrentIndex == LastIndex &&
  342. RemainingByteCount == 0))) {
  343. AssocIrp = IoMakeAssociatedIrp( Irp, (CCHAR)(DeviceObject->StackSize + 1) );
  344. }
  345. if (AssocIrp == NULL) {
  346. AssocIrp = Irp;
  347. IrpIsMaster = TRUE;
  348. //
  349. // We need to drain the associated Irps so we can reliably figure out if
  350. // the master Irp is showing a failed status, in which case we bail out
  351. // immediately - as opposed to putting the value in the status field in
  352. // jeopardy due to our re-use of the master Irp.
  353. //
  354. while (Irp->AssociatedIrp.IrpCount != IrpCount) {
  355. KeDelayExecutionThread (KernelMode, FALSE, &Fat30Milliseconds);
  356. }
  357. //
  358. // Note that since we failed to launch this associated Irp, that the completion
  359. // code at the bottom will take care of completing the master Irp.
  360. //
  361. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  362. ASSERT( IrpCount );
  363. break;
  364. }
  365. } else {
  366. //
  367. // Indicate we used an associated Irp.
  368. //
  369. IrpCount -= 1;
  370. }
  371. //
  372. // With an associated IRP, we must take over the first stack location so
  373. // we can have one to put the completion routine on. When re-using the
  374. // master IRP, its already there.
  375. //
  376. if (!IrpIsMaster) {
  377. //
  378. // Get the first IRP stack location in the associated Irp
  379. //
  380. IoSetNextIrpStackLocation( AssocIrp );
  381. NextIrpSp = IoGetCurrentIrpStackLocation( AssocIrp );
  382. //
  383. // Setup the Stack location to describe our read.
  384. //
  385. NextIrpSp->MajorFunction = IrpSp->MajorFunction;
  386. NextIrpSp->Parameters.Read.Length = NextByteCount;
  387. NextIrpSp->Parameters.Read.ByteOffset.QuadPart = Vbo;
  388. //
  389. // We also need the VolumeDeviceObject in the Irp stack in case
  390. // we take the failure path.
  391. //
  392. NextIrpSp->DeviceObject = IrpSp->DeviceObject;
  393. } else {
  394. //
  395. // Save the MDL in the IRP and prepare the stack
  396. // context for the completion routine.
  397. //
  398. KeInitializeEvent( &Context.Event, SynchronizationEvent, FALSE );
  399. Context.RestoreMdl = Irp->MdlAddress;
  400. }
  401. //
  402. // And drop our Mdl into the Irp.
  403. //
  404. AssocIrp->MdlAddress = Mdl;
  405. //
  406. // Set up the completion routine address in our stack frame.
  407. // For true associated IRPs, this is only invoked on error or
  408. // cancel, and just copies the error Status into master irp's
  409. // iosb.
  410. //
  411. // If the error implies a media problem, it also enqueues a
  412. // worker item to write out the dirty bit so that the next
  413. // time we run we will do a autochk /r
  414. //
  415. if (IrpIsMaster) {
  416. IoSetCompletionRoutine( AssocIrp,
  417. FatPagingFileCompletionRoutineCatch,
  418. &Context,
  419. TRUE,
  420. TRUE,
  421. TRUE );
  422. } else {
  423. IoSetCompletionRoutine( AssocIrp,
  424. FatPagingFileCompletionRoutine,
  425. Irp,
  426. FALSE,
  427. TRUE,
  428. TRUE );
  429. }
  430. //
  431. // Setup the next IRP stack location for the disk driver beneath us.
  432. //
  433. NextIrpSp = IoGetNextIrpStackLocation( AssocIrp );
  434. //
  435. // Since this is paging file IO, we'll just ignore the verify bit.
  436. //
  437. SetFlag( NextIrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  438. //
  439. // Setup the Stack location to do a read from the disk driver.
  440. //
  441. NextIrpSp->MajorFunction = IrpSp->MajorFunction;
  442. NextIrpSp->Parameters.Read.Length = NextByteCount;
  443. NextIrpSp->Parameters.Read.ByteOffset.QuadPart = NextLbo;
  444. (VOID)IoCallDriver( DeviceObject, AssocIrp );
  445. //
  446. // Wait for the Irp in the catch case and drop the flags.
  447. //
  448. if (IrpIsMaster) {
  449. KeWaitForSingleObject( &Context.Event, Executive, KernelMode, FALSE, NULL );
  450. IrpIsMaster = MdlIsReserve = FALSE;
  451. //
  452. // If the Irp is showing a failed status, there is no point in continuing.
  453. // In doing so, we get to avoid squirreling away the failed status in case
  454. // we were to re-use the master irp again.
  455. //
  456. // Note that since we re-used the master, we must not have issued the "last"
  457. // associated Irp, and thus the completion code at the bottom will take care
  458. // of that for us.
  459. //
  460. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  461. ASSERT( IrpCount );
  462. break;
  463. }
  464. }
  465. //
  466. // Now adjust everything for the next pass through the loop.
  467. //
  468. Vbo += NextByteCount;
  469. BufferOffset += NextByteCount;
  470. ByteCount -= NextByteCount;
  471. //
  472. // Try to lookup the next run, if we are not done and we got
  473. // all the way through the current run.
  474. //
  475. if (RemainingByteCount) {
  476. //
  477. // Advance the Lbo/Vbo if we have more to do in the current run.
  478. //
  479. NextLbo += NextByteCount;
  480. NextVbo += NextByteCount;
  481. NextByteCount = RemainingByteCount;
  482. } else {
  483. CurrentIndex += 1;
  484. if ( CurrentIndex <= LastIndex ) {
  485. ASSERT( ByteCount != 0 );
  486. FatGetNextMcbEntry( Fcb->Vcb, &Fcb->Mcb,
  487. CurrentIndex,
  488. &NextVbo,
  489. &NextLbo,
  490. &NextByteCount );
  491. ASSERT( NextVbo == Vbo );
  492. }
  493. }
  494. } // while ( CurrentIndex <= LastIndex )
  495. //
  496. // If we didn't get enough associated Irps going to make this asynchronous, we
  497. // twiddle our thumbs and wait for those we did launch to complete.
  498. //
  499. if (IrpCount) {
  500. while (Irp->AssociatedIrp.IrpCount != IrpCount) {
  501. KeDelayExecutionThread (KernelMode, FALSE, &Fat30Milliseconds);
  502. }
  503. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  504. }
  505. DebugTrace(-1, Dbg, "FatPagingFileIo -> VOID\n", 0);
  506. return;
  507. }
  508. NTSTATUS
  509. FatNonCachedIo (
  510. IN PIRP_CONTEXT IrpContext,
  511. IN PIRP Irp,
  512. IN PFCB FcbOrDcb,
  513. IN ULONG StartingVbo,
  514. IN ULONG ByteCount,
  515. IN ULONG UserByteCount
  516. )
  517. /*++
  518. Routine Description:
  519. This routine performs the non-cached disk io described in its parameters.
  520. The choice of a single run is made if possible, otherwise multiple runs
  521. are executed.
  522. Arguments:
  523. IrpContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
  524. Irp - Supplies the requesting Irp.
  525. FcbOrDcb - Supplies the file to act on.
  526. StartingVbo - The starting point for the operation.
  527. ByteCount - The lengh of the operation.
  528. UserByteCount - The last byte the user can see, rest to be zeroed.
  529. Return Value:
  530. None.
  531. --*/
  532. {
  533. //
  534. // Declare some local variables for enumeration through the
  535. // runs of the file, and an array to store parameters for
  536. // parallel I/Os
  537. //
  538. BOOLEAN Wait;
  539. LBO NextLbo;
  540. VBO NextVbo;
  541. ULONG NextByteCount;
  542. BOOLEAN NextIsAllocated;
  543. LBO LastLbo;
  544. ULONG LastByteCount;
  545. BOOLEAN LastIsAllocated;
  546. BOOLEAN EndOnMax;
  547. ULONG FirstIndex;
  548. ULONG CurrentIndex;
  549. ULONG LastIndex;
  550. ULONG NextRun;
  551. ULONG BufferOffset;
  552. ULONG OriginalByteCount;
  553. IO_RUN StackIoRuns[FAT_MAX_IO_RUNS_ON_STACK];
  554. PIO_RUN IoRuns;
  555. DebugTrace(+1, Dbg, "FatNonCachedIo\n", 0);
  556. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  557. DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", IrpContext->MajorFunction );
  558. DebugTrace( 0, Dbg, "FcbOrDcb = %08lx\n", FcbOrDcb );
  559. DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo );
  560. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount );
  561. if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  562. PFILE_SYSTEM_STATISTICS Stats =
  563. &FcbOrDcb->Vcb->Statistics[KeGetCurrentProcessorNumber()];
  564. if (IrpContext->MajorFunction == IRP_MJ_READ) {
  565. Stats->Fat.NonCachedReads += 1;
  566. Stats->Fat.NonCachedReadBytes += ByteCount;
  567. } else {
  568. Stats->Fat.NonCachedWrites += 1;
  569. Stats->Fat.NonCachedWriteBytes += ByteCount;
  570. }
  571. }
  572. //
  573. // Initialize some locals.
  574. //
  575. NextRun = 0;
  576. BufferOffset = 0;
  577. OriginalByteCount = ByteCount;
  578. Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
  579. //
  580. // For nonbuffered I/O, we need the buffer locked in all
  581. // cases.
  582. //
  583. // This call may raise. If this call succeeds and a subsequent
  584. // condition is raised, the buffers are unlocked automatically
  585. // by the I/O system when the request is completed, via the
  586. // Irp->MdlAddress field.
  587. //
  588. FatLockUserBuffer( IrpContext,
  589. Irp,
  590. (IrpContext->MajorFunction == IRP_MJ_READ) ?
  591. IoWriteAccess : IoReadAccess,
  592. ByteCount );
  593. //
  594. // Setup the required zeroing for read requests.
  595. //
  596. if (UserByteCount != ByteCount) {
  597. PMDL Mdl;
  598. ASSERT( ByteCount > UserByteCount );
  599. Mdl = IoAllocateMdl( (PUCHAR) Irp->UserBuffer + UserByteCount,
  600. ByteCount - UserByteCount,
  601. FALSE,
  602. FALSE,
  603. NULL );
  604. if (Mdl == NULL) {
  605. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  606. }
  607. IoBuildPartialMdl( Irp->MdlAddress,
  608. Mdl,
  609. (PUCHAR) Irp->UserBuffer + UserByteCount,
  610. ByteCount - UserByteCount );
  611. IrpContext->FatIoContext->ZeroMdl = Mdl;
  612. //
  613. // Map the MDL now so we can't fail at IO completion time. Note
  614. // that this will be only a single page.
  615. //
  616. if (MmGetSystemAddressForMdlSafe( Mdl, NormalPagePriority ) == NULL) {
  617. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  618. }
  619. }
  620. #if 0 // The corruption was happening on the SCSI bus. (DavidGoe 1/11/93)
  621. //
  622. // If we are writing a directory, add a spot check here that
  623. // what we are writing is really a directory.
  624. //
  625. if ( !FlagOn(FcbOrDcb->Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
  626. (NodeType(FcbOrDcb) != FAT_NTC_FCB) &&
  627. (IrpContext->MajorFunction == IRP_MJ_WRITE) ) {
  628. PDIRENT Dirent;
  629. Dirent = FatMapUserBuffer( IrpContext, Irp );
  630. //
  631. // For the first page of a non-root directory, make sure that
  632. // . and .. are present.
  633. //
  634. if ( (StartingVbo == 0) &&
  635. (NodeType(FcbOrDcb) != FAT_NTC_ROOT_DCB) ) {
  636. if ( (!RtlEqualMemory( (PUCHAR)Dirent++,
  637. ". ",
  638. 11 )) ||
  639. (!RtlEqualMemory( (PUCHAR)Dirent,
  640. ".. ",
  641. 11 )) ) {
  642. FatBugCheck( 0, 0, 0 );
  643. }
  644. } else {
  645. //
  646. // Check that all the reserved bit in the second dirent are
  647. // zero. (The first one contains our dirty bit in the root dir)
  648. //
  649. PULONG Zeros;
  650. Dirent++;
  651. Zeros = (PULONG)&Dirent->Reserved[0];
  652. if ( (Dirent->FileName[0] != 0xE5) &&
  653. ((*Zeros != 0) || (*(Zeros+1) != 0)) ) {
  654. FatBugCheck( 0, 0, 0 );
  655. }
  656. }
  657. }
  658. #endif //0
  659. //
  660. // Try to lookup the first run. If there is just a single run,
  661. // we may just be able to pass it on.
  662. //
  663. FatLookupFileAllocation( IrpContext,
  664. FcbOrDcb,
  665. StartingVbo,
  666. &NextLbo,
  667. &NextByteCount,
  668. &NextIsAllocated,
  669. &EndOnMax,
  670. &FirstIndex );
  671. //
  672. // We just added the allocation, thus there must be at least
  673. // one entry in the mcb corresponding to our write, ie.
  674. // NextIsAllocated must be true. If not, the pre-existing file
  675. // must have an allocation error.
  676. //
  677. if ( !NextIsAllocated ) {
  678. FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
  679. FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  680. }
  681. ASSERT( NextByteCount != 0 );
  682. //
  683. // If the request was not aligned correctly, read in the first
  684. // part first.
  685. //
  686. //
  687. // See if the write covers a single valid run, and if so pass
  688. // it on. We must bias this by the byte that is lost at the
  689. // end of the maximal file.
  690. //
  691. if ( NextByteCount >= ByteCount - (EndOnMax ? 1 : 0)) {
  692. if (FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  693. CollectDiskIoStats(FcbOrDcb->Vcb, IrpContext->MajorFunction,
  694. FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO), 1);
  695. } else {
  696. PFILE_SYSTEM_STATISTICS Stats =
  697. &FcbOrDcb->Vcb->Statistics[KeGetCurrentProcessorNumber()];
  698. if (IrpContext->MajorFunction == IRP_MJ_READ) {
  699. Stats->Fat.NonCachedDiskReads += 1;
  700. } else {
  701. Stats->Fat.NonCachedDiskWrites += 1;
  702. }
  703. }
  704. DebugTrace( 0, Dbg, "Passing 1 Irp on to Disk Driver\n", 0 );
  705. FatSingleAsync( IrpContext,
  706. FcbOrDcb->Vcb,
  707. NextLbo,
  708. ByteCount,
  709. Irp );
  710. } else {
  711. //
  712. // If there we can't wait, and there are more runs than we can handle,
  713. // we will have to post this request.
  714. //
  715. FatLookupFileAllocation( IrpContext,
  716. FcbOrDcb,
  717. StartingVbo + ByteCount - 1,
  718. &LastLbo,
  719. &LastByteCount,
  720. &LastIsAllocated,
  721. &EndOnMax,
  722. &LastIndex );
  723. //
  724. // Since we already added the allocation for the whole
  725. // write, assert that we find runs until ByteCount == 0
  726. // Otherwise this file is corrupt.
  727. //
  728. if ( !LastIsAllocated ) {
  729. FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
  730. FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  731. }
  732. if (LastIndex - FirstIndex + 1 > FAT_MAX_IO_RUNS_ON_STACK) {
  733. IoRuns = FsRtlAllocatePoolWithTag( PagedPool,
  734. (LastIndex - FirstIndex + 1) * sizeof(IO_RUN),
  735. TAG_IO_RUNS );
  736. } else {
  737. IoRuns = StackIoRuns;
  738. }
  739. ASSERT( LastIndex != FirstIndex );
  740. CurrentIndex = FirstIndex;
  741. //
  742. // Loop while there are still byte writes to satisfy.
  743. //
  744. while (CurrentIndex <= LastIndex) {
  745. ASSERT( NextByteCount != 0);
  746. ASSERT( ByteCount != 0);
  747. //
  748. // If next run is larger than we need, "ya get what you need".
  749. //
  750. if (NextByteCount > ByteCount) {
  751. NextByteCount = ByteCount;
  752. }
  753. //
  754. // Now that we have properly bounded this piece of the
  755. // transfer, it is time to write it.
  756. //
  757. // We remember each piece of a parallel run by saving the
  758. // essential information in the IoRuns array. The tranfers
  759. // are started up in parallel below.
  760. //
  761. IoRuns[NextRun].Vbo = StartingVbo;
  762. IoRuns[NextRun].Lbo = NextLbo;
  763. IoRuns[NextRun].Offset = BufferOffset;
  764. IoRuns[NextRun].ByteCount = NextByteCount;
  765. NextRun += 1;
  766. //
  767. // Now adjust everything for the next pass through the loop.
  768. //
  769. StartingVbo += NextByteCount;
  770. BufferOffset += NextByteCount;
  771. ByteCount -= NextByteCount;
  772. //
  773. // Try to lookup the next run (if we are not done).
  774. //
  775. CurrentIndex += 1;
  776. if ( CurrentIndex <= LastIndex ) {
  777. ASSERT( ByteCount != 0 );
  778. FatGetNextMcbEntry( FcbOrDcb->Vcb, &FcbOrDcb->Mcb,
  779. CurrentIndex,
  780. &NextVbo,
  781. &NextLbo,
  782. &NextByteCount );
  783. ASSERT( NextVbo == StartingVbo );
  784. }
  785. } // while ( CurrentIndex <= LastIndex )
  786. //
  787. // Now set up the Irp->IoStatus. It will be modified by the
  788. // multi-completion routine in case of error or verify required.
  789. //
  790. Irp->IoStatus.Status = STATUS_SUCCESS;
  791. Irp->IoStatus.Information = OriginalByteCount;
  792. if (FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  793. CollectDiskIoStats(FcbOrDcb->Vcb, IrpContext->MajorFunction,
  794. FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO), NextRun);
  795. }
  796. //
  797. // OK, now do the I/O.
  798. //
  799. try {
  800. DebugTrace( 0, Dbg, "Passing Multiple Irps on to Disk Driver\n", 0 );
  801. FatMultipleAsync( IrpContext,
  802. FcbOrDcb->Vcb,
  803. Irp,
  804. NextRun,
  805. IoRuns );
  806. } finally {
  807. if (IoRuns != StackIoRuns) {
  808. ExFreePool( IoRuns );
  809. }
  810. }
  811. }
  812. if (!Wait) {
  813. DebugTrace(-1, Dbg, "FatNonCachedIo -> STATUS_PENDING\n", 0);
  814. return STATUS_PENDING;
  815. }
  816. FatWaitSync( IrpContext );
  817. DebugTrace(-1, Dbg, "FatNonCachedIo -> 0x%08lx\n", Irp->IoStatus.Status);
  818. return Irp->IoStatus.Status;
  819. }
  820. VOID
  821. FatNonCachedNonAlignedRead (
  822. IN PIRP_CONTEXT IrpContext,
  823. IN PIRP Irp,
  824. IN PFCB FcbOrDcb,
  825. IN ULONG StartingVbo,
  826. IN ULONG ByteCount
  827. )
  828. /*++
  829. Routine Description:
  830. This routine performs the non-cached disk io described in its parameters.
  831. This routine differs from the above in that the range does not have to be
  832. sector aligned. This accomplished with the use of intermediate buffers.
  833. Arguments:
  834. IrpContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
  835. Irp - Supplies the requesting Irp.
  836. FcbOrDcb - Supplies the file to act on.
  837. StartingVbo - The starting point for the operation.
  838. ByteCount - The lengh of the operation.
  839. Return Value:
  840. None.
  841. --*/
  842. {
  843. //
  844. // Declare some local variables for enumeration through the
  845. // runs of the file, and an array to store parameters for
  846. // parallel I/Os
  847. //
  848. LBO NextLbo;
  849. ULONG NextByteCount;
  850. BOOLEAN NextIsAllocated;
  851. ULONG SectorSize;
  852. ULONG BytesToCopy;
  853. ULONG OriginalByteCount;
  854. ULONG OriginalStartingVbo;
  855. BOOLEAN EndOnMax;
  856. PUCHAR UserBuffer;
  857. PUCHAR DiskBuffer = NULL;
  858. PMDL Mdl;
  859. PMDL SavedMdl;
  860. PVOID SavedUserBuffer;
  861. DebugTrace(+1, Dbg, "FatNonCachedNonAlignedRead\n", 0);
  862. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  863. DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", IrpContext->MajorFunction );
  864. DebugTrace( 0, Dbg, "FcbOrDcb = %08lx\n", FcbOrDcb );
  865. DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo );
  866. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount );
  867. //
  868. // Initialize some locals.
  869. //
  870. OriginalByteCount = ByteCount;
  871. OriginalStartingVbo = StartingVbo;
  872. SectorSize = FcbOrDcb->Vcb->Bpb.BytesPerSector;
  873. ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
  874. //
  875. // For nonbuffered I/O, we need the buffer locked in all
  876. // cases.
  877. //
  878. // This call may raise. If this call succeeds and a subsequent
  879. // condition is raised, the buffers are unlocked automatically
  880. // by the I/O system when the request is completed, via the
  881. // Irp->MdlAddress field.
  882. //
  883. FatLockUserBuffer( IrpContext,
  884. Irp,
  885. IoWriteAccess,
  886. ByteCount );
  887. UserBuffer = FatMapUserBuffer( IrpContext, Irp );
  888. //
  889. // Allocate the local buffer
  890. //
  891. DiskBuffer = FsRtlAllocatePoolWithTag( NonPagedPoolCacheAligned,
  892. (ULONG) ROUND_TO_PAGES( SectorSize ),
  893. TAG_IO_BUFFER );
  894. //
  895. // We use a try block here to ensure the buffer is freed, and to
  896. // fill in the correct byte count in the Iosb.Information field.
  897. //
  898. try {
  899. //
  900. // If the beginning of the request was not aligned correctly, read in
  901. // the first part first.
  902. //
  903. if ( StartingVbo & (SectorSize - 1) ) {
  904. VBO Hole;
  905. //
  906. // Try to lookup the first run.
  907. //
  908. FatLookupFileAllocation( IrpContext,
  909. FcbOrDcb,
  910. StartingVbo,
  911. &NextLbo,
  912. &NextByteCount,
  913. &NextIsAllocated,
  914. &EndOnMax,
  915. NULL );
  916. //
  917. // We just added the allocation, thus there must be at least
  918. // one entry in the mcb corresponding to our write, ie.
  919. // NextIsAllocated must be true. If not, the pre-existing file
  920. // must have an allocation error.
  921. //
  922. if ( !NextIsAllocated ) {
  923. FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
  924. FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  925. }
  926. FatSingleNonAlignedSync( IrpContext,
  927. FcbOrDcb->Vcb,
  928. DiskBuffer,
  929. NextLbo & ~((LONG)SectorSize - 1),
  930. SectorSize,
  931. Irp );
  932. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  933. try_return( NOTHING );
  934. }
  935. //
  936. // Now copy the part of the first sector that we want to the user
  937. // buffer.
  938. //
  939. Hole = StartingVbo & (SectorSize - 1);
  940. BytesToCopy = ByteCount >= SectorSize - Hole ?
  941. SectorSize - Hole : ByteCount;
  942. RtlCopyMemory( UserBuffer, DiskBuffer + Hole, BytesToCopy );
  943. StartingVbo += BytesToCopy;
  944. ByteCount -= BytesToCopy;
  945. if ( ByteCount == 0 ) {
  946. try_return( NOTHING );
  947. }
  948. }
  949. ASSERT( (StartingVbo & (SectorSize - 1)) == 0 );
  950. //
  951. // If there is a tail part that is not sector aligned, read it.
  952. //
  953. if ( ByteCount & (SectorSize - 1) ) {
  954. VBO LastSectorVbo;
  955. LastSectorVbo = StartingVbo + (ByteCount & ~(SectorSize - 1));
  956. //
  957. // Try to lookup the last part of the requested range.
  958. //
  959. FatLookupFileAllocation( IrpContext,
  960. FcbOrDcb,
  961. LastSectorVbo,
  962. &NextLbo,
  963. &NextByteCount,
  964. &NextIsAllocated,
  965. &EndOnMax,
  966. NULL );
  967. //
  968. // We just added the allocation, thus there must be at least
  969. // one entry in the mcb corresponding to our write, ie.
  970. // NextIsAllocated must be true. If not, the pre-existing file
  971. // must have an allocation error.
  972. //
  973. if ( !NextIsAllocated ) {
  974. FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
  975. FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  976. }
  977. FatSingleNonAlignedSync( IrpContext,
  978. FcbOrDcb->Vcb,
  979. DiskBuffer,
  980. NextLbo,
  981. SectorSize,
  982. Irp );
  983. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  984. try_return( NOTHING );
  985. }
  986. //
  987. // Now copy over the part of this last sector that we need.
  988. //
  989. BytesToCopy = ByteCount & (SectorSize - 1);
  990. UserBuffer += LastSectorVbo - OriginalStartingVbo;
  991. RtlCopyMemory( UserBuffer, DiskBuffer, BytesToCopy );
  992. ByteCount -= BytesToCopy;
  993. if ( ByteCount == 0 ) {
  994. try_return( NOTHING );
  995. }
  996. }
  997. ASSERT( ((StartingVbo | ByteCount) & (SectorSize - 1)) == 0 );
  998. //
  999. // Now build a Mdl describing the sector aligned balance of the transfer,
  1000. // and put it in the Irp, and read that part.
  1001. //
  1002. SavedMdl = Irp->MdlAddress;
  1003. Irp->MdlAddress = NULL;
  1004. SavedUserBuffer = Irp->UserBuffer;
  1005. Irp->UserBuffer = (PUCHAR)MmGetMdlVirtualAddress( SavedMdl ) +
  1006. (StartingVbo - OriginalStartingVbo);
  1007. Mdl = IoAllocateMdl( Irp->UserBuffer,
  1008. ByteCount,
  1009. FALSE,
  1010. FALSE,
  1011. Irp );
  1012. if (Mdl == NULL) {
  1013. Irp->MdlAddress = SavedMdl;
  1014. Irp->UserBuffer = SavedUserBuffer;
  1015. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1016. }
  1017. IoBuildPartialMdl( SavedMdl,
  1018. Mdl,
  1019. Irp->UserBuffer,
  1020. ByteCount );
  1021. //
  1022. // Try to read in the pages.
  1023. //
  1024. try {
  1025. FatNonCachedIo( IrpContext,
  1026. Irp,
  1027. FcbOrDcb,
  1028. StartingVbo,
  1029. ByteCount,
  1030. ByteCount );
  1031. } finally {
  1032. IoFreeMdl( Irp->MdlAddress );
  1033. Irp->MdlAddress = SavedMdl;
  1034. Irp->UserBuffer = SavedUserBuffer;
  1035. }
  1036. try_exit: NOTHING;
  1037. } finally {
  1038. ExFreePool( DiskBuffer );
  1039. if ( !AbnormalTermination() && NT_SUCCESS(Irp->IoStatus.Status) ) {
  1040. Irp->IoStatus.Information = OriginalByteCount;
  1041. //
  1042. // We now flush the user's buffer to memory.
  1043. //
  1044. KeFlushIoBuffers( Irp->MdlAddress, TRUE, FALSE );
  1045. }
  1046. }
  1047. DebugTrace(-1, Dbg, "FatNonCachedNonAlignedRead -> VOID\n", 0);
  1048. return;
  1049. }
  1050. VOID
  1051. FatMultipleAsync (
  1052. IN PIRP_CONTEXT IrpContext,
  1053. IN PVCB Vcb,
  1054. IN PIRP MasterIrp,
  1055. IN ULONG MultipleIrpCount,
  1056. IN PIO_RUN IoRuns
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. This routine first does the initial setup required of a Master IRP that is
  1061. going to be completed using associated IRPs. This routine should not
  1062. be used if only one async request is needed, instead the single read/write
  1063. async routines should be called.
  1064. A context parameter is initialized, to serve as a communications area
  1065. between here and the common completion routine. This initialization
  1066. includes allocation of a spinlock. The spinlock is deallocated in the
  1067. FatWaitSync routine, so it is essential that the caller insure that
  1068. this routine is always called under all circumstances following a call
  1069. to this routine.
  1070. Next this routine reads or writes one or more contiguous sectors from
  1071. a device asynchronously, and is used if there are multiple reads for a
  1072. master IRP. A completion routine is used to synchronize with the
  1073. completion of all of the I/O requests started by calls to this routine.
  1074. Also, prior to calling this routine the caller must initialize the
  1075. IoStatus field in the Context, with the correct success status and byte
  1076. count which are expected if all of the parallel transfers complete
  1077. successfully. After return this status will be unchanged if all requests
  1078. were, in fact, successful. However, if one or more errors occur, the
  1079. IoStatus will be modified to reflect the error status and byte count
  1080. from the first run (by Vbo) which encountered an error. I/O status
  1081. from all subsequent runs will not be indicated.
  1082. Arguments:
  1083. IrpContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
  1084. Vcb - Supplies the device to be read
  1085. MasterIrp - Supplies the master Irp.
  1086. MulitpleIrpCount - Supplies the number of multiple async requests
  1087. that will be issued against the master irp.
  1088. IoRuns - Supplies an array containing the Vbo, Lbo, BufferOffset, and
  1089. ByteCount for all the runs to executed in parallel.
  1090. Return Value:
  1091. None.
  1092. --*/
  1093. {
  1094. PIRP Irp;
  1095. PIO_STACK_LOCATION IrpSp;
  1096. PMDL Mdl;
  1097. BOOLEAN Wait;
  1098. PFAT_IO_CONTEXT Context;
  1099. ULONG UnwindRunCount = 0;
  1100. BOOLEAN ExceptionExpected = TRUE;
  1101. BOOLEAN CalledByFatVerifyVolume = FALSE;
  1102. DebugTrace(+1, Dbg, "FatMultipleAsync\n", 0);
  1103. DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", IrpContext->MajorFunction );
  1104. DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
  1105. DebugTrace( 0, Dbg, "MasterIrp = %08lx\n", MasterIrp );
  1106. DebugTrace( 0, Dbg, "MultipleIrpCount = %08lx\n", MultipleIrpCount );
  1107. DebugTrace( 0, Dbg, "IoRuns = %08lx\n", IoRuns );
  1108. //
  1109. // If this I/O originating during FatVerifyVolume, bypass the
  1110. // verify logic.
  1111. //
  1112. if ( Vcb->VerifyThread == KeGetCurrentThread() ) {
  1113. CalledByFatVerifyVolume = TRUE;
  1114. }
  1115. //
  1116. // Set up things according to whether this is truely async.
  1117. //
  1118. Wait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  1119. Context = IrpContext->FatIoContext;
  1120. //
  1121. // Finish initializing Context, for use in Read/Write Multiple Asynch.
  1122. //
  1123. Context->MasterIrp = MasterIrp;
  1124. try {
  1125. //
  1126. // Itterate through the runs, doing everything that can fail
  1127. //
  1128. for ( UnwindRunCount = 0;
  1129. UnwindRunCount < MultipleIrpCount;
  1130. UnwindRunCount++ ) {
  1131. //
  1132. // Create an associated IRP, making sure there is one stack entry for
  1133. // us, as well.
  1134. //
  1135. IoRuns[UnwindRunCount].SavedIrp = 0;
  1136. Irp = IoMakeAssociatedIrp( MasterIrp,
  1137. (CCHAR)(Vcb->TargetDeviceObject->StackSize + 1) );
  1138. if (Irp == NULL) {
  1139. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1140. }
  1141. IoRuns[UnwindRunCount].SavedIrp = Irp;
  1142. //
  1143. // Allocate and build a partial Mdl for the request.
  1144. //
  1145. Mdl = IoAllocateMdl( (PCHAR)MasterIrp->UserBuffer +
  1146. IoRuns[UnwindRunCount].Offset,
  1147. IoRuns[UnwindRunCount].ByteCount,
  1148. FALSE,
  1149. FALSE,
  1150. Irp );
  1151. if (Mdl == NULL) {
  1152. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1153. }
  1154. //
  1155. // Sanity Check
  1156. //
  1157. ASSERT( Mdl == Irp->MdlAddress );
  1158. IoBuildPartialMdl( MasterIrp->MdlAddress,
  1159. Mdl,
  1160. (PCHAR)MasterIrp->UserBuffer +
  1161. IoRuns[UnwindRunCount].Offset,
  1162. IoRuns[UnwindRunCount].ByteCount );
  1163. //
  1164. // Get the first IRP stack location in the associated Irp
  1165. //
  1166. IoSetNextIrpStackLocation( Irp );
  1167. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1168. //
  1169. // Setup the Stack location to describe our read.
  1170. //
  1171. IrpSp->MajorFunction = IrpContext->MajorFunction;
  1172. IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].ByteCount;
  1173. IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].Vbo;
  1174. //
  1175. // Set up the completion routine address in our stack frame.
  1176. //
  1177. IoSetCompletionRoutine( Irp,
  1178. Wait ?
  1179. &FatMultiSyncCompletionRoutine :
  1180. &FatMultiAsyncCompletionRoutine,
  1181. Context,
  1182. TRUE,
  1183. TRUE,
  1184. TRUE );
  1185. //
  1186. // Setup the next IRP stack location in the associated Irp for the disk
  1187. // driver beneath us.
  1188. //
  1189. IrpSp = IoGetNextIrpStackLocation( Irp );
  1190. //
  1191. // Setup the Stack location to do a read from the disk driver.
  1192. //
  1193. IrpSp->MajorFunction = IrpContext->MajorFunction;
  1194. IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].ByteCount;
  1195. IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].Lbo;
  1196. //
  1197. // If this Irp is the result of a WriteThough operation,
  1198. // tell the device to write it through.
  1199. //
  1200. if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) {
  1201. SetFlag( IrpSp->Flags, SL_WRITE_THROUGH );
  1202. }
  1203. //
  1204. // If this I/O originating during FatVerifyVolume, bypass the
  1205. // verify logic.
  1206. //
  1207. if ( CalledByFatVerifyVolume ) {
  1208. SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  1209. }
  1210. }
  1211. //
  1212. // Now we no longer expect an exception. If the driver raises, we
  1213. // must bugcheck, because we do not know how to recover from that
  1214. // case.
  1215. //
  1216. ExceptionExpected = FALSE;
  1217. //
  1218. // We only need to set the associated IRP count in the master irp to
  1219. // make it a master IRP. But we set the count to one more than our
  1220. // caller requested, because we do not want the I/O system to complete
  1221. // the I/O. We also set our own count.
  1222. //
  1223. Context->IrpCount = MultipleIrpCount;
  1224. MasterIrp->AssociatedIrp.IrpCount = MultipleIrpCount;
  1225. if (Wait) {
  1226. MasterIrp->AssociatedIrp.IrpCount += 1;
  1227. }
  1228. //
  1229. // Now that all the dangerous work is done, issue the read requests
  1230. //
  1231. for (UnwindRunCount = 0;
  1232. UnwindRunCount < MultipleIrpCount;
  1233. UnwindRunCount++) {
  1234. Irp = IoRuns[UnwindRunCount].SavedIrp;
  1235. DebugDoit( FatIoCallDriverCount += 1);
  1236. //
  1237. // If IoCallDriver returns an error, it has completed the Irp
  1238. // and the error will be caught by our completion routines
  1239. // and dealt with as a normal IO error.
  1240. //
  1241. (VOID)FatLowLevelReadWrite( IrpContext,
  1242. Vcb->TargetDeviceObject,
  1243. Irp,
  1244. Vcb );
  1245. }
  1246. } finally {
  1247. ULONG i;
  1248. DebugUnwind( FatMultipleAsync );
  1249. //
  1250. // Only allocating the spinlock, making the associated Irps
  1251. // and allocating the Mdls can fail.
  1252. //
  1253. if ( AbnormalTermination() ) {
  1254. //
  1255. // If the driver raised, we are hosed. He is not supposed to raise,
  1256. // and it is impossible for us to figure out how to clean up.
  1257. //
  1258. if (!ExceptionExpected) {
  1259. ASSERT( ExceptionExpected );
  1260. FatBugCheck( 0, 0, 0 );
  1261. }
  1262. //
  1263. // Unwind
  1264. //
  1265. for (i = 0; i <= UnwindRunCount; i++) {
  1266. if ( (Irp = IoRuns[i].SavedIrp) != NULL ) {
  1267. if ( Irp->MdlAddress != NULL ) {
  1268. IoFreeMdl( Irp->MdlAddress );
  1269. }
  1270. IoFreeIrp( Irp );
  1271. }
  1272. }
  1273. }
  1274. //
  1275. // And return to our caller
  1276. //
  1277. DebugTrace(-1, Dbg, "FatMultipleAsync -> VOID\n", 0);
  1278. }
  1279. return;
  1280. }
  1281. VOID
  1282. FatSingleAsync (
  1283. IN PIRP_CONTEXT IrpContext,
  1284. IN PVCB Vcb,
  1285. IN LBO Lbo,
  1286. IN ULONG ByteCount,
  1287. IN PIRP Irp
  1288. )
  1289. /*++
  1290. Routine Description:
  1291. This routine reads or writes one or more contiguous sectors from a device
  1292. asynchronously, and is used if there is only one read necessary to
  1293. complete the IRP. It implements the read by simply filling
  1294. in the next stack frame in the Irp, and passing it on. The transfer
  1295. occurs to the single buffer originally specified in the user request.
  1296. Arguments:
  1297. IrpContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
  1298. Vcb - Supplies the device to read
  1299. Lbo - Supplies the starting Logical Byte Offset to begin reading from
  1300. ByteCount - Supplies the number of bytes to read from the device
  1301. Irp - Supplies the master Irp to associated with the async
  1302. request.
  1303. Return Value:
  1304. None.
  1305. --*/
  1306. {
  1307. PIO_STACK_LOCATION IrpSp;
  1308. DebugTrace(+1, Dbg, "FatSingleAsync\n", 0);
  1309. DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", IrpContext->MajorFunction );
  1310. DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
  1311. DebugTrace( 0, Dbg, "Lbo = %08lx\n", Lbo);
  1312. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
  1313. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  1314. //
  1315. // Set up the completion routine address in our stack frame.
  1316. //
  1317. IoSetCompletionRoutine( Irp,
  1318. FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ?
  1319. &FatSingleSyncCompletionRoutine :
  1320. &FatSingleAsyncCompletionRoutine,
  1321. IrpContext->FatIoContext,
  1322. TRUE,
  1323. TRUE,
  1324. TRUE );
  1325. //
  1326. // Setup the next IRP stack location in the associated Irp for the disk
  1327. // driver beneath us.
  1328. //
  1329. IrpSp = IoGetNextIrpStackLocation( Irp );
  1330. //
  1331. // Setup the Stack location to do a read from the disk driver.
  1332. //
  1333. IrpSp->MajorFunction = IrpContext->MajorFunction;
  1334. IrpSp->Parameters.Read.Length = ByteCount;
  1335. IrpSp->Parameters.Read.ByteOffset.QuadPart = Lbo;
  1336. //
  1337. // If this Irp is the result of a WriteThough operation,
  1338. // tell the device to write it through.
  1339. //
  1340. if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) {
  1341. SetFlag( IrpSp->Flags, SL_WRITE_THROUGH );
  1342. }
  1343. //
  1344. // If this I/O originating during FatVerifyVolume, bypass the
  1345. // verify logic.
  1346. //
  1347. if ( Vcb->VerifyThread == KeGetCurrentThread() ) {
  1348. SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  1349. }
  1350. //
  1351. // Issue the read request
  1352. //
  1353. DebugDoit( FatIoCallDriverCount += 1);
  1354. //
  1355. // If IoCallDriver returns an error, it has completed the Irp
  1356. // and the error will be caught by our completion routines
  1357. // and dealt with as a normal IO error.
  1358. //
  1359. (VOID)FatLowLevelReadWrite( IrpContext,
  1360. Vcb->TargetDeviceObject,
  1361. Irp,
  1362. Vcb );
  1363. //
  1364. // And return to our caller
  1365. //
  1366. DebugTrace(-1, Dbg, "FatSingleAsync -> VOID\n", 0);
  1367. return;
  1368. }
  1369. VOID
  1370. FatSingleNonAlignedSync (
  1371. IN PIRP_CONTEXT IrpContext,
  1372. IN PVCB Vcb,
  1373. IN PUCHAR Buffer,
  1374. IN LBO Lbo,
  1375. IN ULONG ByteCount,
  1376. IN PIRP Irp
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. This routine reads or writes one or more contiguous sectors from a device
  1381. Synchronously, and does so to a buffer that must come from non paged
  1382. pool. It saves a pointer to the Irp's original Mdl, and creates a new
  1383. one describing the given buffer. It implements the read by simply filling
  1384. in the next stack frame in the Irp, and passing it on. The transfer
  1385. occurs to the single buffer originally specified in the user request.
  1386. Arguments:
  1387. IrpContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
  1388. Vcb - Supplies the device to read
  1389. Buffer - Supplies a buffer from non-paged pool.
  1390. Lbo - Supplies the starting Logical Byte Offset to begin reading from
  1391. ByteCount - Supplies the number of bytes to read from the device
  1392. Irp - Supplies the master Irp to associated with the async
  1393. request.
  1394. Return Value:
  1395. None.
  1396. --*/
  1397. {
  1398. PIO_STACK_LOCATION IrpSp;
  1399. PMDL Mdl;
  1400. PMDL SavedMdl;
  1401. DebugTrace(+1, Dbg, "FatSingleNonAlignedAsync\n", 0);
  1402. DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", IrpContext->MajorFunction );
  1403. DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
  1404. DebugTrace( 0, Dbg, "Buffer = %08lx\n", Buffer );
  1405. DebugTrace( 0, Dbg, "Lbo = %08lx\n", Lbo);
  1406. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
  1407. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  1408. //
  1409. // Create a new Mdl describing the buffer, saving the current one in the
  1410. // Irp
  1411. //
  1412. SavedMdl = Irp->MdlAddress;
  1413. Irp->MdlAddress = 0;
  1414. Mdl = IoAllocateMdl( Buffer,
  1415. ByteCount,
  1416. FALSE,
  1417. FALSE,
  1418. Irp );
  1419. if (Mdl == NULL) {
  1420. Irp->MdlAddress = SavedMdl;
  1421. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1422. }
  1423. //
  1424. // Lock the new Mdl in memory.
  1425. //
  1426. try {
  1427. MmProbeAndLockPages( Mdl, KernelMode, IoWriteAccess );
  1428. } finally {
  1429. if ( AbnormalTermination() ) {
  1430. IoFreeMdl( Mdl );
  1431. Irp->MdlAddress = SavedMdl;
  1432. }
  1433. }
  1434. //
  1435. // Set up the completion routine address in our stack frame.
  1436. //
  1437. IoSetCompletionRoutine( Irp,
  1438. &FatSingleSyncCompletionRoutine,
  1439. IrpContext->FatIoContext,
  1440. TRUE,
  1441. TRUE,
  1442. TRUE );
  1443. //
  1444. // Setup the next IRP stack location in the associated Irp for the disk
  1445. // driver beneath us.
  1446. //
  1447. IrpSp = IoGetNextIrpStackLocation( Irp );
  1448. //
  1449. // Setup the Stack location to do a read from the disk driver.
  1450. //
  1451. IrpSp->MajorFunction = IrpContext->MajorFunction;
  1452. IrpSp->Parameters.Read.Length = ByteCount;
  1453. IrpSp->Parameters.Read.ByteOffset.QuadPart = Lbo;
  1454. //
  1455. // If this I/O originating during FatVerifyVolume, bypass the
  1456. // verify logic.
  1457. //
  1458. if ( Vcb->VerifyThread == KeGetCurrentThread() ) {
  1459. SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  1460. }
  1461. //
  1462. // Issue the read request
  1463. //
  1464. DebugDoit( FatIoCallDriverCount += 1);
  1465. //
  1466. // If IoCallDriver returns an error, it has completed the Irp
  1467. // and the error will be caught by our completion routines
  1468. // and dealt with as a normal IO error.
  1469. //
  1470. try {
  1471. (VOID)FatLowLevelReadWrite( IrpContext,
  1472. Vcb->TargetDeviceObject,
  1473. Irp,
  1474. Vcb );
  1475. FatWaitSync( IrpContext );
  1476. } finally {
  1477. MmUnlockPages( Mdl );
  1478. IoFreeMdl( Mdl );
  1479. Irp->MdlAddress = SavedMdl;
  1480. }
  1481. //
  1482. // And return to our caller
  1483. //
  1484. DebugTrace(-1, Dbg, "FatSingleNonAlignedSync -> VOID\n", 0);
  1485. return;
  1486. }
  1487. VOID
  1488. FatWaitSync (
  1489. IN PIRP_CONTEXT IrpContext
  1490. )
  1491. /*++
  1492. Routine Description:
  1493. This routine waits for one or more previously started I/O requests
  1494. from the above routines, by simply waiting on the event.
  1495. Arguments:
  1496. Return Value:
  1497. None
  1498. --*/
  1499. {
  1500. DebugTrace(+1, Dbg, "FatWaitSync, Context = %08lx\n", IrpContext->FatIoContext );
  1501. KeWaitForSingleObject( &IrpContext->FatIoContext->Wait.SyncEvent,
  1502. Executive, KernelMode, FALSE, NULL );
  1503. KeClearEvent( &IrpContext->FatIoContext->Wait.SyncEvent );
  1504. DebugTrace(-1, Dbg, "FatWaitSync -> VOID\n", 0 );
  1505. }
  1506. //
  1507. // Internal Support Routine
  1508. //
  1509. NTSTATUS
  1510. FatMultiSyncCompletionRoutine (
  1511. IN PDEVICE_OBJECT DeviceObject,
  1512. IN PIRP Irp,
  1513. IN PVOID Contxt
  1514. )
  1515. /*++
  1516. Routine Description:
  1517. This is the completion routine for all reads and writes started via
  1518. FatRead/WriteMultipleAsynch. It must synchronize its operation for
  1519. multiprocessor environments with itself on all other processors, via
  1520. a spin lock found via the Context parameter.
  1521. The completion routine has the following responsibilities:
  1522. If the individual request was completed with an error, then
  1523. this completion routine must see if this is the first error
  1524. (essentially by Vbo), and if so it must correctly reduce the
  1525. byte count and remember the error status in the Context.
  1526. If the IrpCount goes to 1, then it sets the event in the Context
  1527. parameter to signal the caller that all of the asynch requests
  1528. are done.
  1529. Arguments:
  1530. DeviceObject - Pointer to the file system device object.
  1531. Irp - Pointer to the associated Irp which is being completed. (This
  1532. Irp will no longer be accessible after this routine returns.)
  1533. Contxt - The context parameter which was specified for all of
  1534. the multiple asynch I/O requests for this MasterIrp.
  1535. Return Value:
  1536. The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
  1537. immediately complete the Master Irp without being in a race condition
  1538. with the IoCompleteRequest thread trying to decrement the IrpCount in
  1539. the Master Irp.
  1540. --*/
  1541. {
  1542. PFAT_IO_CONTEXT Context = Contxt;
  1543. PIRP MasterIrp = Context->MasterIrp;
  1544. DebugTrace(+1, Dbg, "FatMultiSyncCompletionRoutine, Context = %08lx\n", Context );
  1545. //
  1546. // If we got an error (or verify required), remember it in the Irp
  1547. //
  1548. MasterIrp = Context->MasterIrp;
  1549. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  1550. ASSERT( NT_SUCCESS( FatAssertNotStatus ) || Irp->IoStatus.Status != FatAssertNotStatus );
  1551. #ifdef SYSCACHE_COMPILE
  1552. DbgPrint( "FAT SYSCACHE: MultiSync (IRP %08x for Master %08x) -> %08x\n", Irp, MasterIrp, Irp->IoStatus );
  1553. #endif
  1554. MasterIrp->IoStatus = Irp->IoStatus;
  1555. }
  1556. ASSERT( !(NT_SUCCESS( Irp->IoStatus.Status ) && Irp->IoStatus.Information == 0 ));
  1557. //
  1558. // We must do this here since IoCompleteRequest won't get a chance
  1559. // on this associated Irp.
  1560. //
  1561. IoFreeMdl( Irp->MdlAddress );
  1562. IoFreeIrp( Irp );
  1563. if (InterlockedDecrement(&Context->IrpCount) == 0) {
  1564. FatDoCompletionZero( MasterIrp, Context );
  1565. KeSetEvent( &Context->Wait.SyncEvent, 0, FALSE );
  1566. }
  1567. DebugTrace(-1, Dbg, "FatMultiSyncCompletionRoutine -> SUCCESS\n", 0 );
  1568. UNREFERENCED_PARAMETER( DeviceObject );
  1569. return STATUS_MORE_PROCESSING_REQUIRED;
  1570. }
  1571. //
  1572. // Internal Support Routine
  1573. //
  1574. NTSTATUS
  1575. FatMultiAsyncCompletionRoutine (
  1576. IN PDEVICE_OBJECT DeviceObject,
  1577. IN PIRP Irp,
  1578. IN PVOID Contxt
  1579. )
  1580. /*++
  1581. Routine Description:
  1582. This is the completion routine for all reads and writes started via
  1583. FatRead/WriteMultipleAsynch. It must synchronize its operation for
  1584. multiprocessor environments with itself on all other processors, via
  1585. a spin lock found via the Context parameter.
  1586. The completion routine has has the following responsibilities:
  1587. If the individual request was completed with an error, then
  1588. this completion routine must see if this is the first error
  1589. (essentially by Vbo), and if so it must correctly reduce the
  1590. byte count and remember the error status in the Context.
  1591. If the IrpCount goes to 1, then it sets the event in the Context
  1592. parameter to signal the caller that all of the asynch requests
  1593. are done.
  1594. Arguments:
  1595. DeviceObject - Pointer to the file system device object.
  1596. Irp - Pointer to the associated Irp which is being completed. (This
  1597. Irp will no longer be accessible after this routine returns.)
  1598. Contxt - The context parameter which was specified for all of
  1599. the multiple asynch I/O requests for this MasterIrp.
  1600. Return Value:
  1601. The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
  1602. immediately complete the Master Irp without being in a race condition
  1603. with the IoCompleteRequest thread trying to decrement the IrpCount in
  1604. the Master Irp.
  1605. --*/
  1606. {
  1607. PFAT_IO_CONTEXT Context = Contxt;
  1608. PIRP MasterIrp = Context->MasterIrp;
  1609. DebugTrace(+1, Dbg, "FatMultiAsyncCompletionRoutine, Context = %08lx\n", Context );
  1610. //
  1611. // If we got an error (or verify required), remember it in the Irp
  1612. //
  1613. MasterIrp = Context->MasterIrp;
  1614. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  1615. ASSERT( NT_SUCCESS( FatAssertNotStatus ) || Irp->IoStatus.Status != FatAssertNotStatus );
  1616. #ifdef SYSCACHE_COMPILE
  1617. DbgPrint( "FAT SYSCACHE: MultiAsync (IRP %08x for Master %08x) -> %08x\n", Irp, MasterIrp, Irp->IoStatus );
  1618. #endif
  1619. MasterIrp->IoStatus = Irp->IoStatus;
  1620. }
  1621. ASSERT( !(NT_SUCCESS( Irp->IoStatus.Status ) && Irp->IoStatus.Information == 0 ));
  1622. if (InterlockedDecrement(&Context->IrpCount) == 0) {
  1623. FatDoCompletionZero( MasterIrp, Context );
  1624. if (NT_SUCCESS(MasterIrp->IoStatus.Status)) {
  1625. MasterIrp->IoStatus.Information =
  1626. Context->Wait.Async.RequestedByteCount;
  1627. ASSERT(MasterIrp->IoStatus.Information != 0);
  1628. //
  1629. // Now if this wasn't PagingIo, set either the read or write bit.
  1630. //
  1631. if (!FlagOn(MasterIrp->Flags, IRP_PAGING_IO)) {
  1632. SetFlag( Context->Wait.Async.FileObject->Flags,
  1633. IoGetCurrentIrpStackLocation(MasterIrp)->MajorFunction == IRP_MJ_READ ?
  1634. FO_FILE_FAST_IO_READ : FO_FILE_MODIFIED );
  1635. }
  1636. }
  1637. //
  1638. // If this was a special async write, decrement the count. Set the
  1639. // event if this was the final outstanding I/O for the file. We will
  1640. // also want to queue an APC to deal with any error conditionions.
  1641. //
  1642. if ((Context->Wait.Async.NonPagedFcb) &&
  1643. (ExInterlockedAddUlong( &Context->Wait.Async.NonPagedFcb->OutstandingAsyncWrites,
  1644. 0xffffffff,
  1645. &FatData.GeneralSpinLock ) == 1)) {
  1646. KeSetEvent( Context->Wait.Async.NonPagedFcb->OutstandingAsyncEvent, 0, FALSE );
  1647. }
  1648. //
  1649. // Now release the resources.
  1650. //
  1651. if (Context->Wait.Async.Resource != NULL) {
  1652. ExReleaseResourceForThreadLite( Context->Wait.Async.Resource,
  1653. Context->Wait.Async.ResourceThreadId );
  1654. }
  1655. if (Context->Wait.Async.Resource2 != NULL) {
  1656. ExReleaseResourceForThreadLite( Context->Wait.Async.Resource2,
  1657. Context->Wait.Async.ResourceThreadId );
  1658. }
  1659. //
  1660. // Mark the master Irp pending
  1661. //
  1662. IoMarkIrpPending( MasterIrp );
  1663. //
  1664. // and finally, free the context record.
  1665. //
  1666. ExFreePool( Context );
  1667. }
  1668. DebugTrace(-1, Dbg, "FatMultiAsyncCompletionRoutine -> SUCCESS\n", 0 );
  1669. UNREFERENCED_PARAMETER( DeviceObject );
  1670. return STATUS_SUCCESS;
  1671. }
  1672. NTSTATUS
  1673. FatPagingFileErrorHandler (
  1674. IN PIRP Irp,
  1675. IN PKEVENT Event OPTIONAL
  1676. )
  1677. /*++
  1678. Routine Description:
  1679. This routine attempts to guarantee that the media is marked dirty
  1680. with the surface test bit if a paging file IO fails.
  1681. The work done here has several basic problems
  1682. 1) when paging file writes start failing, this is a good sign
  1683. that the rest of the system is about to fall down around us
  1684. 2) it has no forward progress guarantee
  1685. With Whistler, it is actually quite intentional that we're rejiggering
  1686. the paging file write path to make forward progress at all times. This
  1687. means that the cases where it *does* fail, we're truly seeing media errors
  1688. and this is probably going to mean the paging file is going to stop working
  1689. very soon.
  1690. It'd be nice to make this guarantee progress. It would need
  1691. 1) a guaranteed worker thread which can only be used by items which
  1692. will make forward progress (i.e., not block out this one)
  1693. 2) the virtual volume file's pages containing the boot sector and
  1694. 1st FAT entry would have to be pinned resident and have a guaranteed
  1695. mapping address
  1696. 3) mark volume would have to have a stashed irp/mdl and roll the write
  1697. irp, or use a generalized mechanism to guarantee issue of the irp
  1698. 4) the lower stack would have to guarantee progress
  1699. Of these, 1 and 4 may actually exist shortly.
  1700. Arguments:
  1701. Irp - Pointer to the associated Irp which is being failed.
  1702. Event - Pointer to optional event to be signalled instead of completing
  1703. the IRP
  1704. Return Value:
  1705. Returns STATUS_MORE_PROCESSING_REQUIRED if we managed to queue off the workitem,
  1706. STATUS_SUCCESS otherwise.
  1707. --*/
  1708. {
  1709. NTSTATUS Status;
  1710. //
  1711. // If this was a media error, we want to chkdsk /r the next time we boot.
  1712. //
  1713. if (FsRtlIsTotalDeviceFailure(Irp->IoStatus.Status)) {
  1714. Status = STATUS_SUCCESS;
  1715. } else {
  1716. PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
  1717. //
  1718. // We are going to try to mark the volume needing recover.
  1719. // If we can't get pool, oh well....
  1720. //
  1721. Packet = ExAllocatePool(NonPagedPool, sizeof(CLEAN_AND_DIRTY_VOLUME_PACKET));
  1722. if ( Packet ) {
  1723. Packet->Vcb = &((PVOLUME_DEVICE_OBJECT)IoGetCurrentIrpStackLocation(Irp)->DeviceObject)->Vcb;
  1724. Packet->Irp = Irp;
  1725. Packet->Event = Event;
  1726. ExInitializeWorkItem( &Packet->Item,
  1727. &FatFspMarkVolumeDirtyWithRecover,
  1728. Packet );
  1729. ExQueueWorkItem( &Packet->Item, CriticalWorkQueue );
  1730. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1731. } else {
  1732. Status = STATUS_SUCCESS;
  1733. }
  1734. }
  1735. return Status;
  1736. }
  1737. //
  1738. // Internal Support Routine
  1739. //
  1740. NTSTATUS
  1741. FatPagingFileCompletionRoutineCatch (
  1742. IN PDEVICE_OBJECT DeviceObject,
  1743. IN PIRP Irp,
  1744. IN PVOID Contxt
  1745. )
  1746. /*++
  1747. Routine Description:
  1748. This is the completion routine for all reads and writes started via
  1749. FatPagingFileIo that reuse the master irp (that we have to catch
  1750. on the way back). It is always invoked.
  1751. The completion routine has has the following responsibility:
  1752. If the error implies a media problem, it enqueues a
  1753. worker item to write out the dirty bit so that the next
  1754. time we run we will do a autochk /r. This is not forward
  1755. progress guaranteed at the moment.
  1756. Clean up the Mdl used for this partial request.
  1757. Note that if the Irp is failing, the error code is already where
  1758. we want it.
  1759. Arguments:
  1760. DeviceObject - Pointer to the file system device object.
  1761. Irp - Pointer to the associated Irp which is being completed. (This
  1762. Irp will no longer be accessible after this routine returns.)
  1763. MasterIrp - Pointer to the master Irp.
  1764. Return Value:
  1765. Always returns STATUS_MORE_PROCESSING_REQUIRED.
  1766. --*/
  1767. {
  1768. PFAT_PAGING_FILE_CONTEXT Context = (PFAT_PAGING_FILE_CONTEXT) Contxt;
  1769. DebugTrace(+1, Dbg, "FatPagingFileCompletionRoutineCatch, Context = %08lx\n", Context );
  1770. //
  1771. // Cleanup the existing Mdl, perhaps by returning the reserve.
  1772. //
  1773. if (Irp->MdlAddress == FatReserveMdl) {
  1774. MmPrepareMdlForReuse( Irp->MdlAddress );
  1775. KeSetEvent( &FatReserveEvent, 0, FALSE );
  1776. } else {
  1777. IoFreeMdl( Irp->MdlAddress );
  1778. }
  1779. //
  1780. // Restore the original Mdl.
  1781. //
  1782. Irp->MdlAddress = Context->RestoreMdl;
  1783. DebugTrace(-1, Dbg, "FatPagingFileCompletionRoutine => (done)\n", 0 );
  1784. //
  1785. // If the IRP is succeeding or the failure handler did not post off the
  1786. // completion, we're done and should set the event to let the master
  1787. // know the IRP is his again.
  1788. //
  1789. if (NT_SUCCESS( Irp->IoStatus.Status ) ||
  1790. FatPagingFileErrorHandler( Irp, &Context->Event ) == STATUS_SUCCESS) {
  1791. KeSetEvent( &Context->Event, 0, FALSE );
  1792. }
  1793. return STATUS_MORE_PROCESSING_REQUIRED;
  1794. }
  1795. //
  1796. // Internal Support Routine
  1797. //
  1798. NTSTATUS
  1799. FatPagingFileCompletionRoutine (
  1800. IN PDEVICE_OBJECT DeviceObject,
  1801. IN PIRP Irp,
  1802. IN PVOID MasterIrp
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. This is the completion routine for all reads and writes started via
  1807. FatPagingFileIo. It should only be invoked on error or cancel.
  1808. The completion routine has has the following responsibility:
  1809. Since the individual request was completed with an error,
  1810. this completion routine must stuff it into the master irp.
  1811. If the error implies a media problem, it also enqueues a
  1812. worker item to write out the dirty bit so that the next
  1813. time we run we will do a autochk /r
  1814. Arguments:
  1815. DeviceObject - Pointer to the file system device object.
  1816. Irp - Pointer to the associated Irp which is being completed. (This
  1817. Irp will no longer be accessible after this routine returns.)
  1818. MasterIrp - Pointer to the master Irp.
  1819. Return Value:
  1820. Always returns STATUS_SUCCESS.
  1821. --*/
  1822. {
  1823. NTSTATUS Status;
  1824. DebugTrace(+1, Dbg, "FatPagingFileCompletionRoutine, MasterIrp = %08lx\n", MasterIrp );
  1825. //
  1826. // If we got an error (or verify required), remember it in the Irp
  1827. //
  1828. ASSERT( !NT_SUCCESS( Irp->IoStatus.Status ));
  1829. //
  1830. // If we were invoked with an assoicated Irp, copy the error over.
  1831. //
  1832. if (Irp != MasterIrp) {
  1833. ((PIRP)MasterIrp)->IoStatus = Irp->IoStatus;
  1834. }
  1835. DebugTrace(-1, Dbg, "FatPagingFileCompletionRoutine => (done)\n", 0 );
  1836. UNREFERENCED_PARAMETER( DeviceObject );
  1837. return FatPagingFileErrorHandler( Irp, NULL );
  1838. }
  1839. //
  1840. // Internal Support Routine
  1841. //
  1842. NTSTATUS
  1843. FatSpecialSyncCompletionRoutine (
  1844. IN PDEVICE_OBJECT DeviceObject,
  1845. IN PIRP Irp,
  1846. IN PVOID Contxt
  1847. )
  1848. /*++
  1849. Routine Description:
  1850. This is the completion routine for a special set of sub irps
  1851. that have to work at APC level.
  1852. The completion routine has has the following responsibilities:
  1853. It sets the event passed as the context to signal that the
  1854. request is done.
  1855. By doing this, the caller will be released before final APC
  1856. completion with knowledge that the IRP is finished. Final
  1857. completion will occur at an indeterminate time after this
  1858. occurs, and by using this completion routine the caller expects
  1859. to not have any output or status returned. A junk user Iosb
  1860. should be used to capture the status without forcing Io to take
  1861. an exception on NULL.
  1862. Arguments:
  1863. DeviceObject - Pointer to the file system device object.
  1864. Irp - Pointer to the Irp for this request. (This Irp will no longer
  1865. be accessible after this routine returns.)
  1866. Contxt - The context parameter which was specified in the call to
  1867. FatRead/WriteSingleAsynch.
  1868. Return Value:
  1869. Currently always returns STATUS_SUCCESS.
  1870. --*/
  1871. {
  1872. PKEVENT Event = (PKEVENT)Contxt;
  1873. DebugTrace(+1, Dbg, "FatSpecialSyncCompletionRoutine, Context = %08lx\n", Contxt );
  1874. KeSetEvent( Event, 0, FALSE );
  1875. DebugTrace(-1, Dbg, "FatSpecialSyncCompletionRoutine -> STATUS_SUCCESS\n", 0 );
  1876. UNREFERENCED_PARAMETER( DeviceObject );
  1877. return STATUS_SUCCESS;
  1878. }
  1879. //
  1880. // Internal Support Routine
  1881. //
  1882. NTSTATUS
  1883. FatSingleSyncCompletionRoutine (
  1884. IN PDEVICE_OBJECT DeviceObject,
  1885. IN PIRP Irp,
  1886. IN PVOID Contxt
  1887. )
  1888. /*++
  1889. Routine Description:
  1890. This is the completion routine for all reads and writes started via
  1891. FatRead/WriteSingleAsynch.
  1892. The completion routine has has the following responsibilities:
  1893. Copy the I/O status from the Irp to the Context, since the Irp
  1894. will no longer be accessible.
  1895. It sets the event in the Context parameter to signal the caller
  1896. that all of the asynch requests are done.
  1897. Arguments:
  1898. DeviceObject - Pointer to the file system device object.
  1899. Irp - Pointer to the Irp for this request. (This Irp will no longer
  1900. be accessible after this routine returns.)
  1901. Contxt - The context parameter which was specified in the call to
  1902. FatRead/WriteSingleAsynch.
  1903. Return Value:
  1904. Currently always returns STATUS_SUCCESS.
  1905. --*/
  1906. {
  1907. PFAT_IO_CONTEXT Context = Contxt;
  1908. DebugTrace(+1, Dbg, "FatSingleSyncCompletionRoutine, Context = %08lx\n", Context );
  1909. FatDoCompletionZero( Irp, Context );
  1910. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  1911. ASSERT( NT_SUCCESS( FatAssertNotStatus ) || Irp->IoStatus.Status != FatAssertNotStatus );
  1912. }
  1913. ASSERT( !(NT_SUCCESS( Irp->IoStatus.Status ) && Irp->IoStatus.Information == 0 ));
  1914. KeSetEvent( &Context->Wait.SyncEvent, 0, FALSE );
  1915. DebugTrace(-1, Dbg, "FatSingleSyncCompletionRoutine -> STATUS_MORE_PROCESSING_REQUIRED\n", 0 );
  1916. UNREFERENCED_PARAMETER( DeviceObject );
  1917. return STATUS_MORE_PROCESSING_REQUIRED;
  1918. }
  1919. //
  1920. // Internal Support Routine
  1921. //
  1922. NTSTATUS
  1923. FatSingleAsyncCompletionRoutine (
  1924. IN PDEVICE_OBJECT DeviceObject,
  1925. IN PIRP Irp,
  1926. IN PVOID Contxt
  1927. )
  1928. /*++
  1929. Routine Description:
  1930. This is the completion routine for all reads and writes started via
  1931. FatRead/WriteSingleAsynch.
  1932. The completion routine has has the following responsibilities:
  1933. Copy the I/O status from the Irp to the Context, since the Irp
  1934. will no longer be accessible.
  1935. It sets the event in the Context parameter to signal the caller
  1936. that all of the asynch requests are done.
  1937. Arguments:
  1938. DeviceObject - Pointer to the file system device object.
  1939. Irp - Pointer to the Irp for this request. (This Irp will no longer
  1940. be accessible after this routine returns.)
  1941. Contxt - The context parameter which was specified in the call to
  1942. FatRead/WriteSingleAsynch.
  1943. Return Value:
  1944. Currently always returns STATUS_SUCCESS.
  1945. --*/
  1946. {
  1947. PFAT_IO_CONTEXT Context = Contxt;
  1948. DebugTrace(+1, Dbg, "FatSingleAsyncCompletionRoutine, Context = %08lx\n", Context );
  1949. //
  1950. // Fill in the information field correctedly if this worked.
  1951. //
  1952. FatDoCompletionZero( Irp, Context );
  1953. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  1954. ASSERT( Irp->IoStatus.Information != 0 );
  1955. Irp->IoStatus.Information = Context->Wait.Async.RequestedByteCount;
  1956. ASSERT( Irp->IoStatus.Information != 0 );
  1957. //
  1958. // Now if this wasn't PagingIo, set either the read or write bit.
  1959. //
  1960. if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  1961. SetFlag( Context->Wait.Async.FileObject->Flags,
  1962. IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_READ ?
  1963. FO_FILE_FAST_IO_READ : FO_FILE_MODIFIED );
  1964. }
  1965. } else {
  1966. ASSERT( NT_SUCCESS( FatAssertNotStatus ) || Irp->IoStatus.Status != FatAssertNotStatus );
  1967. #ifdef SYSCACHE_COMPILE
  1968. DbgPrint( "FAT SYSCACHE: SingleAsync (IRP %08x) -> %08x\n", Irp, Irp->IoStatus );
  1969. #endif
  1970. }
  1971. //
  1972. // If this was a special async write, decrement the count. Set the
  1973. // event if this was the final outstanding I/O for the file. We will
  1974. // also want to queue an APC to deal with any error conditionions.
  1975. //
  1976. if ((Context->Wait.Async.NonPagedFcb) &&
  1977. (ExInterlockedAddUlong( &Context->Wait.Async.NonPagedFcb->OutstandingAsyncWrites,
  1978. 0xffffffff,
  1979. &FatData.GeneralSpinLock ) == 1)) {
  1980. KeSetEvent( Context->Wait.Async.NonPagedFcb->OutstandingAsyncEvent, 0, FALSE );
  1981. }
  1982. //
  1983. // Now release the resources
  1984. //
  1985. if (Context->Wait.Async.Resource != NULL) {
  1986. ExReleaseResourceForThreadLite( Context->Wait.Async.Resource,
  1987. Context->Wait.Async.ResourceThreadId );
  1988. }
  1989. if (Context->Wait.Async.Resource2 != NULL) {
  1990. ExReleaseResourceForThreadLite( Context->Wait.Async.Resource2,
  1991. Context->Wait.Async.ResourceThreadId );
  1992. }
  1993. //
  1994. // Mark the Irp pending
  1995. //
  1996. IoMarkIrpPending( Irp );
  1997. //
  1998. // and finally, free the context record.
  1999. //
  2000. ExFreePool( Context );
  2001. DebugTrace(-1, Dbg, "FatSingleAsyncCompletionRoutine -> STATUS_MORE_PROCESSING_REQUIRED\n", 0 );
  2002. UNREFERENCED_PARAMETER( DeviceObject );
  2003. return STATUS_SUCCESS;
  2004. }
  2005. VOID
  2006. FatLockUserBuffer (
  2007. IN PIRP_CONTEXT IrpContext,
  2008. IN OUT PIRP Irp,
  2009. IN LOCK_OPERATION Operation,
  2010. IN ULONG BufferLength
  2011. )
  2012. /*++
  2013. Routine Description:
  2014. This routine locks the specified buffer for the specified type of
  2015. access. The file system requires this routine since it does not
  2016. ask the I/O system to lock its buffers for direct I/O. This routine
  2017. may only be called from the Fsd while still in the user context.
  2018. Note that this is the *input/output* buffer.
  2019. Arguments:
  2020. Irp - Pointer to the Irp for which the buffer is to be locked.
  2021. Operation - IoWriteAccess for read operations, or IoReadAccess for
  2022. write operations.
  2023. BufferLength - Length of user buffer.
  2024. Return Value:
  2025. None
  2026. --*/
  2027. {
  2028. PMDL Mdl = NULL;
  2029. if (Irp->MdlAddress == NULL) {
  2030. //
  2031. // Allocate the Mdl, and Raise if we fail.
  2032. //
  2033. Mdl = IoAllocateMdl( Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp );
  2034. if (Mdl == NULL) {
  2035. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  2036. }
  2037. //
  2038. // Now probe the buffer described by the Irp. If we get an exception,
  2039. // deallocate the Mdl and return the appropriate "expected" status.
  2040. //
  2041. try {
  2042. MmProbeAndLockPages( Mdl,
  2043. Irp->RequestorMode,
  2044. Operation );
  2045. } except(EXCEPTION_EXECUTE_HANDLER) {
  2046. NTSTATUS Status;
  2047. Status = GetExceptionCode();
  2048. IoFreeMdl( Mdl );
  2049. Irp->MdlAddress = NULL;
  2050. FatRaiseStatus( IrpContext,
  2051. FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER );
  2052. }
  2053. }
  2054. UNREFERENCED_PARAMETER( IrpContext );
  2055. }
  2056. PVOID
  2057. FatMapUserBuffer (
  2058. IN PIRP_CONTEXT IrpContext,
  2059. IN OUT PIRP Irp
  2060. )
  2061. /*++
  2062. Routine Description:
  2063. This routine conditionally maps the user buffer for the current I/O
  2064. request in the specified mode. If the buffer is already mapped, it
  2065. just returns its address.
  2066. Note that this is the *input/output* buffer.
  2067. Arguments:
  2068. Irp - Pointer to the Irp for the request.
  2069. Return Value:
  2070. Mapped address
  2071. --*/
  2072. {
  2073. UNREFERENCED_PARAMETER( IrpContext );
  2074. //
  2075. // If there is no Mdl, then we must be in the Fsd, and we can simply
  2076. // return the UserBuffer field from the Irp.
  2077. //
  2078. if (Irp->MdlAddress == NULL) {
  2079. return Irp->UserBuffer;
  2080. } else {
  2081. PVOID Address = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  2082. if (Address == NULL) {
  2083. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  2084. }
  2085. return Address;
  2086. }
  2087. }
  2088. PVOID
  2089. FatBufferUserBuffer (
  2090. IN PIRP_CONTEXT IrpContext,
  2091. IN OUT PIRP Irp,
  2092. IN ULONG BufferLength
  2093. )
  2094. /*++
  2095. Routine Description:
  2096. This routine conditionally buffers the user buffer for the current I/O
  2097. request. If the buffer is already buffered, it just returns its address.
  2098. Note that this is the *input* buffer.
  2099. Arguments:
  2100. Irp - Pointer to the Irp for the request.
  2101. BufferLength - Length of user buffer.
  2102. Return Value:
  2103. Buffered address.
  2104. --*/
  2105. {
  2106. PUCHAR UserBuffer;
  2107. UNREFERENCED_PARAMETER( IrpContext );
  2108. //
  2109. // Handle the no buffer case.
  2110. //
  2111. if (BufferLength == 0) {
  2112. return NULL;
  2113. }
  2114. //
  2115. // If there is no system buffer we must have been supplied an Mdl
  2116. // describing the users input buffer, which we will now snapshot.
  2117. //
  2118. if (Irp->AssociatedIrp.SystemBuffer == NULL) {
  2119. UserBuffer = FatMapUserBuffer( IrpContext, Irp );
  2120. Irp->AssociatedIrp.SystemBuffer = FsRtlAllocatePoolWithQuotaTag( NonPagedPool,
  2121. BufferLength,
  2122. TAG_IO_USER_BUFFER );
  2123. //
  2124. // Set the flags so that the completion code knows to deallocate the
  2125. // buffer.
  2126. //
  2127. Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
  2128. try {
  2129. RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer,
  2130. UserBuffer,
  2131. BufferLength );
  2132. } except (EXCEPTION_EXECUTE_HANDLER) {
  2133. NTSTATUS Status;
  2134. Status = GetExceptionCode();
  2135. FatRaiseStatus( IrpContext,
  2136. FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER );
  2137. }
  2138. }
  2139. return Irp->AssociatedIrp.SystemBuffer;
  2140. }
  2141. NTSTATUS
  2142. FatToggleMediaEjectDisable (
  2143. IN PIRP_CONTEXT IrpContext,
  2144. IN PVCB Vcb,
  2145. IN BOOLEAN PreventRemoval
  2146. )
  2147. /*++
  2148. Routine Description:
  2149. The routine either enables or disables the eject button on removable
  2150. media.
  2151. Arguments:
  2152. Vcb - Descibes the volume to operate on
  2153. PreventRemoval - TRUE if we should disable the media eject button. FALSE
  2154. if we want to enable it.
  2155. Return Value:
  2156. Status of the operation.
  2157. --*/
  2158. {
  2159. PIRP Irp;
  2160. KEVENT Event;
  2161. KIRQL SavedIrql;
  2162. NTSTATUS Status;
  2163. IO_STATUS_BLOCK Iosb;
  2164. PREVENT_MEDIA_REMOVAL Prevent;
  2165. //
  2166. // If PreventRemoval is the same as VCB_STATE_FLAG_REMOVAL_PREVENTED,
  2167. // no-op this call, otherwise toggle the state of the flag.
  2168. //
  2169. KeAcquireSpinLock( &FatData.GeneralSpinLock, &SavedIrql );
  2170. if ((PreventRemoval ^
  2171. BooleanFlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVAL_PREVENTED)) == 0) {
  2172. KeReleaseSpinLock( &FatData.GeneralSpinLock, SavedIrql );
  2173. return STATUS_SUCCESS;
  2174. } else {
  2175. Vcb->VcbState ^= VCB_STATE_FLAG_REMOVAL_PREVENTED;
  2176. KeReleaseSpinLock( &FatData.GeneralSpinLock, SavedIrql );
  2177. }
  2178. Prevent.PreventMediaRemoval = PreventRemoval;
  2179. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  2180. //
  2181. // We build this IRP using a junk Iosb that will receive the final
  2182. // completion status since we won't be around for it.
  2183. //
  2184. Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_MEDIA_REMOVAL,
  2185. Vcb->TargetDeviceObject,
  2186. &Prevent,
  2187. sizeof(PREVENT_MEDIA_REMOVAL),
  2188. NULL,
  2189. 0,
  2190. FALSE,
  2191. NULL,
  2192. &Iosb );
  2193. if ( Irp != NULL ) {
  2194. //
  2195. // Use our special completion routine which will remove the requirement that
  2196. // the caller must be below APC level. All it tells us is that the Irp got
  2197. // back, but will not tell us if it was succesful or not. We don't care,
  2198. // and there is of course no fallback if the attempt to prevent removal
  2199. // doesn't work for some mysterious reason.
  2200. //
  2201. // Normally, all IO is done at passive level. However, MM needs to be able
  2202. // to issue IO with fast mutexes locked down, which raises us to APC. The
  2203. // overlying IRP is set up to complete in yet another magical fashion even
  2204. // though APCs are disabled, and any IRPage we do in these cases has to do
  2205. // the same. Marking media dirty (and toggling eject state) is one.
  2206. //
  2207. IoSetCompletionRoutine( Irp,
  2208. FatSpecialSyncCompletionRoutine,
  2209. &Event,
  2210. TRUE,
  2211. TRUE,
  2212. TRUE );
  2213. Status = IoCallDriver( Vcb->TargetDeviceObject, Irp );
  2214. if (Status == STATUS_PENDING) {
  2215. (VOID) KeWaitForSingleObject( &Event,
  2216. Executive,
  2217. KernelMode,
  2218. FALSE,
  2219. NULL );
  2220. Status = Iosb.Status;
  2221. }
  2222. return Status;
  2223. }
  2224. return STATUS_INSUFFICIENT_RESOURCES;
  2225. }
  2226. NTSTATUS
  2227. FatPerformDevIoCtrl (
  2228. IN PIRP_CONTEXT IrpContext,
  2229. IN ULONG IoControlCode,
  2230. IN PDEVICE_OBJECT Device,
  2231. OUT PVOID OutputBuffer OPTIONAL,
  2232. IN ULONG OutputBufferLength,
  2233. IN BOOLEAN InternalDeviceIoControl,
  2234. IN BOOLEAN OverrideVerify,
  2235. OUT PIO_STATUS_BLOCK Iosb OPTIONAL
  2236. )
  2237. /*++
  2238. Routine Description:
  2239. This routine is called to perform DevIoCtrl functions internally within
  2240. the filesystem. We take the status from the driver and return it to our
  2241. caller.
  2242. Arguments:
  2243. IoControlCode - Code to send to driver.
  2244. Device - This is the device to send the request to.
  2245. OutPutBuffer - Pointer to output buffer.
  2246. OutputBufferLength - Length of output buffer above.
  2247. InternalDeviceIoControl - Indicates if this is an internal or external
  2248. Io control code.
  2249. OverrideVerify - Indicates if we should tell the driver not to return
  2250. STATUS_VERIFY_REQUIRED for mount and verify.
  2251. Iosb - If specified, we return the results of the operation here.
  2252. Return Value:
  2253. NTSTATUS - Status returned by next lower driver.
  2254. --*/
  2255. {
  2256. NTSTATUS Status;
  2257. PIRP Irp;
  2258. KEVENT Event;
  2259. IO_STATUS_BLOCK LocalIosb;
  2260. PIO_STATUS_BLOCK IosbToUse = &LocalIosb;
  2261. PAGED_CODE();
  2262. //
  2263. // Check if the user gave us an Iosb.
  2264. //
  2265. if (ARGUMENT_PRESENT( Iosb )) {
  2266. IosbToUse = Iosb;
  2267. }
  2268. IosbToUse->Status = 0;
  2269. IosbToUse->Information = 0;
  2270. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  2271. Irp = IoBuildDeviceIoControlRequest( IoControlCode,
  2272. Device,
  2273. NULL,
  2274. 0,
  2275. OutputBuffer,
  2276. OutputBufferLength,
  2277. InternalDeviceIoControl,
  2278. &Event,
  2279. IosbToUse );
  2280. if (Irp == NULL) {
  2281. return STATUS_INSUFFICIENT_RESOURCES;
  2282. }
  2283. if (OverrideVerify) {
  2284. SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  2285. }
  2286. Status = IoCallDriver( Device, Irp );
  2287. //
  2288. // We check for device not ready by first checking Status
  2289. // and then if status pending was returned, the Iosb status
  2290. // value.
  2291. //
  2292. if (Status == STATUS_PENDING) {
  2293. (VOID) KeWaitForSingleObject( &Event,
  2294. Executive,
  2295. KernelMode,
  2296. FALSE,
  2297. (PLARGE_INTEGER)NULL );
  2298. Status = IosbToUse->Status;
  2299. }
  2300. return Status;
  2301. }