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

2444 lines
63 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. DevIoSup.c
  5. Abstract:
  6. This module implements the low lever disk read/write support for Rx.
  7. Author:
  8. Gary Kimura [GaryKi] 22-Jan-1990
  9. Revision History:
  10. David Goebel [DavidGoe] 05-Oct-1990
  11. Major changes for the new RDBSS
  12. Tom Miller [TomM] 22-Apr-1990
  13. Added User Buffer Locking and Mapping routines
  14. Modified behavior of async I/O routines to use completion routines
  15. --*/
  16. // ----------------------joejoe-----------found-------------#include "RxProcs.h"
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. //
  20. // The Bug check file id for this module
  21. //
  22. #define BugCheckFileId (RDBSS_BUG_CHECK_DEVIOSUP)
  23. //
  24. // Local debug trace level
  25. //
  26. #define Dbg (DEBUG_TRACE_DEVIOSUP)
  27. //
  28. // Completion Routine declarations
  29. //
  30. RXSTATUS
  31. RxMultiSyncCompletionRoutine (
  32. IN PDEVICE_OBJECT DeviceObject,
  33. IN PIRP Irp,
  34. IN PVOID Contxt
  35. );
  36. RXSTATUS
  37. RxMultiAsyncCompletionRoutine (
  38. IN PDEVICE_OBJECT DeviceObject,
  39. IN PIRP Irp,
  40. IN PVOID Contxt
  41. );
  42. RXSTATUS
  43. RxSingleSyncCompletionRoutine (
  44. IN PDEVICE_OBJECT DeviceObject,
  45. IN PIRP Irp,
  46. IN PVOID Contxt
  47. );
  48. RXSTATUS
  49. RxSingleAsyncCompletionRoutine (
  50. IN PDEVICE_OBJECT DeviceObject,
  51. IN PIRP Irp,
  52. IN PVOID Contxt
  53. );
  54. RXSTATUS
  55. RxPagingFileCompletionRoutine (
  56. IN PDEVICE_OBJECT DeviceObject,
  57. IN PIRP Irp,
  58. IN PVOID MasterIrp
  59. );
  60. VOID
  61. RxSingleNonAlignedSync (
  62. IN PRX_CONTEXT RxContext,
  63. IN PVCB Vcb,
  64. IN PUCHAR Buffer,
  65. IN LBO Lbo,
  66. IN ULONG ByteCount,
  67. IN PIRP Irp
  68. );
  69. //
  70. // The following macro decides whether to send a request directly to
  71. // the device driver, or to the double space routines. It was meant to
  72. // replace IoCallDriver as transparently as possible. It must only be
  73. // called with a read or write Irp.
  74. //
  75. // RXSTATUS
  76. // RxLowLevelReadWrite (
  77. // PRX_CONTEXT RxContext,
  78. // PDEVICE_OBJECT DeviceObject,
  79. // PIRP Irp,
  80. // PVCB Vcb
  81. // );
  82. //
  83. #ifdef WE_WON_ON_APPEAL
  84. #define RxLowLevelReadWrite(RXCONTEXT,DO,IRP,VCB) ( \
  85. (VCB)->Dscb == NULL ? \
  86. IoCallDriver((DO),(IRP)) : \
  87. RxLowLevelDblsReadWrite((RXCONTEXT),(IRP),(VCB)) \
  88. )
  89. #else
  90. #define RxLowLevelReadWrite(RXCONTEXT,DO,IRP,VCB) ( \
  91. IoCallDriver((DO),(IRP)) \
  92. )
  93. #endif // WE_WON_ON_APPEAL
  94. #ifdef ALLOC_PRAGMA
  95. #pragma alloc_text(PAGE, RxMultipleAsync)
  96. #pragma alloc_text(PAGE, RxSingleAsync)
  97. #pragma alloc_text(PAGE, RxSingleNonAlignedSync)
  98. #pragma alloc_text(PAGE, RxToggleMediaEjectDisable)
  99. #pragma alloc_text(PAGE, RxNonCachedIo)
  100. #pragma alloc_text(PAGE, RxSingleNonAlignedSync)
  101. #pragma alloc_text(PAGE, RxNonCachedNonAlignedRead)
  102. #endif
  103. VOID
  104. RxPagingFileIo (
  105. IN PIRP Irp,
  106. IN PFCB Fcb
  107. )
  108. /*++
  109. Routine Description:
  110. This routine performs the non-cached disk io described in its parameters.
  111. This routine nevers blocks, and should only be used with the paging
  112. file since no completion processing is performed.
  113. Arguments:
  114. Irp - Supplies the requesting Irp.
  115. Fcb - Supplies the file to act on.
  116. Return Value:
  117. None.
  118. --*/
  119. {
  120. //
  121. // Declare some local variables for enumeration through the
  122. // runs of the file.
  123. //
  124. VBO Vbo;
  125. ULONG ByteCount;
  126. PMDL Mdl;
  127. LBO NextLbo;
  128. VBO NextVbo;
  129. ULONG NextByteCount;
  130. BOOLEAN MustSucceed;
  131. ULONG FirstIndex;
  132. ULONG CurrentIndex;
  133. ULONG LastIndex;
  134. LBO LastLbo;
  135. ULONG LastByteCount;
  136. PIRP AssocIrp;
  137. PIO_STACK_LOCATION IrpSp;
  138. PIO_STACK_LOCATION NextIrpSp;
  139. ULONG BufferOffset;
  140. PDEVICE_OBJECT DeviceObject;
  141. DebugTrace(+1, Dbg, "RxPagingFileIo\n", 0);
  142. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  143. DebugTrace( 0, Dbg, "Fcb = %08lx\n", Fcb );
  144. //
  145. // Initialize some locals.
  146. //
  147. BufferOffset = 0;
  148. DeviceObject = Fcb->Vcb->TargetDeviceObject;
  149. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  150. Vbo = IrpSp->Parameters.Read.ByteOffset.LowPart;
  151. ByteCount = IrpSp->Parameters.Read.Length;
  152. MustSucceed = FsRtlLookupMcbEntry( &Fcb->Mcb,
  153. Vbo,
  154. &NextLbo,
  155. &NextByteCount,
  156. &FirstIndex);
  157. //
  158. // If this run isn't present, something is very wrong.
  159. //
  160. if (!MustSucceed) {
  161. RxBugCheck( Vbo, ByteCount, 0 );
  162. }
  163. //
  164. // See if the write covers a single valid run, and if so pass
  165. // it on.
  166. //
  167. if ( NextByteCount >= ByteCount ) {
  168. DebugTrace( 0, Dbg, "Passing Irp on to Disk Driver\n", 0 );
  169. //
  170. // Setup the next IRP stack location for the disk driver beneath us.
  171. //
  172. NextIrpSp = IoGetNextIrpStackLocation( Irp );
  173. NextIrpSp->MajorFunction = IrpSp->MajorFunction;
  174. NextIrpSp->Parameters.Read.Length = ByteCount;
  175. NextIrpSp->Parameters.Read.ByteOffset.QuadPart = NextLbo;
  176. //
  177. // Since this is Paging file IO, we'll just ignore the verify bit.
  178. //
  179. if (FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ||
  180. (Fcb->Vcb->VerifyThread == KeGetCurrentThread())) {
  181. SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  182. }
  183. //
  184. // Set up the completion routine address in our stack frame.
  185. // This is only invoked on error or cancel, and just copies
  186. // the error Status into master irp's iosb.
  187. //
  188. // If the error implies a media problem, it also enqueues a
  189. // worker item to write out the dirty bit so that the next
  190. // time we run we will do a autochk /r
  191. //
  192. IoSetCompletionRoutine( Irp,
  193. &RxPagingFileCompletionRoutine,
  194. Irp,
  195. FALSE,
  196. TRUE,
  197. TRUE );
  198. //
  199. // Issue the read/write request
  200. //
  201. // If IoCallDriver returns an error, it has completed the Irp
  202. // and the error will be dealt with as a normal IO error.
  203. //
  204. (VOID)IoCallDriver( DeviceObject, Irp );
  205. DebugTrace(-1, Dbg, "RxPagingFileIo -> VOID\n", 0);
  206. return;
  207. }
  208. //
  209. // Find out how may runs there are.
  210. //
  211. MustSucceed = FsRtlLookupMcbEntry( &Fcb->Mcb,
  212. Vbo + ByteCount - 1,
  213. &LastLbo,
  214. &LastByteCount,
  215. &LastIndex);
  216. //
  217. // If this run isn't present, something is very wrong.
  218. //
  219. if (!MustSucceed) {
  220. RxBugCheck( Vbo + ByteCount - 1, 1, 0 );
  221. }
  222. CurrentIndex = FirstIndex;
  223. //
  224. // Now set up the Irp->IoStatus. It will be modified by the
  225. // multi-completion routine in case of error or verify required.
  226. //
  227. Irp->IoStatus.Status = RxStatus(SUCCESS);
  228. Irp->IoStatus.Information = ByteCount;
  229. //
  230. // Loop while there are still byte writes to satisfy. If we fail to
  231. // allocate resources the AssociatedIrp.IrpCount will be high enough
  232. // that we can safely complete the Master Irp.
  233. //
  234. Irp->AssociatedIrp.IrpCount = LastIndex - FirstIndex + 1;
  235. while (CurrentIndex <= LastIndex) {
  236. //
  237. // Reset this for unwinding purposes
  238. //
  239. AssocIrp = NULL;
  240. //
  241. // If next run is larger than we need, "ya get what you need".
  242. //
  243. if (NextByteCount > ByteCount) {
  244. NextByteCount = ByteCount;
  245. }
  246. //
  247. // Now that we have properly bounded this piece of the
  248. // transfer, it is time to read/write it.
  249. //
  250. AssocIrp = IoMakeAssociatedIrp( Irp, (CCHAR)(DeviceObject->StackSize + 1) );
  251. if (AssocIrp == NULL) {
  252. //
  253. // This is a rare case, so just spin until all pending Associated
  254. // Irps complete.
  255. //
  256. while (Irp->AssociatedIrp.IrpCount !=
  257. (LONG)(LastIndex - CurrentIndex + 1)) {
  258. //
  259. // Wait for a short time so other processing can continue.
  260. //
  261. KeDelayExecutionThread (KernelMode, FALSE, &Rx30Milliseconds);
  262. }
  263. Irp->IoStatus.Status = RxStatus(INSUFFICIENT_RESOURCES);
  264. Irp->IoStatus.Information = 0;
  265. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  266. return;
  267. }
  268. //
  269. // Allocate and build a partial Mdl for the request.
  270. //
  271. Mdl = IoAllocateMdl( (PCHAR)Irp->UserBuffer + BufferOffset,
  272. NextByteCount,
  273. FALSE,
  274. FALSE,
  275. AssocIrp );
  276. if (Mdl == NULL) {
  277. IoFreeIrp( AssocIrp );
  278. //
  279. // This is a rare case, so just spin until all pending Associated
  280. // Irps complete.
  281. //
  282. while (Irp->AssociatedIrp.IrpCount !=
  283. (LONG)(LastIndex - CurrentIndex + 1)) {
  284. //
  285. // Wait for a short time so other processing can continue.
  286. //
  287. KeDelayExecutionThread (KernelMode, FALSE, &Rx30Milliseconds);
  288. }
  289. Irp->IoStatus.Status = RxStatus(INSUFFICIENT_RESOURCES);
  290. Irp->IoStatus.Information = 0;
  291. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  292. return;
  293. }
  294. IoBuildPartialMdl( Irp->MdlAddress,
  295. Mdl,
  296. (PCHAR)Irp->UserBuffer + BufferOffset,
  297. NextByteCount );
  298. //
  299. // Get the first IRP stack location in the associated Irp
  300. //
  301. IoSetNextIrpStackLocation( AssocIrp );
  302. NextIrpSp = IoGetCurrentIrpStackLocation( AssocIrp );
  303. //
  304. // Setup the Stack location to describe our read.
  305. //
  306. NextIrpSp->MajorFunction = IrpSp->MajorFunction;
  307. NextIrpSp->Parameters.Read.Length = NextByteCount;
  308. NextIrpSp->Parameters.Read.ByteOffset.QuadPart = Vbo;
  309. //
  310. // We also need the RxDeviceObject in the Irp stack in case
  311. // we take the failure path.
  312. //
  313. NextIrpSp->DeviceObject = IrpSp->DeviceObject;
  314. //
  315. // Since this is Paging file IO, we'll just ignore the verify bit.
  316. //
  317. if (FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ||
  318. (Fcb->Vcb->VerifyThread == KeGetCurrentThread())) {
  319. SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  320. }
  321. //
  322. // Set up the completion routine address in our stack frame.
  323. // This is only invoked on error or cancel, and just copies
  324. // the error Status into master irp's iosb.
  325. //
  326. // If the error implies a media problem, it also enqueues a
  327. // worker item to write out the dirty bit so that the next
  328. // time we run we will do a autochk /r
  329. //
  330. IoSetCompletionRoutine( AssocIrp,
  331. &RxPagingFileCompletionRoutine,
  332. Irp,
  333. FALSE,
  334. TRUE,
  335. TRUE );
  336. //
  337. // Setup the next IRP stack location in the associated Irp for the disk
  338. // driver beneath us.
  339. //
  340. NextIrpSp = IoGetNextIrpStackLocation( AssocIrp );
  341. //
  342. // Setup the Stack location to do a read from the disk driver.
  343. //
  344. NextIrpSp->MajorFunction = IrpSp->MajorFunction;
  345. NextIrpSp->Parameters.Read.Length = NextByteCount;
  346. NextIrpSp->Parameters.Read.ByteOffset.QuadPart = NextLbo;
  347. (VOID)IoCallDriver( DeviceObject, AssocIrp );
  348. //
  349. // Now adjust everything for the next pass through the loop.
  350. //
  351. Vbo += NextByteCount;
  352. BufferOffset += NextByteCount;
  353. ByteCount -= NextByteCount;
  354. //
  355. // Try to lookup the next run (if we are not done).
  356. //
  357. CurrentIndex += 1;
  358. if ( CurrentIndex <= LastIndex ) {
  359. ASSERT( ByteCount != 0 );
  360. FsRtlGetNextMcbEntry( &Fcb->Mcb,
  361. CurrentIndex,
  362. &NextVbo,
  363. &NextLbo,
  364. &NextByteCount );
  365. ASSERT( NextVbo == Vbo );
  366. }
  367. } // while ( CurrentIndex <= LastIndex )
  368. DebugTrace(-1, Dbg, "RxPagingFileIo -> VOID\n", 0);
  369. return;
  370. }
  371. RXSTATUS
  372. RxNonCachedIo (
  373. IN PRX_CONTEXT RxContext,
  374. IN PIRP Irp,
  375. IN PFCB FcbOrDcb,
  376. IN ULONG StartingVbo,
  377. IN ULONG ByteCount
  378. )
  379. /*++
  380. Routine Description:
  381. This routine performs the non-cached disk io described in its parameters.
  382. The choice of a single run is made if possible, otherwise multiple runs
  383. are executed.
  384. Arguments:
  385. RxContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
  386. Irp - Supplies the requesting Irp.
  387. FcbOrDcb - Supplies the file to act on.
  388. StartingVbo - The starting point for the operation.
  389. ByteCount - The lengh of the operation.
  390. Return Value:
  391. None.
  392. --*/
  393. {
  394. //
  395. // Declare some local variables for enumeration through the
  396. // runs of the file, and an array to store parameters for
  397. // parallel I/Os
  398. //
  399. BOOLEAN Wait;
  400. LBO NextLbo;
  401. VBO NextVbo;
  402. ULONG NextByteCount;
  403. BOOLEAN NextIsAllocated;
  404. LBO LastLbo;
  405. ULONG LastByteCount;
  406. BOOLEAN LastIsAllocated;
  407. ULONG FirstIndex;
  408. ULONG CurrentIndex;
  409. ULONG LastIndex;
  410. ULONG NextRun;
  411. ULONG BufferOffset;
  412. ULONG OriginalByteCount;
  413. IO_RUN StackIoRuns[RDBSS_MAX_IO_RUNS_ON_STACK];
  414. PIO_RUN IoRuns;
  415. DebugTrace(+1, Dbg, "RxNonCachedIo\n", 0);
  416. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  417. DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", RxContext->MajorFunction );
  418. DebugTrace( 0, Dbg, "FcbOrDcb = %08lx\n", FcbOrDcb );
  419. DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo );
  420. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount );
  421. //no longer used DebugTrace( 0, Dbg, "Context = %08lx\n", Context );
  422. //
  423. // Initialize some locals.
  424. //
  425. NextRun = 0;
  426. BufferOffset = 0;
  427. OriginalByteCount = ByteCount;
  428. Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
  429. //
  430. // For nonbuffered I/O, we need the buffer locked in all
  431. // cases.
  432. //
  433. // This call may raise. If this call succeeds and a subsequent
  434. // condition is raised, the buffers are unlocked automatically
  435. // by the I/O system when the request is completed, via the
  436. // Irp->MdlAddress field.
  437. //
  438. RxLockUserBuffer( RxContext,
  439. (RxContext->MajorFunction == IRP_MJ_READ) ?
  440. IoWriteAccess : IoReadAccess,
  441. ByteCount );
  442. #if 0 // The corruption was happening on the SCSI bus. (DavidGoe 1/11/93)
  443. //
  444. // If we are writing a directory, add a spot check here that
  445. // what we are writing is really a directory.
  446. //
  447. if ( !FlagOn(FcbOrDcb->Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
  448. (NodeType(FcbOrDcb) != RDBSS_NTC_FCB) &&
  449. (RxContext->MajorFunction == IRP_MJ_WRITE) ) {
  450. PDIRENT Dirent;
  451. Dirent = RxMapUserBuffer( RxContext, Irp );
  452. //
  453. // For the first page of a non-root directory, make sure that
  454. // . and .. are present.
  455. //
  456. if ( (StartingVbo == 0) &&
  457. (NodeType(FcbOrDcb) != RDBSS_NTC_ROOT_DCB) ) {
  458. if ( (RtlCompareMemory( (PUCHAR)Dirent++,
  459. ". ",
  460. 11 ) != 11) ||
  461. (RtlCompareMemory( (PUCHAR)Dirent,
  462. ".. ",
  463. 11 ) != 11) ) {
  464. RxBugCheck( 0, 0, 0 );
  465. }
  466. } else {
  467. //
  468. // Check that all the reserved bit in the second dirent are
  469. // zero. (The first one contains our dirty bit in the root dir)
  470. //
  471. PULONG Zeros;
  472. Dirent++;
  473. Zeros = (PULONG)&Dirent->Reserved[0];
  474. if ( (Dirent->FileName[0] != 0xE5) &&
  475. ((*Zeros != 0) || (*(Zeros+1) != 0)) ) {
  476. RxBugCheck( 0, 0, 0 );
  477. }
  478. }
  479. }
  480. #endif //0
  481. //
  482. // Try to lookup the first run. If there is just a single run,
  483. // we may just be able to pass it on.
  484. //
  485. RxLookupFileAllocation( RxContext,
  486. FcbOrDcb,
  487. StartingVbo,
  488. &NextLbo,
  489. &NextByteCount,
  490. &NextIsAllocated,
  491. &FirstIndex );
  492. //
  493. // We just added the allocation, thus there must be at least
  494. // one entry in the mcb corresponding to our write, ie.
  495. // NextIsAllocated must be true. If not, the pre-existing file
  496. // must have an allocation error.
  497. //
  498. if ( !NextIsAllocated ) {
  499. RxPopUpFileCorrupt( RxContext, FcbOrDcb );
  500. RxRaiseStatus( RxContext, RxStatus(FILE_CORRUPT_ERROR) );
  501. }
  502. //
  503. // If the request was not aligned correctly, read in the first
  504. // part first.
  505. //
  506. //
  507. // See if the write covers a single valid run, and if so pass
  508. // it on.
  509. //
  510. if ( NextByteCount >= ByteCount ) {
  511. DebugTrace( 0, Dbg, "Passing Irp on to Disk Driver\n", 0 );
  512. RxSingleAsync( RxContext,
  513. FcbOrDcb->Vcb,
  514. NextLbo,
  515. ByteCount,
  516. Irp );
  517. if (!Wait) {
  518. DebugTrace(-1, Dbg, "RxNonCachedIo -> RxStatus(PENDING\n)", 0);
  519. return RxStatus(PENDING);
  520. } else {
  521. RxWaitSync( RxContext );
  522. DebugTrace(-1, Dbg, "RxNonCachedIo -> 0x%08lx\n", Irp->IoStatus.Status);
  523. return Irp->IoStatus.Status;
  524. }
  525. }
  526. //
  527. // If there we can't wait, and there are more runs than we can handle,
  528. // we will have to post this request.
  529. //
  530. RxLookupFileAllocation( RxContext,
  531. FcbOrDcb,
  532. StartingVbo + ByteCount - 1,
  533. &LastLbo,
  534. &LastByteCount,
  535. &LastIsAllocated,
  536. &LastIndex );
  537. //
  538. // Since we already added the allocation for the whole
  539. // write, assert that we find runs until ByteCount == 0
  540. // Otherwise this file is corrupt.
  541. //
  542. if ( !LastIsAllocated ) {
  543. RxPopUpFileCorrupt( RxContext, FcbOrDcb );
  544. RxRaiseStatus( RxContext, RxStatus(FILE_CORRUPT_ERROR) );
  545. }
  546. if (LastIndex - FirstIndex + 1 > RDBSS_MAX_IO_RUNS_ON_STACK) {
  547. IoRuns = FsRtlAllocatePool(PagedPool,
  548. (LastIndex - FirstIndex + 1) * sizeof(IO_RUN));
  549. } else {
  550. IoRuns = StackIoRuns;
  551. }
  552. CurrentIndex = FirstIndex;
  553. //
  554. // Loop while there are still byte writes to satisfy.
  555. //
  556. while (CurrentIndex <= LastIndex) {
  557. //
  558. // If next run is larger than we need, "ya get what you need".
  559. //
  560. if (NextByteCount > ByteCount) {
  561. NextByteCount = ByteCount;
  562. }
  563. //
  564. // Now that we have properly bounded this piece of the
  565. // transfer, it is time to write it.
  566. //
  567. // We remember each piece of a parallel run by saving the
  568. // essential information in the IoRuns array. The tranfers
  569. // are started up in parallel below.
  570. //
  571. IoRuns[NextRun].Vbo = StartingVbo;
  572. IoRuns[NextRun].Lbo = NextLbo;
  573. IoRuns[NextRun].Offset = BufferOffset;
  574. IoRuns[NextRun].ByteCount = NextByteCount;
  575. NextRun += 1;
  576. //
  577. // Now adjust everything for the next pass through the loop.
  578. //
  579. StartingVbo += NextByteCount;
  580. BufferOffset += NextByteCount;
  581. ByteCount -= NextByteCount;
  582. //
  583. // Try to lookup the next run (if we are not done).
  584. //
  585. CurrentIndex += 1;
  586. if ( CurrentIndex <= LastIndex ) {
  587. ASSERT( ByteCount != 0 );
  588. FsRtlGetNextMcbEntry( &FcbOrDcb->Mcb,
  589. CurrentIndex,
  590. &NextVbo,
  591. &NextLbo,
  592. &NextByteCount );
  593. ASSERT( NextVbo == StartingVbo );
  594. }
  595. } // while ( CurrentIndex <= LastIndex )
  596. //
  597. // Now set up the Irp->IoStatus. It will be modified by the
  598. // multi-completion routine in case of error or verify required.
  599. //
  600. Irp->IoStatus.Status = RxStatus(SUCCESS);
  601. Irp->IoStatus.Information = OriginalByteCount;
  602. //
  603. // OK, now do the I/O.
  604. //
  605. try {
  606. RxMultipleAsync( RxContext,
  607. FcbOrDcb->Vcb,
  608. Irp,
  609. NextRun,
  610. IoRuns );
  611. } finally {
  612. if (IoRuns != StackIoRuns) {
  613. ExFreePool( IoRuns );
  614. }
  615. }
  616. if (!Wait) {
  617. DebugTrace(-1, Dbg, "RxNonCachedIo -> RxStatus(PENDING\n)", 0);
  618. return RxStatus(PENDING);
  619. }
  620. RxWaitSync( RxContext );
  621. DebugTrace(-1, Dbg, "RxNonCachedIo -> 0x%08lx\n", Irp->IoStatus.Status);
  622. return Irp->IoStatus.Status;
  623. }
  624. VOID
  625. RxNonCachedNonAlignedRead (
  626. IN PRX_CONTEXT RxContext,
  627. IN PIRP Irp,
  628. IN PFCB FcbOrDcb,
  629. IN ULONG StartingVbo,
  630. IN ULONG ByteCount
  631. )
  632. /*++
  633. Routine Description:
  634. This routine performs the non-cached disk io described in its parameters.
  635. This routine differs from the above in that the range does not have to be
  636. sector aligned. This accomplished with the use of intermediate buffers.
  637. Arguments:
  638. RxContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
  639. Irp - Supplies the requesting Irp.
  640. FcbOrDcb - Supplies the file to act on.
  641. StartingVbo - The starting point for the operation.
  642. ByteCount - The lengh of the operation.
  643. Return Value:
  644. None.
  645. --*/
  646. {
  647. //
  648. // Declare some local variables for enumeration through the
  649. // runs of the file, and an array to store parameters for
  650. // parallel I/Os
  651. //
  652. LBO NextLbo;
  653. ULONG NextByteCount;
  654. BOOLEAN NextIsAllocated;
  655. ULONG SectorSize;
  656. ULONG BytesToCopy;
  657. ULONG OriginalByteCount;
  658. ULONG OriginalStartingVbo;
  659. PUCHAR UserBuffer;
  660. PUCHAR DiskBuffer = NULL;
  661. PMDL Mdl;
  662. PMDL SavedMdl;
  663. DebugTrace(+1, Dbg, "RxNonCachedNonAlignedRead\n", 0);
  664. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  665. DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", RxContext->MajorFunction );
  666. DebugTrace( 0, Dbg, "FcbOrDcb = %08lx\n", FcbOrDcb );
  667. DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo );
  668. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount );
  669. //
  670. // Initialize some locals.
  671. //
  672. OriginalByteCount = ByteCount;
  673. OriginalStartingVbo = StartingVbo;
  674. SectorSize = FcbOrDcb->Vcb->Bpb.BytesPerSector;
  675. ASSERT( FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT) );
  676. //
  677. // For nonbuffered I/O, we need the buffer locked in all
  678. // cases.
  679. //
  680. // This call may raise. If this call succeeds and a subsequent
  681. // condition is raised, the buffers are unlocked automatically
  682. // by the I/O system when the request is completed, via the
  683. // Irp->MdlAddress field.
  684. //
  685. RxLockUserBuffer( RxContext,
  686. IoWriteAccess,
  687. ByteCount );
  688. UserBuffer = RxMapUserBuffer( RxContext );
  689. //
  690. // Allocate the local buffer
  691. //
  692. DiskBuffer = FsRtlAllocatePool( NonPagedPoolCacheAligned,
  693. ROUND_TO_PAGES( SectorSize ));
  694. //
  695. // We use a try block here to ensure the buffer is freed, and to
  696. // fill in the correct byte count in the Iosb.Information field.
  697. //
  698. try {
  699. //
  700. // If the beginning of the request was not aligned correctly, read in
  701. // the first part first.
  702. //
  703. if ( StartingVbo & (SectorSize - 1) ) {
  704. VBO Hole;
  705. //
  706. // Try to lookup the first run.
  707. //
  708. RxLookupFileAllocation( RxContext,
  709. FcbOrDcb,
  710. StartingVbo,
  711. &NextLbo,
  712. &NextByteCount,
  713. &NextIsAllocated,
  714. NULL );
  715. //
  716. // We just added the allocation, thus there must be at least
  717. // one entry in the mcb corresponding to our write, ie.
  718. // NextIsAllocated must be true. If not, the pre-existing file
  719. // must have an allocation error.
  720. //
  721. if ( !NextIsAllocated ) {
  722. RxPopUpFileCorrupt( RxContext, FcbOrDcb );
  723. RxRaiseStatus( RxContext, RxStatus(FILE_CORRUPT_ERROR) );
  724. }
  725. RxSingleNonAlignedSync( RxContext,
  726. FcbOrDcb->Vcb,
  727. DiskBuffer,
  728. NextLbo & ~(SectorSize - 1),
  729. SectorSize,
  730. Irp );
  731. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  732. try_return( NOTHING );
  733. }
  734. //
  735. // Now copy the part of the first sector that we want to the user
  736. // buffer.
  737. //
  738. Hole = StartingVbo & (SectorSize - 1);
  739. BytesToCopy = ByteCount >= SectorSize - Hole ?
  740. SectorSize - Hole : ByteCount;
  741. RtlCopyMemory( UserBuffer, DiskBuffer + Hole, BytesToCopy );
  742. StartingVbo += BytesToCopy;
  743. ByteCount -= BytesToCopy;
  744. if ( ByteCount == 0 ) {
  745. try_return( NOTHING );
  746. }
  747. }
  748. ASSERT( (StartingVbo & (SectorSize - 1)) == 0 );
  749. //
  750. // If there is a tail part that is not sector aligned, read it.
  751. //
  752. if ( ByteCount & (SectorSize - 1) ) {
  753. VBO LastSectorVbo;
  754. LastSectorVbo = StartingVbo + (ByteCount & ~(SectorSize - 1));
  755. //
  756. // Try to lookup the last part of the requested range.
  757. //
  758. RxLookupFileAllocation( RxContext,
  759. FcbOrDcb,
  760. LastSectorVbo,
  761. &NextLbo,
  762. &NextByteCount,
  763. &NextIsAllocated,
  764. NULL );
  765. //
  766. // We just added the allocation, thus there must be at least
  767. // one entry in the mcb corresponding to our write, ie.
  768. // NextIsAllocated must be true. If not, the pre-existing file
  769. // must have an allocation error.
  770. //
  771. if ( !NextIsAllocated ) {
  772. RxPopUpFileCorrupt( RxContext, FcbOrDcb );
  773. RxRaiseStatus( RxContext, RxStatus(FILE_CORRUPT_ERROR) );
  774. }
  775. RxSingleNonAlignedSync( RxContext,
  776. FcbOrDcb->Vcb,
  777. DiskBuffer,
  778. NextLbo,
  779. SectorSize,
  780. Irp );
  781. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  782. try_return( NOTHING );
  783. }
  784. //
  785. // Now copy over the part of this last sector that we need.
  786. //
  787. BytesToCopy = ByteCount & (SectorSize - 1);
  788. UserBuffer += LastSectorVbo - OriginalStartingVbo;
  789. RtlCopyMemory( UserBuffer, DiskBuffer, BytesToCopy );
  790. ByteCount -= BytesToCopy;
  791. if ( ByteCount == 0 ) {
  792. try_return( NOTHING );
  793. }
  794. }
  795. ASSERT( ((StartingVbo | ByteCount) & (SectorSize - 1)) == 0 );
  796. //
  797. // Now build a Mdl describing the sector aligned balance of the transfer,
  798. // and put it in the Irp, and read that part.
  799. //
  800. SavedMdl = Irp->MdlAddress;
  801. Irp->MdlAddress = NULL;
  802. UserBuffer = MmGetMdlVirtualAddress( SavedMdl );
  803. Mdl = IoAllocateMdl( UserBuffer + (StartingVbo - OriginalStartingVbo),
  804. ByteCount,
  805. FALSE,
  806. FALSE,
  807. Irp );
  808. if (Mdl == NULL) {
  809. Irp->MdlAddress = SavedMdl;
  810. RxRaiseStatus( RxContext, RxStatus(INSUFFICIENT_RESOURCES) );
  811. }
  812. IoBuildPartialMdl( SavedMdl,
  813. Mdl,
  814. UserBuffer + (StartingVbo - OriginalStartingVbo),
  815. ByteCount );
  816. //
  817. // Try to read in the pages.
  818. //
  819. try {
  820. RxNonCachedIo( RxContext,
  821. Irp,
  822. FcbOrDcb,
  823. StartingVbo,
  824. ByteCount );
  825. } finally {
  826. IoFreeMdl( Irp->MdlAddress );
  827. Irp->MdlAddress = SavedMdl;
  828. }
  829. try_exit: NOTHING;
  830. } finally {
  831. ExFreePool( DiskBuffer );
  832. if ( !AbnormalTermination() && NT_SUCCESS(Irp->IoStatus.Status) ) {
  833. Irp->IoStatus.Information = OriginalByteCount;
  834. //
  835. // We now flush the user's buffer to memory.
  836. //
  837. KeFlushIoBuffers( Irp->MdlAddress, TRUE, FALSE );
  838. }
  839. }
  840. DebugTrace(-1, Dbg, "RxNonCachedNonAlignedRead -> VOID\n", 0);
  841. return;
  842. }
  843. VOID
  844. RxMultipleAsync (
  845. IN PRX_CONTEXT RxContext,
  846. IN PVCB Vcb,
  847. IN PIRP MasterIrp,
  848. IN ULONG MultipleIrpCount,
  849. IN PIO_RUN IoRuns
  850. )
  851. /*++
  852. Routine Description:
  853. This routine first does the initial setup required of a Master IRP that is
  854. going to be completed using associated IRPs. This routine should not
  855. be used if only one async request is needed, instead the single read/write
  856. async routines should be called.
  857. A context parameter is initialized, to serve as a communications area
  858. between here and the common completion routine. This initialization
  859. includes allocation of a spinlock. The spinlock is deallocated in the
  860. RxWaitSync routine, so it is essential that the caller insure that
  861. this routine is always called under all circumstances following a call
  862. to this routine.
  863. Next this routine reads or writes one or more contiguous sectors from
  864. a device asynchronously, and is used if there are multiple reads for a
  865. master IRP. A completion routine is used to synchronize with the
  866. completion of all of the I/O requests started by calls to this routine.
  867. Also, prior to calling this routine the caller must initialize the
  868. IoStatus field in the Context, with the correct success status and byte
  869. count which are expected if all of the parallel transfers complete
  870. successfully. After return this status will be unchanged if all requests
  871. were, in fact, successful. However, if one or more errors occur, the
  872. IoStatus will be modified to reflect the error status and byte count
  873. from the first run (by Vbo) which encountered an error. I/O status
  874. from all subsequent runs will not be indicated.
  875. Arguments:
  876. RxContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
  877. Vcb - Supplies the device to be read
  878. MasterIrp - Supplies the master Irp.
  879. MulitpleIrpCount - Supplies the number of multiple async requests
  880. that will be issued against the master irp.
  881. IoRuns - Supplies an array containing the Vbo, Lbo, BufferOffset, and
  882. ByteCount for all the runs to executed in parallel.
  883. Return Value:
  884. None.
  885. --*/
  886. {
  887. PIRP Irp;
  888. PIO_STACK_LOCATION IrpSp;
  889. PMDL Mdl;
  890. BOOLEAN Wait;
  891. PRDBSS_IO_CONTEXT Context;
  892. ULONG UnwindRunCount = 0;
  893. BOOLEAN ExceptionExpected = TRUE;
  894. BOOLEAN CalledByRxVerifyVolume = FALSE;
  895. DebugTrace(+1, Dbg, "RxMultipleAsync\n", 0);
  896. DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", RxContext->MajorFunction );
  897. DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
  898. DebugTrace( 0, Dbg, "MasterIrp = %08lx\n", MasterIrp );
  899. DebugTrace( 0, Dbg, "MultipleIrpCount = %08lx\n", MultipleIrpCount );
  900. DebugTrace( 0, Dbg, "IoRuns = %08lx\n", IoRuns );
  901. //
  902. // If this I/O originating during RxVerifyVolume, bypass the
  903. // verify logic.
  904. //
  905. if ( Vcb->VerifyThread == KeGetCurrentThread() ) {
  906. CalledByRxVerifyVolume = TRUE;
  907. }
  908. //
  909. // Set up things according to whether this is truely async.
  910. //
  911. Wait = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
  912. Context = RxContext->RxIoContext;
  913. //
  914. // Finish initializing Context, for use in Read/Write Multiple Asynch.
  915. //
  916. Context->MasterIrp = MasterIrp;
  917. try {
  918. //
  919. // Itterate through the runs, doing everything that can fail
  920. //
  921. for ( UnwindRunCount = 0;
  922. UnwindRunCount < MultipleIrpCount;
  923. UnwindRunCount++ ) {
  924. //
  925. // Create an associated IRP, making sure there is one stack entry for
  926. // us, as well.
  927. //
  928. IoRuns[UnwindRunCount].SavedIrp = 0;
  929. Irp = IoMakeAssociatedIrp( MasterIrp,
  930. (CCHAR)(Vcb->TargetDeviceObject->StackSize + 1) );
  931. if (Irp == NULL) {
  932. RxRaiseStatus( RxContext, RxStatus(INSUFFICIENT_RESOURCES) );
  933. }
  934. IoRuns[UnwindRunCount].SavedIrp = Irp;
  935. //
  936. // Allocate and build a partial Mdl for the request.
  937. //
  938. Mdl = IoAllocateMdl( (PCHAR)MasterIrp->UserBuffer +
  939. IoRuns[UnwindRunCount].Offset,
  940. IoRuns[UnwindRunCount].ByteCount,
  941. FALSE,
  942. FALSE,
  943. Irp );
  944. if (Mdl == NULL) {
  945. RxRaiseStatus( RxContext, RxStatus(INSUFFICIENT_RESOURCES) );
  946. }
  947. //
  948. // Sanity Check
  949. //
  950. ASSERT( Mdl == Irp->MdlAddress );
  951. IoBuildPartialMdl( MasterIrp->MdlAddress,
  952. Mdl,
  953. (PCHAR)MasterIrp->UserBuffer +
  954. IoRuns[UnwindRunCount].Offset,
  955. IoRuns[UnwindRunCount].ByteCount );
  956. //
  957. // Get the first IRP stack location in the associated Irp
  958. //
  959. IoSetNextIrpStackLocation( Irp );
  960. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  961. //
  962. // Setup the Stack location to describe our read.
  963. //
  964. IrpSp->MajorFunction = RxContext->MajorFunction;
  965. IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].ByteCount;
  966. IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].Vbo;
  967. //
  968. // Set up the completion routine address in our stack frame.
  969. //
  970. IoSetCompletionRoutine( Irp,
  971. Wait ?
  972. &RxMultiSyncCompletionRoutine :
  973. &RxMultiAsyncCompletionRoutine,
  974. Context,
  975. TRUE,
  976. TRUE,
  977. TRUE );
  978. //
  979. // Setup the next IRP stack location in the associated Irp for the disk
  980. // driver beneath us.
  981. //
  982. IrpSp = IoGetNextIrpStackLocation( Irp );
  983. //
  984. // Setup the Stack location to do a read from the disk driver.
  985. //
  986. IrpSp->MajorFunction = RxContext->MajorFunction;
  987. IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].ByteCount;
  988. IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].Lbo;
  989. //
  990. // If this Irp is the result of a WriteThough operation,
  991. // tell the device to write it through.
  992. //
  993. if (FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH)) {
  994. SetFlag( IrpSp->Flags, SL_WRITE_THROUGH );
  995. }
  996. //
  997. // If this I/O originating during RxVerifyVolume, bypass the
  998. // verify logic.
  999. //
  1000. if ( CalledByRxVerifyVolume ) {
  1001. SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  1002. }
  1003. }
  1004. //
  1005. // Now we no longer expect an exception. If the driver raises, we
  1006. // must bugcheck, because we do not know how to recover from that
  1007. // case.
  1008. //
  1009. ExceptionExpected = FALSE;
  1010. //
  1011. // We only need to set the associated IRP count in the master irp to
  1012. // make it a master IRP. But we set the count to one more than our
  1013. // caller requested, because we do not want the I/O system to complete
  1014. // the I/O. We also set our own count.
  1015. //
  1016. Context->IrpCount = MultipleIrpCount;
  1017. MasterIrp->AssociatedIrp.IrpCount = MultipleIrpCount;
  1018. if (Wait) {
  1019. MasterIrp->AssociatedIrp.IrpCount += 1;
  1020. }
  1021. //
  1022. // Now that all the dangerous work is done, issue the read requests
  1023. //
  1024. for (UnwindRunCount = 0;
  1025. UnwindRunCount < MultipleIrpCount;
  1026. UnwindRunCount++) {
  1027. Irp = IoRuns[UnwindRunCount].SavedIrp;
  1028. DebugDoit( RxIoCallDriverCount += 1);
  1029. //
  1030. // If IoCallDriver returns an error, it has completed the Irp
  1031. // and the error will be caught by our completion routines
  1032. // and dealt with as a normal IO error.
  1033. //
  1034. (VOID)RxLowLevelReadWrite( RxContext,
  1035. Vcb->TargetDeviceObject,
  1036. Irp,
  1037. Vcb );
  1038. }
  1039. } finally {
  1040. ULONG i;
  1041. DebugUnwind( RxMultipleAsync );
  1042. //
  1043. // Only allocating the spinlock, making the associated Irps
  1044. // and allocating the Mdls can fail.
  1045. //
  1046. if ( AbnormalTermination() ) {
  1047. //
  1048. // If the driver raised, we are hosed. He is not supposed to raise,
  1049. // and it is impossible for us to figure out how to clean up.
  1050. //
  1051. if (!ExceptionExpected) {
  1052. ASSERT( ExceptionExpected );
  1053. RxBugCheck( 0, 0, 0 );
  1054. }
  1055. //
  1056. // Unwind
  1057. //
  1058. for (i = 0; i <= UnwindRunCount; i++) {
  1059. if ( (Irp = IoRuns[i].SavedIrp) != NULL ) {
  1060. if ( Irp->MdlAddress != NULL ) {
  1061. IoFreeMdl( Irp->MdlAddress );
  1062. }
  1063. IoFreeIrp( Irp );
  1064. }
  1065. }
  1066. }
  1067. //
  1068. // And return to our caller
  1069. //
  1070. DebugTrace(-1, Dbg, "RxMultipleAsync -> VOID\n", 0);
  1071. }
  1072. return;
  1073. }
  1074. VOID
  1075. RxSingleAsync (
  1076. IN PRX_CONTEXT RxContext,
  1077. IN PVCB Vcb,
  1078. IN LBO Lbo,
  1079. IN ULONG ByteCount,
  1080. IN PIRP Irp
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. This routine reads or writes one or more contiguous sectors from a device
  1085. asynchronously, and is used if there is only one read necessary to
  1086. complete the IRP. It implements the read by simply filling
  1087. in the next stack frame in the Irp, and passing it on. The transfer
  1088. occurs to the single buffer originally specified in the user request.
  1089. Arguments:
  1090. RxContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
  1091. Vcb - Supplies the device to read
  1092. Lbo - Supplies the starting Logical Byte Offset to begin reading from
  1093. ByteCount - Supplies the number of bytes to read from the device
  1094. Irp - Supplies the master Irp to associated with the async
  1095. request.
  1096. Return Value:
  1097. None.
  1098. --*/
  1099. {
  1100. PIO_STACK_LOCATION IrpSp;
  1101. DebugTrace(+1, Dbg, "RxSingleAsync\n", 0);
  1102. DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", RxContext->MajorFunction );
  1103. DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
  1104. DebugTrace( 0, Dbg, "Lbo = %08lx\n", Lbo);
  1105. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
  1106. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  1107. //
  1108. // Set up the completion routine address in our stack frame.
  1109. //
  1110. IoSetCompletionRoutine( Irp,
  1111. FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT) ?
  1112. &RxSingleSyncCompletionRoutine :
  1113. &RxSingleAsyncCompletionRoutine,
  1114. RxContext->RxIoContext,
  1115. TRUE,
  1116. TRUE,
  1117. TRUE );
  1118. //
  1119. // Setup the next IRP stack location in the associated Irp for the disk
  1120. // driver beneath us.
  1121. //
  1122. IrpSp = IoGetNextIrpStackLocation( Irp );
  1123. //
  1124. // Setup the Stack location to do a read from the disk driver.
  1125. //
  1126. IrpSp->MajorFunction = RxContext->MajorFunction;
  1127. IrpSp->Parameters.Read.Length = ByteCount;
  1128. IrpSp->Parameters.Read.ByteOffset.QuadPart = Lbo;
  1129. //
  1130. // If this Irp is the result of a WriteThough operation,
  1131. // tell the device to write it through.
  1132. //
  1133. if (FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH)) {
  1134. SetFlag( IrpSp->Flags, SL_WRITE_THROUGH );
  1135. }
  1136. //
  1137. // If this I/O originating during RxVerifyVolume, bypass the
  1138. // verify logic.
  1139. //
  1140. if ( Vcb->VerifyThread == KeGetCurrentThread() ) {
  1141. SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  1142. }
  1143. //
  1144. // Issue the read request
  1145. //
  1146. DebugDoit( RxIoCallDriverCount += 1);
  1147. //
  1148. // If IoCallDriver returns an error, it has completed the Irp
  1149. // and the error will be caught by our completion routines
  1150. // and dealt with as a normal IO error.
  1151. //
  1152. (VOID)RxLowLevelReadWrite( RxContext,
  1153. Vcb->TargetDeviceObject,
  1154. Irp,
  1155. Vcb );
  1156. //
  1157. // And return to our caller
  1158. //
  1159. DebugTrace(-1, Dbg, "RxSingleAsync -> VOID\n", 0);
  1160. return;
  1161. }
  1162. VOID
  1163. RxSingleNonAlignedSync (
  1164. IN PRX_CONTEXT RxContext,
  1165. IN PVCB Vcb,
  1166. IN PUCHAR Buffer,
  1167. IN LBO Lbo,
  1168. IN ULONG ByteCount,
  1169. IN PIRP Irp
  1170. )
  1171. /*++
  1172. Routine Description:
  1173. This routine reads or writes one or more contiguous sectors from a device
  1174. Synchronously, and does so to a buffer that must come from non paged
  1175. pool. It saves a pointer to the Irp's original Mdl, and creates a new
  1176. one describing the given buffer. It implements the read by simply filling
  1177. in the next stack frame in the Irp, and passing it on. The transfer
  1178. occurs to the single buffer originally specified in the user request.
  1179. Arguments:
  1180. RxContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
  1181. Vcb - Supplies the device to read
  1182. Buffer - Supplies a buffer from non-paged pool.
  1183. Lbo - Supplies the starting Logical Byte Offset to begin reading from
  1184. ByteCount - Supplies the number of bytes to read from the device
  1185. Irp - Supplies the master Irp to associated with the async
  1186. request.
  1187. Return Value:
  1188. None.
  1189. --*/
  1190. {
  1191. PIO_STACK_LOCATION IrpSp;
  1192. PMDL Mdl;
  1193. PMDL SavedMdl;
  1194. DebugTrace(+1, Dbg, "RxSingleNonAlignedAsync\n", 0);
  1195. DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", RxContext->MajorFunction );
  1196. DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
  1197. DebugTrace( 0, Dbg, "Buffer = %08lx\n", Buffer );
  1198. DebugTrace( 0, Dbg, "Lbo = %08lx\n", Lbo);
  1199. DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
  1200. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  1201. //
  1202. // Create a new Mdl describing the buffer, saving the current one in the
  1203. // Irp
  1204. //
  1205. SavedMdl = Irp->MdlAddress;
  1206. Irp->MdlAddress = 0;
  1207. Mdl = IoAllocateMdl( Buffer,
  1208. ByteCount,
  1209. FALSE,
  1210. FALSE,
  1211. Irp );
  1212. if (Mdl == NULL) {
  1213. Irp->MdlAddress = SavedMdl;
  1214. RxRaiseStatus( RxContext, RxStatus(INSUFFICIENT_RESOURCES) );
  1215. }
  1216. //
  1217. // Lock the new Mdl in memory.
  1218. //
  1219. try {
  1220. MmProbeAndLockPages( Mdl, KernelMode, IoWriteAccess );
  1221. } finally {
  1222. if ( AbnormalTermination() ) {
  1223. IoFreeMdl( Mdl );
  1224. }
  1225. }
  1226. //
  1227. // Set up the completion routine address in our stack frame.
  1228. //
  1229. IoSetCompletionRoutine( Irp,
  1230. &RxSingleSyncCompletionRoutine,
  1231. RxContext->RxIoContext,
  1232. TRUE,
  1233. TRUE,
  1234. TRUE );
  1235. //
  1236. // Setup the next IRP stack location in the associated Irp for the disk
  1237. // driver beneath us.
  1238. //
  1239. IrpSp = IoGetNextIrpStackLocation( Irp );
  1240. //
  1241. // Setup the Stack location to do a read from the disk driver.
  1242. //
  1243. IrpSp->MajorFunction = RxContext->MajorFunction;
  1244. IrpSp->Parameters.Read.Length = ByteCount;
  1245. IrpSp->Parameters.Read.ByteOffset.QuadPart = Lbo;
  1246. //
  1247. // If this I/O originating during RxVerifyVolume, bypass the
  1248. // verify logic.
  1249. //
  1250. if ( Vcb->VerifyThread == KeGetCurrentThread() ) {
  1251. SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  1252. }
  1253. //
  1254. // Issue the read request
  1255. //
  1256. DebugDoit( RxIoCallDriverCount += 1);
  1257. //
  1258. // If IoCallDriver returns an error, it has completed the Irp
  1259. // and the error will be caught by our completion routines
  1260. // and dealt with as a normal IO error.
  1261. //
  1262. try {
  1263. (VOID)RxLowLevelReadWrite( RxContext,
  1264. Vcb->TargetDeviceObject,
  1265. Irp,
  1266. Vcb );
  1267. RxWaitSync( RxContext );
  1268. } finally {
  1269. MmUnlockPages( Mdl );
  1270. IoFreeMdl( Mdl );
  1271. Irp->MdlAddress = SavedMdl;
  1272. }
  1273. //
  1274. // And return to our caller
  1275. //
  1276. DebugTrace(-1, Dbg, "RxSingleNonAlignedSync -> VOID\n", 0);
  1277. return;
  1278. }
  1279. //
  1280. // Internal Support Routine
  1281. //
  1282. RXSTATUS
  1283. RxMultiSyncCompletionRoutine (
  1284. IN PDEVICE_OBJECT DeviceObject,
  1285. IN PIRP Irp,
  1286. IN PVOID Contxt
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. This is the completion routine for all reads and writes started via
  1291. RxRead/WriteMultipleAsynch. It must synchronize its operation for
  1292. multiprocessor environments with itself on all other processors, via
  1293. a spin lock found via the Context parameter.
  1294. The completion routine has the following responsibilities:
  1295. If the individual request was completed with an error, then
  1296. this completion routine must see if this is the first error
  1297. (essentially by Vbo), and if so it must correctly reduce the
  1298. byte count and remember the error status in the Context.
  1299. If the IrpCount goes to 1, then it sets the event in the Context
  1300. parameter to signal the caller that all of the asynch requests
  1301. are done.
  1302. Arguments:
  1303. DeviceObject - Pointer to the file system device object.
  1304. Irp - Pointer to the associated Irp which is being completed. (This
  1305. Irp will no longer be accessible after this routine returns.)
  1306. Contxt - The context parameter which was specified for all of
  1307. the multiple asynch I/O requests for this MasterIrp.
  1308. Return Value:
  1309. The routine returns RxStatus(MORE_PROCESSING_REQUIRED) so that we can
  1310. immediately complete the Master Irp without being in a race condition
  1311. with the IoCompleteRequest thread trying to decrement the IrpCount in
  1312. the Master Irp.
  1313. --*/
  1314. {
  1315. PRDBSS_IO_CONTEXT Context = Contxt;
  1316. PIRP MasterIrp = Context->MasterIrp;
  1317. DebugTrace(+1, Dbg, "RxMultiSyncCompletionRoutine, Context = %08lx\n", Context );
  1318. //
  1319. // If we got an error (or verify required), remember it in the Irp
  1320. //
  1321. MasterIrp = Context->MasterIrp;
  1322. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  1323. MasterIrp->IoStatus = Irp->IoStatus;
  1324. }
  1325. //
  1326. // We must do this here since IoCompleteRequest won't get a chance
  1327. // on this associated Irp.
  1328. //
  1329. IoFreeMdl( Irp->MdlAddress );
  1330. IoFreeIrp( Irp );
  1331. //
  1332. // Use a spin lock to synchronize access to Context->IrpCount.
  1333. //
  1334. if (ExInterlockedDecrementLong(&Context->IrpCount,
  1335. &RxData.StrucSupSpinLock) == RESULT_ZERO) {
  1336. KeSetEvent( &Context->Wait.SyncEvent, 0, FALSE );
  1337. }
  1338. DebugTrace(-1, Dbg, "RxMultiSyncCompletionRoutine -> SUCCESS\n", 0 );
  1339. UNREFERENCED_PARAMETER( DeviceObject );
  1340. return RxStatus(MORE_PROCESSING_REQUIRED);
  1341. }
  1342. //
  1343. // Internal Support Routine
  1344. //
  1345. RXSTATUS
  1346. RxMultiAsyncCompletionRoutine (
  1347. IN PDEVICE_OBJECT DeviceObject,
  1348. IN PIRP Irp,
  1349. IN PVOID Contxt
  1350. )
  1351. /*++
  1352. Routine Description:
  1353. This is the completion routine for all reads and writes started via
  1354. RxRead/WriteMultipleAsynch. It must synchronize its operation for
  1355. multiprocessor environments with itself on all other processors, via
  1356. a spin lock found via the Context parameter.
  1357. The completion routine has has the following responsibilities:
  1358. If the individual request was completed with an error, then
  1359. this completion routine must see if this is the first error
  1360. (essentially by Vbo), and if so it must correctly reduce the
  1361. byte count and remember the error status in the Context.
  1362. If the IrpCount goes to 1, then it sets the event in the Context
  1363. parameter to signal the caller that all of the asynch requests
  1364. are done.
  1365. Arguments:
  1366. DeviceObject - Pointer to the file system device object.
  1367. Irp - Pointer to the associated Irp which is being completed. (This
  1368. Irp will no longer be accessible after this routine returns.)
  1369. Contxt - The context parameter which was specified for all of
  1370. the multiple asynch I/O requests for this MasterIrp.
  1371. Return Value:
  1372. The routine returns RxStatus(MORE_PROCESSING_REQUIRED) so that we can
  1373. immediately complete the Master Irp without being in a race condition
  1374. with the IoCompleteRequest thread trying to decrement the IrpCount in
  1375. the Master Irp.
  1376. --*/
  1377. {
  1378. PRDBSS_IO_CONTEXT Context = Contxt;
  1379. PIRP MasterIrp = Context->MasterIrp;
  1380. DebugTrace(+1, Dbg, "RxMultiAsyncCompletionRoutine, Context = %08lx\n", Context );
  1381. //
  1382. // If we got an error (or verify required), remember it in the Irp
  1383. //
  1384. MasterIrp = Context->MasterIrp;
  1385. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  1386. MasterIrp->IoStatus = Irp->IoStatus;
  1387. }
  1388. //
  1389. // Use a spin lock to synchronize access to Context->IrpCount.
  1390. //
  1391. if (ExInterlockedDecrementLong(&Context->IrpCount,
  1392. &RxData.StrucSupSpinLock) == RESULT_ZERO) {
  1393. if (NT_SUCCESS(MasterIrp->IoStatus.Status)) {
  1394. MasterIrp->IoStatus.Information =
  1395. Context->Wait.Async.RequestedByteCount;
  1396. //
  1397. // Now if this wasn't PagingIo, set either the read or write bit.
  1398. //
  1399. if (!FlagOn(MasterIrp->Flags, IRP_PAGING_IO)) {
  1400. SetFlag( Context->Wait.Async.FileObject->Flags,
  1401. IoGetCurrentIrpStackLocation(MasterIrp)->MajorFunction == IRP_MJ_READ ?
  1402. FO_FILE_FAST_IO_READ : FO_FILE_MODIFIED );
  1403. }
  1404. }
  1405. //
  1406. // If this was a special async write, decrement the count. Set the
  1407. // event if this was the final outstanding I/O for the file. We will
  1408. // also want to queue an APC to deal with any error conditionions.
  1409. //
  1410. if ((Context->Wait.Async.NonPagedFcb) &&
  1411. (ExInterlockedAddUlong( &Context->Wait.Async.NonPagedFcb->OutstandingAsyncWrites,
  1412. 0xffffffff,
  1413. &RxStrucSupSpinLock ) == 1)) {
  1414. KeSetEvent( Context->Wait.Async.NonPagedFcb->OutstandingAsyncEvent, 0, FALSE );
  1415. }
  1416. //
  1417. // Now release the resource
  1418. //
  1419. if (Context->Wait.Async.Resource != NULL) {
  1420. ExReleaseResourceForThread( Context->Wait.Async.Resource,
  1421. Context->Wait.Async.ResourceThreadId );
  1422. }
  1423. //
  1424. // Mark the master Irp pending
  1425. //
  1426. IoMarkIrpPending( MasterIrp );
  1427. //
  1428. // and finally, free the context record.
  1429. //
  1430. ExFreePool( Context );
  1431. }
  1432. DebugTrace(-1, Dbg, "RxMultiAsyncCompletionRoutine -> SUCCESS\n", 0 );
  1433. UNREFERENCED_PARAMETER( DeviceObject );
  1434. return RxStatus(SUCCESS);
  1435. }
  1436. //
  1437. // Internal Support Routine
  1438. //
  1439. RXSTATUS
  1440. RxPagingFileCompletionRoutine (
  1441. IN PDEVICE_OBJECT DeviceObject,
  1442. IN PIRP Irp,
  1443. IN PVOID MasterIrp
  1444. )
  1445. /*++
  1446. Routine Description:
  1447. This is the completion routine for all reads and writes started via
  1448. RxPagingFileIo. It should only be invoked on error or cancel.
  1449. The completion routine has has the following responsibility:
  1450. Since the individual request was completed with an error,
  1451. this completion routine must stuff it into the master irp.
  1452. If the error implies a media problem, it also enqueues a
  1453. worker item to write out the dirty bit so that the next
  1454. time we run we will do a autochk /r
  1455. Arguments:
  1456. DeviceObject - Pointer to the file system device object.
  1457. Irp - Pointer to the associated Irp which is being completed. (This
  1458. Irp will no longer be accessible after this routine returns.)
  1459. MasterIrp - Pointer to the master Irp.
  1460. Return Value:
  1461. Always returns RxStatus(SUCCESS).
  1462. --*/
  1463. {
  1464. RXSTATUS Status;
  1465. DebugTrace(+1, Dbg, "RxPagingFileCompletionRoutine, MasterIrp = %08lx\n", MasterIrp );
  1466. //
  1467. // If we got an error (or verify required), remember it in the Irp
  1468. //
  1469. ASSERT( !NT_SUCCESS( Irp->IoStatus.Status ));
  1470. //
  1471. // If we were invoked with an assoicated Irp, copy the error over.
  1472. //
  1473. if (Irp != MasterIrp) {
  1474. ((PIRP)MasterIrp)->IoStatus = Irp->IoStatus;
  1475. }
  1476. //
  1477. // If this was a media error, we want to chkdsk /r the next time we boot.
  1478. //
  1479. if (FsRtlIsTotalDeviceFailure(Irp->IoStatus.Status)) {
  1480. Status = RxStatus(SUCCESS);
  1481. } else {
  1482. PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
  1483. //
  1484. // We are going to try to mark the volume needing recover.
  1485. // If we can't get pool, oh well....
  1486. //
  1487. Packet = ExAllocatePool(NonPagedPool, sizeof(CLEAN_AND_DIRTY_VOLUME_PACKET));
  1488. if ( Packet ) {
  1489. Packet->Vcb = &((PRDBSS_DEVICE_OBJECT)IoGetCurrentIrpStackLocation(Irp)->DeviceObject)->Vcb;
  1490. Packet->Irp = Irp;
  1491. ExInitializeWorkItem( &Packet->Item,
  1492. &RxFspMarkVolumeDirtyWithRecover,
  1493. Packet );
  1494. ExQueueWorkItem( &Packet->Item, CriticalWorkQueue );
  1495. Status = RxStatus(MORE_PROCESSING_REQUIRED);
  1496. } else {
  1497. Status = RxStatus(SUCCESS);
  1498. }
  1499. }
  1500. DebugTrace(-1, Dbg, "RxPagingFileCompletionRoutine => (RxStatus(SUCCESS))\n", 0 );
  1501. UNREFERENCED_PARAMETER( DeviceObject );
  1502. return Status;
  1503. }
  1504. //
  1505. // Internal Support Routine
  1506. //
  1507. RXSTATUS
  1508. RxSingleSyncCompletionRoutine (
  1509. IN PDEVICE_OBJECT DeviceObject,
  1510. IN PIRP Irp,
  1511. IN PVOID Contxt
  1512. )
  1513. /*++
  1514. Routine Description:
  1515. This is the completion routine for all reads and writes started via
  1516. RxRead/WriteSingleAsynch.
  1517. The completion routine has has the following responsibilities:
  1518. Copy the I/O status from the Irp to the Context, since the Irp
  1519. will no longer be accessible.
  1520. It sets the event in the Context parameter to signal the caller
  1521. that all of the asynch requests are done.
  1522. Arguments:
  1523. DeviceObject - Pointer to the file system device object.
  1524. Irp - Pointer to the Irp for this request. (This Irp will no longer
  1525. be accessible after this routine returns.)
  1526. Contxt - The context parameter which was specified in the call to
  1527. RxRead/WriteSingleAsynch.
  1528. Return Value:
  1529. Currently always returns RxStatus(SUCCESS).
  1530. --*/
  1531. {
  1532. PRDBSS_IO_CONTEXT Context = Contxt;
  1533. DebugTrace(+1, Dbg, "RxSingleSyncCompletionRoutine, Context = %08lx\n", Context );
  1534. KeSetEvent( &Context->Wait.SyncEvent, 0, FALSE );
  1535. DebugTrace(-1, Dbg, "RxSingleSyncCompletionRoutine -> RxStatus(MORE_PROCESSING_REQUIRED\n)", 0 );
  1536. UNREFERENCED_PARAMETER( DeviceObject );
  1537. return RxStatus(MORE_PROCESSING_REQUIRED);
  1538. }
  1539. //
  1540. // Internal Support Routine
  1541. //
  1542. RXSTATUS
  1543. RxSingleAsyncCompletionRoutine (
  1544. IN PDEVICE_OBJECT DeviceObject,
  1545. IN PIRP Irp,
  1546. IN PVOID Contxt
  1547. )
  1548. /*++
  1549. Routine Description:
  1550. This is the completion routine for all reads and writes started via
  1551. RxRead/WriteSingleAsynch.
  1552. The completion routine has has the following responsibilities:
  1553. Copy the I/O status from the Irp to the Context, since the Irp
  1554. will no longer be accessible.
  1555. It sets the event in the Context parameter to signal the caller
  1556. that all of the asynch requests are done.
  1557. Arguments:
  1558. DeviceObject - Pointer to the file system device object.
  1559. Irp - Pointer to the Irp for this request. (This Irp will no longer
  1560. be accessible after this routine returns.)
  1561. Contxt - The context parameter which was specified in the call to
  1562. RxRead/WriteSingleAsynch.
  1563. Return Value:
  1564. Currently always returns RxStatus(SUCCESS).
  1565. --*/
  1566. {
  1567. PRDBSS_IO_CONTEXT Context = Contxt;
  1568. DebugTrace(+1, Dbg, "RxSingleAsyncCompletionRoutine, Context = %08lx\n", Context );
  1569. //
  1570. // Fill in the information field correctedly if this worked.
  1571. //
  1572. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  1573. Irp->IoStatus.Information = Context->Wait.Async.RequestedByteCount;
  1574. //
  1575. // Now if this wasn't PagingIo, set either the read or write bit.
  1576. //
  1577. if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  1578. SetFlag( Context->Wait.Async.FileObject->Flags,
  1579. IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_READ ?
  1580. FO_FILE_FAST_IO_READ : FO_FILE_MODIFIED );
  1581. }
  1582. }
  1583. //
  1584. // If this was a special async write, decrement the count. Set the
  1585. // event if this was the final outstanding I/O for the file. We will
  1586. // also want to queue an APC to deal with any error conditionions.
  1587. //
  1588. if ((Context->Wait.Async.NonPagedFcb) &&
  1589. (ExInterlockedAddUlong( &Context->Wait.Async.NonPagedFcb->OutstandingAsyncWrites,
  1590. 0xffffffff,
  1591. &RxStrucSupSpinLock ) == 1)) {
  1592. KeSetEvent( Context->Wait.Async.NonPagedFcb->OutstandingAsyncEvent, 0, FALSE );
  1593. }
  1594. //
  1595. // Now release the resource
  1596. //
  1597. if (Context->Wait.Async.Resource != NULL) {
  1598. ExReleaseResourceForThread( Context->Wait.Async.Resource,
  1599. Context->Wait.Async.ResourceThreadId );
  1600. }
  1601. //
  1602. // Mark the Irp pending
  1603. //
  1604. IoMarkIrpPending( Irp );
  1605. //
  1606. // and finally, free the context record.
  1607. //
  1608. ExFreePool( Context );
  1609. DebugTrace(-1, Dbg, "RxSingleAsyncCompletionRoutine -> RxStatus(MORE_PROCESSING_REQUIRED\n)", 0 );
  1610. UNREFERENCED_PARAMETER( DeviceObject );
  1611. return RxStatus(SUCCESS);
  1612. }
  1613. VOID
  1614. RxToggleMediaEjectDisable (
  1615. IN PRX_CONTEXT RxContext,
  1616. IN PVCB Vcb,
  1617. IN BOOLEAN PreventRemoval
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. The routine either enables or disables the eject button on removable
  1622. media. Any error conditions are ignored.
  1623. Arguments:
  1624. Vcb - Descibes the volume to operate on
  1625. PreventRemoval - TRUE if we should disable the media eject button. FALSE
  1626. if we want to enable it.
  1627. Return Value:
  1628. None.
  1629. --*/
  1630. {
  1631. PIRP Irp;
  1632. KEVENT Event;
  1633. RXSTATUS Status;
  1634. IO_STATUS_BLOCK Iosb;
  1635. PREVENT_MEDIA_REMOVAL Prevent;
  1636. Prevent.PreventMediaRemoval = PreventRemoval;
  1637. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  1638. Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_MEDIA_REMOVAL,
  1639. Vcb->Vpb->RealDevice,
  1640. &Prevent,
  1641. sizeof(PREVENT_MEDIA_REMOVAL),
  1642. NULL,
  1643. 0,
  1644. FALSE,
  1645. &Event,
  1646. &Iosb );
  1647. if ( Irp != NULL ) {
  1648. Status = IoCallDriver( Vcb->TargetDeviceObject, Irp );
  1649. if (Status == RxStatus(PENDING)) {
  1650. Status = KeWaitForSingleObject( &Event,
  1651. Executive,
  1652. KernelMode,
  1653. FALSE,
  1654. NULL );
  1655. }
  1656. }
  1657. }
  1658. #ifdef WE_WON_ON_APPEAL
  1659. RXSTATUS
  1660. RxLowLevelDblsReadWrite (
  1661. PRX_CONTEXT RxContext,
  1662. PIRP Irp,
  1663. PVCB Vcb
  1664. )
  1665. /*++
  1666. Routine Description:
  1667. This routine passes on a non-cached read or write request to the
  1668. double space routines. The status is extracted from an exception
  1669. handler in case of error.
  1670. Arguments:
  1671. Vcb - Descibes the volume to operate on.
  1672. Irp - Supplies the parameters for the read/write operation.
  1673. Return Value:
  1674. The Status of the read or write operation.
  1675. --*/
  1676. {
  1677. PIO_STACK_LOCATION IrpSp;
  1678. ULONG BytesTransfered = 0;
  1679. RXSTATUS Status = RxStatus(SUCCESS);
  1680. IrpSp = IoGetNextIrpStackLocation( Irp );
  1681. try {
  1682. #ifdef DOUBLE_SPACE_WRITE
  1683. BytesTransfered = (IrpSp->MajorFunction == IRP_MJ_READ) ?
  1684. RxDblsReadData( RxContext,
  1685. Vcb->Dscb,
  1686. IrpSp->Parameters.Read.ByteOffset.LowPart,
  1687. MmGetSystemAddressForMdl( Irp->MdlAddress ),
  1688. IrpSp->Parameters.Read.Length )
  1689. :
  1690. RxDblsWriteData( RxContext,
  1691. Vcb->Dscb,
  1692. IrpSp->Parameters.Write.ByteOffset.LowPart,
  1693. MmGetSystemAddressForMdl( Irp->MdlAddress ),
  1694. IrpSp->Parameters.Write.Length );
  1695. #else
  1696. BytesTransfered =
  1697. RxDblsReadData( RxContext,
  1698. Vcb->Dscb,
  1699. IrpSp->Parameters.Read.ByteOffset.LowPart,
  1700. MmGetSystemAddressForMdl( Irp->MdlAddress ),
  1701. IrpSp->Parameters.Read.Length );
  1702. #endif // DOUBLE_SPACE_WRITE
  1703. } except(RxExceptionFilter( RxContext, GetExceptionInformation() )) {
  1704. Status = RxContext->ExceptionStatus;
  1705. RxContext->ExceptionStatus = 0;
  1706. }
  1707. //
  1708. // Load up the Status in the Irp
  1709. //
  1710. Irp->IoStatus.Status = Status;
  1711. Irp->IoStatus.Information = BytesTransfered;
  1712. //
  1713. // Update the IRP stack to point to the next location so that our
  1714. // completion routine will get called.
  1715. //
  1716. Irp->CurrentLocation--;
  1717. Irp->Tail.Overlay.CurrentStackLocation--;
  1718. if (Irp->CurrentLocation <= 0) {
  1719. KeBugCheckEx( NO_MORE_IRP_STACK_LOCATIONS, (ULONG) Irp, 0, 0, 0 );
  1720. }
  1721. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  1722. return Status;
  1723. }
  1724. #endif // WE_WON_ON_APPEAL
  1725.