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.

1756 lines
39 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. VerfySup.c
  5. Abstract:
  6. This module implements the Rx Verify volume and fcb/dcb support
  7. routines
  8. Author:
  9. Gary Kimura [GaryKi] 01-Jun-1990
  10. Revision History:
  11. --*/
  12. // ----------------------joejoe-----------found-------------#include "RxProcs.h"
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (RDBSS_BUG_CHECK_VERFYSUP)
  19. //
  20. // The Debug trace level for this module
  21. //
  22. #define Dbg (DEBUG_TRACE_VERFYSUP)
  23. //
  24. // Local procedure prototypes
  25. //
  26. VOID
  27. RxResetFcb (
  28. IN PRX_CONTEXT RxContext,
  29. IN PFCB Fcb
  30. );
  31. VOID
  32. RxDetermineAndMarkFcbCondition (
  33. IN PRX_CONTEXT RxContext,
  34. IN PFCB Fcb
  35. );
  36. VOID
  37. RxDeferredCleanVolume (
  38. PVOID Parameter
  39. );
  40. RXSTATUS
  41. RxMarkDirtyCompletionRoutine(
  42. IN PDEVICE_OBJECT DeviceObject,
  43. IN PIRP Irp,
  44. IN PVOID Contxt
  45. );
  46. #ifdef ALLOC_PRAGMA
  47. #pragma alloc_text(PAGE, RxCheckDirtyBit)
  48. #pragma alloc_text(PAGE, RxVerifyOperationIsLegal)
  49. #pragma alloc_text(PAGE, RxDeferredCleanVolume)
  50. #pragma alloc_text(PAGE, RxDetermineAndMarkFcbCondition)
  51. #pragma alloc_text(PAGE, RxQuickVerifyVcb)
  52. #pragma alloc_text(PAGE, RxPerformVerify)
  53. #pragma alloc_text(PAGE, RxMarkFcbCondition)
  54. #pragma alloc_text(PAGE, RxMarkVolumeClean)
  55. #pragma alloc_text(PAGE, RxResetFcb)
  56. #pragma alloc_text(PAGE, RxVerifyVcb)
  57. #pragma alloc_text(PAGE, RxVerifyFcb)
  58. #endif
  59. VOID
  60. RxMarkFcbCondition (
  61. IN PRX_CONTEXT RxContext,
  62. IN PFCB Fcb,
  63. IN FCB_CONDITION FcbCondition
  64. )
  65. /*++
  66. Routine Description:
  67. This routines marks the entire Fcb/Dcb structure from Fcb down with
  68. FcbCondition.
  69. Arguments:
  70. Fcb - Supplies the Fcb/Dcb being marked
  71. FcbCondition - Supplies the setting to use for the Fcb Condition
  72. Return Value:
  73. None.
  74. --*/
  75. {
  76. DebugTrace(+1, Dbg, "RxMarkFcbCondition, Fcb = %08lx\n", Fcb );
  77. //
  78. // If we are marking this Fcb something other than Good, we will need
  79. // to have the Vcb exclusive.
  80. ASSERT( FcbCondition != FcbNeedsToBeVerified ? TRUE :
  81. RxVcbAcquiredExclusive(RxContext, Fcb->Vcb) );
  82. //
  83. // If this is a PagingFile it has to be good.
  84. //
  85. if (FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
  86. Fcb->FcbCondition = FcbGood;
  87. return;
  88. }
  89. //
  90. // Update the condition of the Fcb.
  91. //
  92. Fcb->FcbCondition = FcbCondition;
  93. DebugTrace(0, Dbg, "MarkFcb: %wZ\n", &Fcb->FullFileName);
  94. //
  95. // This FastIo flag is based on FcbCondition, so update it now.
  96. //
  97. Fcb->Header.IsFastIoPossible = RxIsFastIoPossible( Fcb );
  98. //
  99. // Now if we marked NeedsVerify or Bad a directory then we also need to
  100. // go and mark all of our children with the same condition.
  101. //
  102. if ( ((FcbCondition == FcbNeedsToBeVerified) ||
  103. (FcbCondition == FcbBad)) &&
  104. ((Fcb->Header.NodeTypeCode == RDBSS_NTC_DCB) ||
  105. (Fcb->Header.NodeTypeCode == RDBSS_NTC_ROOT_DCB)) ) {
  106. PFCB OriginalFcb = Fcb;
  107. while ( (Fcb = RxGetNextFcb(RxContext, Fcb, OriginalFcb)) != NULL ) {
  108. DebugTrace(0, Dbg, "MarkFcb: %wZ\n", &Fcb->FullFileName);
  109. Fcb->FcbCondition = FcbCondition;
  110. Fcb->Header.IsFastIoPossible = RxIsFastIoPossible( Fcb );
  111. }
  112. }
  113. DebugTrace(-1, Dbg, "RxMarkFcbCondition -> VOID\n", 0);
  114. return;
  115. }
  116. VOID
  117. RxVerifyVcb (
  118. IN PRX_CONTEXT RxContext,
  119. IN PVCB Vcb
  120. )
  121. /*++
  122. Routine Description:
  123. This routines verifies that the Vcb still denotes a valid Volume
  124. If the Vcb is bad it raises an error condition.
  125. Arguments:
  126. Vcb - Supplies the Vcb being verified
  127. Return Value:
  128. None.
  129. --*/
  130. {
  131. DebugTrace(+1, Dbg, "RxVerifyVcb, Vcb = %08lx\n", Vcb );
  132. //
  133. // If the media is removable and the verify volume flag in the
  134. // device object is not set then we want to ping the device
  135. // to see if it needs to be verified.
  136. //
  137. // Note that we only force this ping for create operations.
  138. // For others we take a sporting chance. If in the end we
  139. // have to physically access the disk, the right thing will happen.
  140. //
  141. if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
  142. !FlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME) ) {
  143. PIRP Irp;
  144. KEVENT Event;
  145. IO_STATUS_BLOCK Iosb;
  146. RXSTATUS Status;
  147. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  148. Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_CHECK_VERIFY,
  149. Vcb->TargetDeviceObject,
  150. NULL,
  151. 0,
  152. NULL,
  153. 0,
  154. FALSE,
  155. &Event,
  156. &Iosb );
  157. if ( Irp == NULL ) {
  158. RxRaiseStatus( RxContext, RxStatus(INSUFFICIENT_RESOURCES) );
  159. }
  160. Status = IoCallDriver( Vcb->TargetDeviceObject, Irp );
  161. if (Status == RxStatus(PENDING)) {
  162. Status = KeWaitForSingleObject( &Event,
  163. Executive,
  164. KernelMode,
  165. FALSE,
  166. NULL );
  167. ASSERT( Status == RxStatus(SUCCESS) );
  168. //
  169. // This may raise an error.
  170. //
  171. if ( !NT_SUCCESS(Iosb.Status) ) {
  172. RxNormalizeAndRaiseStatus( RxContext, Iosb.Status );
  173. }
  174. } else {
  175. //
  176. // This may raise an error.
  177. //
  178. if ( !NT_SUCCESS(Status) ) {
  179. RxNormalizeAndRaiseStatus( RxContext, Status );
  180. }
  181. }
  182. }
  183. //
  184. // Now that the verify bit has been appropriately set, check the Vcb.
  185. //
  186. RxQuickVerifyVcb( RxContext, Vcb );
  187. DebugTrace(-1, Dbg, "RxVerifyVcb -> VOID\n", 0);
  188. return;
  189. }
  190. VOID
  191. RxVerifyFcb (
  192. IN PRX_CONTEXT RxContext,
  193. IN PFCB Fcb
  194. )
  195. /*++
  196. Routine Description:
  197. This routines verifies that the Fcb still denotes the same file.
  198. If the Fcb is bad it raises a error condition.
  199. Arguments:
  200. Fcb - Supplies the Fcb being verified
  201. Return Value:
  202. None.
  203. --*/
  204. {
  205. PFCB CurrentFcb;
  206. DebugTrace(+1, Dbg, "RxVerifyFcb, Vcb = %08lx\n", Fcb );
  207. //
  208. // If this is the Fcb of a deleted dirent or our parent is deleted,
  209. // no-op this call with the hope that the caller will do the right thing.
  210. //
  211. if (IsFileDeleted( RxContext, Fcb ) ||
  212. ((NodeType(Fcb) != RDBSS_NTC_ROOT_DCB) &&
  213. IsFileDeleted( RxContext, Fcb->ParentDcb ))) {
  214. return;
  215. }
  216. //
  217. // If we are not in the process of doing a verify,
  218. // first do a quick spot check on the Vcb.
  219. //
  220. if ( Fcb->Vcb->VerifyThread != KeGetCurrentThread() ) {
  221. RxQuickVerifyVcb( RxContext, Fcb->Vcb );
  222. }
  223. //
  224. // Now based on the condition of the Fcb we'll either return
  225. // immediately to the caller, raise a condition, or do some work
  226. // to verify the Fcb.
  227. //
  228. switch (Fcb->FcbCondition) {
  229. case FcbGood:
  230. DebugTrace(0, Dbg, "The Fcb is good\n", 0);
  231. break;
  232. case FcbBad:
  233. RxRaiseStatus( RxContext, RxStatus(FILE_INVALID) );
  234. break;
  235. case FcbNeedsToBeVerified:
  236. //
  237. // We loop here checking our ancestors until we hit an Fcb which
  238. // is either good or bad.
  239. //
  240. CurrentFcb = Fcb;
  241. while (CurrentFcb->FcbCondition == FcbNeedsToBeVerified) {
  242. RxDetermineAndMarkFcbCondition(RxContext, CurrentFcb);
  243. //
  244. // If this Fcb didn't make it, or it was the Root Dcb, exit
  245. // the loop now, else continue with out parent.
  246. //
  247. if ( (CurrentFcb->FcbCondition != FcbGood) ||
  248. (NodeType(CurrentFcb) == RDBSS_NTC_ROOT_DCB) ) {
  249. break;
  250. }
  251. CurrentFcb = CurrentFcb->ParentDcb;
  252. }
  253. //
  254. // Now we can just look at ourselves to see how we did.
  255. //
  256. if (Fcb->FcbCondition != FcbGood) {
  257. RxRaiseStatus( RxContext, RxStatus(FILE_INVALID) );
  258. }
  259. break;
  260. default:
  261. DebugDump("Invalid FcbCondition\n", 0, Fcb);
  262. RxBugCheck( Fcb->FcbCondition, 0, 0 );
  263. }
  264. DebugTrace(-1, Dbg, "RxVerifyFcb -> VOID\n", 0);
  265. return;
  266. }
  267. VOID
  268. RxDeferredCleanVolume (
  269. PVOID Parameter
  270. )
  271. /*++
  272. Routine Description:
  273. This is the routine that performs the actual RxMarkVolumeClean call.
  274. It assures that the target volume still exists as there ia a race
  275. condition between queueing the ExWorker item and volumes going away.
  276. Arguments:
  277. Parameter - Points to a clean volume packet that was allocated from pool
  278. Return Value:
  279. None.
  280. --*/
  281. {
  282. PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
  283. PLIST_ENTRY Links;
  284. PVCB Vcb;
  285. RX_CONTEXT RxContext;
  286. BOOLEAN VcbExists = FALSE;
  287. DebugTrace(+1, Dbg, "RxDeferredCleanVolume\n", 0);
  288. Packet = (PCLEAN_AND_DIRTY_VOLUME_PACKET)Parameter;
  289. Vcb = Packet->Vcb;
  290. //
  291. // Make us appear as a top level FSP request so that we will
  292. // receive any errors from the operation.
  293. //
  294. IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP );
  295. //
  296. // Dummy up and Irp Context so we can call our worker routines
  297. //
  298. RtlZeroMemory( &RxContext, sizeof(RX_CONTEXT));
  299. SetFlag(RxContext.Flags, RX_CONTEXT_FLAG_WAIT);
  300. //
  301. // Acquire shared access to the global lock and make sure this volume
  302. // still exists.
  303. //
  304. RxAcquireSharedGlobal( &RxContext );
  305. for (Links = RxData.VcbQueue.Flink;
  306. Links != &RxData.VcbQueue;
  307. Links = Links->Flink) {
  308. PVCB ExistingVcb;
  309. ExistingVcb = CONTAINING_RECORD(Links, VCB, VcbLinks);
  310. if ( Vcb == ExistingVcb ) {
  311. VcbExists = TRUE;
  312. break;
  313. }
  314. }
  315. //
  316. // If the vcb is good then mark it clean. Ignore any problems.
  317. //
  318. if ( VcbExists &&
  319. (Vcb->VcbCondition == VcbGood) ) {
  320. try {
  321. if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
  322. RxMarkVolumeClean( &RxContext, Vcb );
  323. }
  324. //
  325. // Check for a pathelogical race condition, and fix it.
  326. //
  327. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) {
  328. RxMarkVolumeDirty( &RxContext, Vcb, FALSE );
  329. } else {
  330. //
  331. // Unlock the volume if it is removable.
  332. //
  333. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
  334. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
  335. RxToggleMediaEjectDisable( &RxContext, Vcb, FALSE );
  336. }
  337. }
  338. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  339. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  340. NOTHING;
  341. }
  342. }
  343. //
  344. // Release the global resource, unpin and repinned Bcbs and return.
  345. //
  346. RxReleaseGlobal( &RxContext );
  347. try {
  348. RxUnpinRepinnedBcbs( &RxContext );
  349. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  350. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  351. NOTHING;
  352. }
  353. IoSetTopLevelIrp( NULL );
  354. //
  355. // and finally free the packet.
  356. //
  357. ExFreePool( Packet );
  358. return;
  359. }
  360. VOID
  361. RxCleanVolumeDpc (
  362. IN PKDPC Dpc,
  363. IN PVOID DeferredContext,
  364. IN PVOID SystemArgument1,
  365. IN PVOID SystemArgument2
  366. )
  367. /*++
  368. Routine Description:
  369. This routine is dispatched 5 seconds after the last disk structure was
  370. modified in a specific volume, and exqueues an execuative worker thread
  371. to perform the actual task of marking the volume dirty.
  372. Arguments:
  373. DefferedContext - Contains the Vcb to process.
  374. Return Value:
  375. None.
  376. --*/
  377. {
  378. PVCB Vcb;
  379. PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
  380. Vcb = (PVCB)DeferredContext;
  381. //
  382. // If there is still dirty data (highly unlikely), set the timer for a
  383. // second in the future.
  384. //
  385. if (CcIsThereDirtyData(Vcb->Vpb)) {
  386. LARGE_INTEGER TwoSecondsFromNow;
  387. TwoSecondsFromNow.QuadPart = -2*1000*1000*10;
  388. KeSetTimer( &Vcb->CleanVolumeTimer,
  389. TwoSecondsFromNow,
  390. &Vcb->CleanVolumeDpc );
  391. return;
  392. }
  393. //
  394. // If we couldn't get pool, oh well....
  395. //
  396. Packet = ExAllocatePool(NonPagedPool, sizeof(CLEAN_AND_DIRTY_VOLUME_PACKET));
  397. if ( Packet ) {
  398. Packet->Vcb = Vcb;
  399. Packet->Irp = NULL;
  400. //
  401. // Clear the dirty flag now since we cannot synchronize after this point.
  402. //
  403. ClearFlag( Packet->Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
  404. ExInitializeWorkItem( &Packet->Item, &RxDeferredCleanVolume, Packet );
  405. ExQueueWorkItem( &Packet->Item, CriticalWorkQueue );
  406. }
  407. return;
  408. }
  409. VOID
  410. RxMarkVolumeClean (
  411. IN PRX_CONTEXT RxContext,
  412. IN PVCB Vcb
  413. )
  414. /*++
  415. Routine Description:
  416. This routine marks the indicated rx volume as clean, but only if it is
  417. a non-removable media. The volume is marked dirty by setting the first
  418. reserved byte of the first dirent in the root directory to 0.
  419. Arguments:
  420. Vcb - Supplies the Vcb being modified
  421. Return Value:
  422. None.
  423. --*/
  424. {
  425. PDIRENT Dirent;
  426. PBCB DirentBcb = NULL;
  427. RXSTATUS Status;
  428. DebugTrace(+1, Dbg, "RxMarkVolumeClean, Vcb = %08lx\n", Vcb);
  429. DebugTrace(0, Dbg, "Mark volume clean\n", 0);
  430. DirentBcb = NULL;
  431. //
  432. // Make Wait TRUE
  433. //
  434. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
  435. RxAcquireSharedFcb( RxContext, Vcb->RootDcb );
  436. try {
  437. //
  438. // Bail if we get an IO error.
  439. //
  440. try {
  441. RxReadDirectoryFile( RxContext,
  442. Vcb->RootDcb,
  443. 0,
  444. sizeof(DIRENT),
  445. TRUE,
  446. &DirentBcb,
  447. (PVOID *)&Dirent,
  448. &Status );
  449. //
  450. // Set the volume clean.
  451. //
  452. ClearFlag( Dirent->NtByte, RDBSS_DIRENT_NT_BYTE_DIRTY );
  453. //
  454. // Set the Bcb dirty and conditionally flush it.
  455. //
  456. CcSetDirtyPinnedData( DirentBcb, NULL );
  457. } except( RxExceptionFilter( RxContext, GetExceptionInformation() ) ) {
  458. NOTHING;
  459. }
  460. if (DirentBcb) {
  461. RxUnpinBcb( RxContext, DirentBcb );
  462. //
  463. // Always flush this so that the drive is not unlocked prematurely
  464. //
  465. CcFlushCache( &Vcb->RootDcb->NonPaged->SectionObjectPointers,
  466. &RxLargeZero,
  467. sizeof( DIRENT ),
  468. NULL );
  469. }
  470. } finally {
  471. RxReleaseFcb( RxContext, Vcb->RootDcb );
  472. }
  473. DebugTrace(-1, Dbg, "RxMarkVolumeClean -> VOID\n", 0);
  474. return;
  475. }
  476. VOID
  477. RxFspMarkVolumeDirtyWithRecover(
  478. PVOID Parameter
  479. )
  480. /*++
  481. Routine Description:
  482. This is the routine that performs the actual RxMarkVolumeDirty call
  483. on of paging file Io that encounters a media error. It is responsible
  484. for completing the PagingIo Irp as soon as this is done.
  485. Note: this routine (and thus RxMarkVolumeDirty() must be resident as
  486. the paging file might be damaged at this point.
  487. Arguments:
  488. Parameter - Points to a dirty volume packet that was allocated from pool
  489. Return Value:
  490. None.
  491. --*/
  492. {
  493. PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
  494. PVCB Vcb;
  495. RX_CONTEXT RxContext;
  496. PIRP Irp;
  497. BOOLEAN VcbExists = FALSE;
  498. DebugTrace(+1, Dbg, "RxDeferredCleanVolume\n", 0);
  499. Packet = (PCLEAN_AND_DIRTY_VOLUME_PACKET)Parameter;
  500. Vcb = Packet->Vcb;
  501. Irp = Packet->Irp;
  502. //
  503. // Dummy up the RxContext so we can call our worker routines
  504. //
  505. RtlZeroMemory( &RxContext, sizeof(RX_CONTEXT));
  506. SetFlag(RxContext.Flags, RX_CONTEXT_FLAG_WAIT);
  507. RxContext.CurrentIrp = Irp;
  508. //
  509. // Make us appear as a top level FSP request so that we will
  510. // receive any errors from the operation.
  511. //
  512. IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP );
  513. //
  514. // Try to write out the dirty bit. If something goes wrong, we
  515. // tried.
  516. //
  517. try {
  518. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );
  519. RxMarkVolumeDirty( &RxContext, Vcb, TRUE );
  520. } except(RxExceptionFilter( &RxContext, GetExceptionInformation() )) {
  521. NOTHING;
  522. }
  523. IoSetTopLevelIrp( NULL );
  524. //
  525. // Now complete the originating Irp
  526. //
  527. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  528. }
  529. VOID
  530. RxMarkVolumeDirty (
  531. IN PRX_CONTEXT RxContext,
  532. IN PVCB Vcb,
  533. IN BOOLEAN PerformSurfaceTest
  534. )
  535. /*++
  536. Routine Description:
  537. This routine marks the indicated rx volume as dirty, but only if it is
  538. a non-removable media. The volume is marked dirty by setting the first
  539. reserved byte of the first dirent in the root directory to 1.
  540. Arguments:
  541. Vcb - Supplies the Vcb being modified
  542. PerformSurfaceTest - Indicates to autochk that we think the media may be
  543. defective and that a surface test should be performed.
  544. Return Value:
  545. None.
  546. --*/
  547. {
  548. PDIRENT Dirent;
  549. PBCB DirentBcb;
  550. KEVENT Event;
  551. PIRP Irp;
  552. LARGE_INTEGER ByteOffset;
  553. RXSTATUS Status;
  554. BOOLEAN ReleaseFcb = FALSE;
  555. DebugTrace(+1, Dbg, "RxMarkVolumeDirty, Vcb = %08lx\n", Vcb);
  556. Irp = NULL;
  557. DirentBcb = NULL;
  558. //
  559. // Bail if we get an IO error.
  560. //
  561. try {
  562. //
  563. // Make Wait TRUE
  564. //
  565. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
  566. ReleaseFcb = RxAcquireSharedFcb( RxContext, Vcb->RootDcb );
  567. //
  568. // Call Cc directly here so that RxReadDirectoryFile doesn't
  569. // have to be resident.
  570. //
  571. CcPinRead( Vcb->RootDcb->Specific.Dcb.DirectoryFile,
  572. &RxLargeZero,
  573. sizeof(DIRENT),
  574. TRUE,
  575. &DirentBcb,
  576. (PVOID *)&Dirent );
  577. DbgDoit( RxContext->PinCount += 1 )
  578. //
  579. // Set the volume dirty.
  580. //
  581. SetFlag( Dirent->NtByte, RDBSS_DIRENT_NT_BYTE_DIRTY );
  582. //
  583. // In addition, if this request received an error that may indicate
  584. // media corruption, have autochk perform a surface test.
  585. //
  586. if ( PerformSurfaceTest ) {
  587. SetFlag( Dirent->NtByte, RDBSS_DIRENT_NT_BYTE_TEST_SURFACE );
  588. }
  589. //
  590. // Initialize the event we're going to use
  591. //
  592. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  593. //
  594. // Build the irp for the operation and also set the overrride flag.
  595. // Note that we may be at APC level, so do this asyncrhonously and
  596. // use an event for synchronization as normal request completion
  597. // cannot occur at APC level.
  598. //
  599. ByteOffset.QuadPart = Vcb->AllocationSupport.RootDirectoryLbo;
  600. Irp = IoBuildAsynchronousFsdRequest( IRP_MJ_WRITE,
  601. Vcb->TargetDeviceObject,
  602. (PVOID)Dirent,
  603. 1 << Vcb->AllocationSupport.LogOfBytesPerSector,
  604. &ByteOffset,
  605. NULL );
  606. if ( Irp == NULL ) {
  607. RxRaiseStatus( RxContext, RxStatus(INSUFFICIENT_RESOURCES) );
  608. }
  609. //
  610. // Set up the completion routine
  611. //
  612. IoSetCompletionRoutine( Irp,
  613. RxMarkDirtyCompletionRoutine,
  614. &Event,
  615. TRUE,
  616. TRUE,
  617. TRUE );
  618. //
  619. // Call the device to do the write and wait for it to finish.
  620. //
  621. (VOID)IoCallDriver( Vcb->TargetDeviceObject, Irp );
  622. (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
  623. //
  624. // Grab the Status.
  625. //
  626. Status = Irp->IoStatus.Status;
  627. //
  628. // Raise any error status
  629. //
  630. if (!NT_SUCCESS(Status)) {
  631. RxNormalizeAndRaiseStatus( RxContext, Status );
  632. }
  633. } finally {
  634. //
  635. // Clean up the Irp and Mdl
  636. //
  637. if (Irp) {
  638. //
  639. // If there is an MDL (or MDLs) associated with this I/O
  640. // request, Free it (them) here. This is accomplished by
  641. // walking the MDL list hanging off of the IRP and deallocating
  642. // each MDL encountered.
  643. //
  644. while (Irp->MdlAddress != NULL) {
  645. PMDL NextMdl;
  646. NextMdl = Irp->MdlAddress->Next;
  647. MmUnlockPages( Irp->MdlAddress );
  648. IoFreeMdl( Irp->MdlAddress );
  649. Irp->MdlAddress = NextMdl;
  650. }
  651. IoFreeIrp( Irp );
  652. }
  653. if (DirentBcb != NULL) {
  654. RxUnpinBcb( RxContext, DirentBcb );
  655. }
  656. if (ReleaseFcb) {
  657. RxReleaseFcb( RxContext, Vcb->RootDcb );
  658. }
  659. }
  660. DebugTrace(-1, Dbg, "RxMarkVolumeDirty -> VOID\n", 0);
  661. return;
  662. }
  663. VOID
  664. RxCheckDirtyBit (
  665. IN PRX_CONTEXT RxContext,
  666. IN PVCB Vcb
  667. )
  668. /*++
  669. Routine Description:
  670. This routine looks at the volume dirty bit, and depending on the state of
  671. VCB_STATE_FLAG_MOUNTED_DIRTY, the appropriate action is taken.
  672. Arguments:
  673. Vcb - Supplies the Vcb being queried.
  674. Return Value:
  675. None.
  676. --*/
  677. {
  678. BOOLEAN Dirty;
  679. PDIRENT Dirent;
  680. PBCB DirtyBitBcb;
  681. RXSTATUS Status;
  682. UNICODE_STRING VolumeLabel;
  683. //
  684. // Look in the first dirent
  685. //
  686. RxReadDirectoryFile( RxContext,
  687. Vcb->RootDcb,
  688. 0,
  689. sizeof(DIRENT),
  690. FALSE,
  691. &DirtyBitBcb,
  692. (PVOID *)&Dirent,
  693. &Status );
  694. ASSERT( NT_SUCCESS( Status ));
  695. //
  696. // Check if the magic bit is set
  697. //
  698. Dirty = BooleanFlagOn( Dirent->NtByte, RDBSS_DIRENT_NT_BYTE_DIRTY );
  699. //
  700. // Setup the VolumeLabel string
  701. //
  702. VolumeLabel.Length = Vcb->Vpb->VolumeLabelLength;
  703. VolumeLabel.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH;
  704. VolumeLabel.Buffer = &Vcb->Vpb->VolumeLabel[0];
  705. if ( Dirty ) {
  706. KdPrint(("FASTRDBSS: WARNING! Mounting Dirty Volume %wZ\n", &VolumeLabel));
  707. SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );
  708. } else {
  709. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
  710. KdPrint(("FASTRDBSS: Volume %wZ has been cleaned.\n", &VolumeLabel));
  711. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );
  712. } else {
  713. (VOID)FsRtlBalanceReads( Vcb->TargetDeviceObject );
  714. }
  715. }
  716. RxUnpinBcb( RxContext, DirtyBitBcb );
  717. }
  718. VOID
  719. RxVerifyOperationIsLegal ( RXCOMMON_SIGNATURE )
  720. /*++
  721. Routine Description:
  722. This routine determines is the requested operation should be allowed to
  723. continue. It either returns to the user if the request is Okay, or
  724. raises an appropriate status.
  725. Arguments:
  726. Irp - Supplies the Irp to check
  727. Return Value:
  728. None.
  729. --*/
  730. {
  731. RxCaptureRequestPacket;
  732. RxCaptureParamBlock; RxCaptureFileObject;
  733. //
  734. // If the Irp is not present, then we got here via close.
  735. //
  736. //
  737. if ( capReqPacket == NULL ) {
  738. return;
  739. }
  740. //
  741. // If there is not a file object, we cannot continue.
  742. //
  743. if ( capFileObject == NULL ) {
  744. return;
  745. }
  746. //
  747. // If we are trying to do any other operation than close on a file
  748. // object marked for delete, raise RxStatus(DELETE_PENDING).
  749. //
  750. if ( ( capFileObject->DeletePending == TRUE ) &&
  751. ( RxContext->MajorFunction != IRP_MJ_CLEANUP ) &&
  752. ( RxContext->MajorFunction != IRP_MJ_CLOSE ) ) {
  753. RxRaiseStatus( RxContext, RxStatus(DELETE_PENDING) );
  754. }
  755. //
  756. // If we are doing a create, and there is a related file objects, and
  757. // it it is marked for delete, raise RxStatus(DELETE_PENDING).
  758. //
  759. if ( RxContext->MajorFunction == IRP_MJ_CREATE ) {
  760. PFILE_OBJECT RelatedFileObject;
  761. RelatedFileObject = capFileObject->RelatedFileObject;
  762. if ( (RelatedFileObject != NULL) &&
  763. FlagOn(((PFCB)RelatedFileObject->FsContext)->FcbState,
  764. FCB_STATE_DELETE_ON_CLOSE) ) {
  765. RxRaiseStatus( RxContext, RxStatus(DELETE_PENDING) );
  766. }
  767. }
  768. //
  769. // If the file object has already been cleaned up, and
  770. //
  771. // A) This request is a paging io read or write, or
  772. // B) This request is a close operation, or
  773. // C) This request is a set or query info call (for Lou)
  774. // D) This is an MDL complete
  775. //
  776. // let it pass, otherwise return RxStatus(FILE_CLOSED).
  777. //
  778. if ( FlagOn(capFileObject->Flags, FO_CLEANUP_COMPLETE) ) {
  779. if ( (FlagOn(capReqPacket->Flags, IRP_PAGING_IO)) ||
  780. (capPARAMS->MajorFunction == IRP_MJ_CLOSE ) ||
  781. (capPARAMS->MajorFunction == IRP_MJ_SET_INFORMATION) ||
  782. (capPARAMS->MajorFunction == IRP_MJ_QUERY_INFORMATION) ||
  783. ( ( (capPARAMS->MajorFunction == IRP_MJ_READ) ||
  784. (capPARAMS->MajorFunction == IRP_MJ_WRITE) ) &&
  785. FlagOn(capPARAMS->MinorFunction, IRP_MN_COMPLETE) ) ) {
  786. NOTHING;
  787. } else {
  788. RxRaiseStatus( RxContext, RxStatus(FILE_CLOSED) );
  789. }
  790. }
  791. return;
  792. }
  793. //
  794. // Internal support routine
  795. //
  796. VOID
  797. RxResetFcb (
  798. IN PRX_CONTEXT RxContext,
  799. IN PFCB Fcb
  800. )
  801. /*++
  802. Routine Description:
  803. This routine is called when an Fcb has been marked as needs to be verified.
  804. It does the following tasks:
  805. - Reset Mcb mapping information
  806. - For directories, reset dirent hints
  807. - Set allocation size to unknown
  808. Arguments:
  809. Fcb - Supplies the Fcb to reset
  810. Return Value:
  811. None.
  812. --*/
  813. {
  814. //
  815. // Don't do the two following operations for the Root Dcb.
  816. //
  817. if ( NodeType(Fcb) != RDBSS_NTC_ROOT_DCB ) {
  818. POOL_TYPE PoolType;
  819. //
  820. // If this happens to be a paging file, use non-paged pool for the FCB
  821. //
  822. if ( FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE ) ) {
  823. PoolType = NonPagedPool;
  824. } else {
  825. PoolType = PagedPool;
  826. }
  827. //
  828. // Reset the mcb mapping.
  829. //
  830. FsRtlRemoveMcbEntry( &Fcb->Mcb, 0, 0xFFFFFFFF );
  831. //
  832. // Reset the allocation size to 0 or unknown
  833. //
  834. if ( Fcb->FirstClusterOfFile == 0 ) {
  835. Fcb->Header.AllocationSize = RxLargeZero;
  836. } else {
  837. Fcb->Header.AllocationSize.QuadPart = -1;
  838. }
  839. }
  840. //
  841. // If this is a directory, reset the hints.
  842. //
  843. if ( (NodeType(Fcb) == RDBSS_NTC_DCB) ||
  844. (NodeType(Fcb) == RDBSS_NTC_ROOT_DCB) ) {
  845. //
  846. // Force a rescan of the directory
  847. //
  848. Fcb->Specific.Dcb.UnusedDirentVbo = 0xffffffff;
  849. Fcb->Specific.Dcb.DeletedDirentHint = 0xffffffff;
  850. }
  851. }
  852. //
  853. // Internal support routine
  854. //
  855. VOID
  856. RxDetermineAndMarkFcbCondition (
  857. IN PRX_CONTEXT RxContext,
  858. IN PFCB Fcb
  859. )
  860. /*++
  861. Routine Description:
  862. This routine checks a specific Fcb to see if it is different from what's
  863. on the disk. The following things are checked:
  864. - File Name
  865. - File Size (if not directory)
  866. - First Cluster Of File
  867. - Dirent Attributes
  868. Arguments:
  869. Fcb - Supplies the Fcb to examine
  870. Return Value:
  871. None.
  872. --*/
  873. {
  874. PDIRENT Dirent;
  875. PBCB DirentBcb;
  876. OEM_STRING Name;
  877. CHAR Buffer[16];
  878. //
  879. // If this is the Root Dcb, special case it. That is, we know
  880. // by definition that it is good since it is fixed in the volume
  881. // structure.
  882. //
  883. if ( NodeType(Fcb) == RDBSS_NTC_ROOT_DCB ) {
  884. RxResetFcb( RxContext, Fcb );
  885. RxMarkFcbCondition( RxContext, Fcb, FcbGood );
  886. return;
  887. }
  888. // The first thing we need to do to verify ourselves is
  889. // locate the dirent on the disk.
  890. //
  891. RxGetDirentFromFcbOrDcb( RxContext,
  892. Fcb,
  893. &Dirent,
  894. &DirentBcb );
  895. //
  896. // We located the dirent for ourselves now make sure it
  897. // is really ours by comparing the Name and RxFlags.
  898. // Then for a file we also check the file size.
  899. //
  900. // Note that we have to unpin the Bcb before calling RxResetFcb
  901. // in order to avoid a deadlock in CcUninitializeCacheMap.
  902. //
  903. Name.MaximumLength = 16;
  904. Name.Buffer = &Buffer[0];
  905. Rx8dot3ToString( RxContext, Dirent, FALSE, &Name );
  906. if (!RtlEqualString( &Name, &Fcb->ShortName.Name.Oem, TRUE )
  907. ||
  908. ( (NodeType(Fcb) == RDBSS_NTC_FCB) &&
  909. (Fcb->Header.FileSize.LowPart != Dirent->FileSize) )
  910. ||
  911. ((ULONG)Dirent->FirstClusterOfFile != Fcb->FirstClusterOfFile)
  912. ||
  913. (Dirent->Attributes != Fcb->DirentRxFlags) ) {
  914. RxMarkFcbCondition( RxContext, Fcb, FcbBad );
  915. RxUnpinBcb( RxContext, DirentBcb );
  916. } else {
  917. //
  918. // We passed. Get the Fcb ready to use again.
  919. //
  920. RxUnpinBcb( RxContext, DirentBcb );
  921. RxResetFcb( RxContext, Fcb );
  922. RxMarkFcbCondition( RxContext, Fcb, FcbGood );
  923. }
  924. return;
  925. }
  926. //
  927. // Internal support routine
  928. //
  929. VOID
  930. RxQuickVerifyVcb (
  931. IN PRX_CONTEXT RxContext,
  932. IN PVCB Vcb
  933. )
  934. /*++
  935. Routine Description:
  936. This routines just checks the verify bit in the real device and the
  937. Vcb condition and raises an appropriate exception if so warented.
  938. It is called when verifying both Fcbs and Vcbs.
  939. Arguments:
  940. Vcb - Supplies the Vcb to check the condition of.
  941. Return Value:
  942. None.
  943. --*/
  944. {
  945. RxCaptureRequestPacket;
  946. //
  947. // If the real device needs to be verified we'll set the
  948. // DeviceToVerify to be our real device and raise VerifyRequired.
  949. //
  950. if (FlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
  951. DebugTrace(0, Dbg, "The Vcb needs to be verified\n", 0);
  952. IoSetHardErrorOrVerifyDevice( capReqPacket,
  953. Vcb->Vpb->RealDevice );
  954. RxRaiseStatus( RxContext, RxStatus(VERIFY_REQUIRED) );
  955. }
  956. //
  957. // Based on the condition of the Vcb we'll either return to our
  958. // caller or raise an error condition
  959. //
  960. switch (Vcb->VcbCondition) {
  961. case VcbGood:
  962. DebugTrace(0, Dbg, "The Vcb is good\n", 0);
  963. //
  964. // Do a check here of an operation that would try to modify a
  965. // write protected media.
  966. //
  967. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED) &&
  968. ((RxContext->MajorFunction == IRP_MJ_WRITE) ||
  969. (RxContext->MajorFunction == IRP_MJ_SET_INFORMATION) ||
  970. (RxContext->MajorFunction == IRP_MJ_SET_EA) ||
  971. (RxContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) ||
  972. (RxContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION))) {
  973. //
  974. // Set the real device for the pop-up info, and set the verify
  975. // bit in the device object, so that we will force a verify
  976. // in case the user put the correct media back in.
  977. //
  978. IoSetHardErrorOrVerifyDevice( capReqPacket,
  979. Vcb->Vpb->RealDevice );
  980. SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
  981. RxRaiseStatus( RxContext, RxStatus(MEDIA_WRITE_PROTECTED) );
  982. }
  983. break;
  984. case VcbNotMounted:
  985. DebugTrace(0, Dbg, "The Vcb is not mounted\n", 0);
  986. //
  987. // Set the real device for the pop-up info, and set the verify
  988. // bit in the device object, so that we will force a verify
  989. // in case the user put the correct media back in.
  990. //
  991. IoSetHardErrorOrVerifyDevice( capReqPacket,
  992. Vcb->Vpb->RealDevice );
  993. SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
  994. RxRaiseStatus( RxContext, RxStatus(WRONG_VOLUME) );
  995. break;
  996. default:
  997. DebugDump("Invalid VcbCondition\n", 0, Vcb);
  998. RxBugCheck( Vcb->VcbCondition, 0, 0 );
  999. }
  1000. }
  1001. RXSTATUS
  1002. RxPerformVerify (
  1003. IN PRX_CONTEXT RxContext,
  1004. IN PIRP Irp,
  1005. IN PDEVICE_OBJECT Device
  1006. )
  1007. /*++
  1008. Routine Description:
  1009. This routines performs an IoVerifyVolume operation and takes the
  1010. appropriate action. After the Verify is complete the originating
  1011. Irp is sent off to an Ex Worker Thread. This routine is called
  1012. from the exception handler.
  1013. Arguments:
  1014. Irp - The irp to send off after all is well and done.
  1015. Device - The real device needing verification.
  1016. Return Value:
  1017. None.
  1018. --*/
  1019. {
  1020. PVCB Vcb;
  1021. RXSTATUS Status = RxStatus(SUCCESS);
  1022. RxCaptureParamBlock; RxCaptureFileObject;
  1023. //
  1024. // Check if this Irp has a status of Verify required and if it does
  1025. // then call the I/O system to do a verify.
  1026. //
  1027. // Skip the IoVerifyVolume if this is a mount or verify request
  1028. // itself. Trying a recursive mount will cause a deadlock with
  1029. // the DeviceObject->DeviceLock.
  1030. //
  1031. if ( (RxContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL)
  1032. &&
  1033. ((RxContext->MinorFunction == IRP_MN_MOUNT_VOLUME) ||
  1034. (RxContext->MinorFunction == IRP_MN_VERIFY_VOLUME)) ) {
  1035. return RxFsdPostRequest( RxContext );
  1036. }
  1037. DebugTrace(0, Dbg, "Verify Required, DeviceObject = %08lx\n", Device);
  1038. //
  1039. // Extract a pointer to the Vcb from the RxDeviceObject.
  1040. // Note that since we have specifically excluded mount,
  1041. // requests, we know that IrpSp->DeviceObject is indeed a
  1042. // volume device object.
  1043. //
  1044. Vcb = &CONTAINING_RECORD( capPARAMS->DeviceObject,
  1045. RDBSS_DEVICE_OBJECT,
  1046. DeviceObject )->Vcb;
  1047. //
  1048. // Check if the volume still thinks it needs to be verified,
  1049. // if it doesn't then we can skip doing a verify because someone
  1050. // else beat us to it.
  1051. //
  1052. try {
  1053. if (FlagOn(Device->Flags, DO_VERIFY_VOLUME)) {
  1054. BOOLEAN AllowRawMount;
  1055. #ifdef WE_WON_ON_APPEAL
  1056. PLIST_ENTRY Links;
  1057. #endif // WE_WON_ON_APPEAL
  1058. //
  1059. // We will allow Raw to mount this volume if we were doing a
  1060. // a DASD open.
  1061. //
  1062. if ( (RxContext->MajorFunction == IRP_MJ_CREATE) &&
  1063. (capFileObject->FileName.Length == 0) &&
  1064. (capFileObject->RelatedFileObject == NULL) ) {
  1065. AllowRawMount = TRUE;
  1066. } else {
  1067. AllowRawMount = FALSE;
  1068. }
  1069. //
  1070. // If the IopMount in IoVerifyVolume did something, and
  1071. // this is an absolute open, force a reparse.
  1072. //
  1073. Status = IoVerifyVolume( Device, AllowRawMount );
  1074. //
  1075. // If the verify operation completed it will return
  1076. // either RxStatus(SUCCESS) or STATUS_WRONG_VOLUME, exactly.
  1077. //
  1078. // If RxVerifyVolume encountered an error during
  1079. // processing, it will return that error. If we got
  1080. // RxStatus(WRONG_VOLUME) from the verfy, and our volume
  1081. // is now mounted, commute the status to RxStatus(SUCCESS).
  1082. //
  1083. if ( (Status == RxStatus(WRONG_VOLUME)) &&
  1084. (Vcb->VcbCondition == VcbGood) ) {
  1085. Status = RxStatus(SUCCESS);
  1086. }
  1087. //
  1088. // Do a quick unprotected check here. The routine will do
  1089. // a safe check. After here we can release the resource.
  1090. // Note that if the volume really went away, we will be taking
  1091. // the Reparse path.
  1092. //
  1093. (VOID)RxAcquireExclusiveGlobal( RxContext );
  1094. #ifdef WE_WON_ON_APPEAL
  1095. //
  1096. // It is possible we were called with a double space Vcb.
  1097. // We need to start with the Parent Vcb at this point.
  1098. //
  1099. if (Vcb->Dscb) {
  1100. Vcb = Vcb->Dscb->ParentVcb;
  1101. }
  1102. //
  1103. // First run through any mounted DBLS volumes. Note that we
  1104. // have to get the next Flink before calling RxCheckForDismount
  1105. // incase the Vcb goes away.
  1106. //
  1107. (VOID)RxAcquireExclusiveVcb( RxContext, Vcb );
  1108. for (Links = Vcb->ParentDscbLinks.Flink;
  1109. Links != &Vcb->ParentDscbLinks; ) {
  1110. PVCB ChildVcb;
  1111. ChildVcb = CONTAINING_RECORD( Links, DSCB, ChildDscbLinks )->Vcb;
  1112. Links = Links->Flink;
  1113. ASSERT( ChildVcb->Vpb->RealDevice == Vcb->Vpb->RealDevice );
  1114. if ( (ChildVcb->VcbCondition == VcbNotMounted) &&
  1115. (ChildVcb->OpenFileCount == 0) ) {
  1116. (VOID)RxCheckForDismount( RxContext, ChildVcb );
  1117. }
  1118. }
  1119. RxReleaseVcb( RxContext, Vcb );
  1120. #endif // WE_WON_ON_APPEAL
  1121. if ( (Vcb->VcbCondition == VcbNotMounted) &&
  1122. (Vcb->OpenFileCount == 0) ) {
  1123. (VOID)RxCheckForDismount( RxContext, Vcb );
  1124. }
  1125. RxReleaseGlobal( RxContext );
  1126. if ((RxContext->MajorFunction == IRP_MJ_CREATE) &&
  1127. (capFileObject->RelatedFileObject == NULL) &&
  1128. ((Status == RxStatus(SUCCESS)) || (Status == STATUS_WRONG_VOLUME))) {
  1129. Irp->IoStatus.Information = IO_REMOUNT;
  1130. RxCompleteRequest( RxContext, RxStatus(REPARSE) );
  1131. Status = RxStatus(REPARSE);
  1132. Irp = NULL;
  1133. }
  1134. if ( (Irp != NULL) && !NT_SUCCESS(Status) ) {
  1135. //
  1136. // Fill in the device object if required.
  1137. //
  1138. if ( IoIsErrorUserInduced( Status ) ) {
  1139. IoSetHardErrorOrVerifyDevice( Irp, Device );
  1140. }
  1141. RxNormalizeAndRaiseStatus( RxContext, Status );
  1142. }
  1143. } else {
  1144. DebugTrace(0, Dbg, "Volume no longer needs verification\n", 0);
  1145. }
  1146. //
  1147. // If there is still an Irp, send it off to an Ex Worker thread.
  1148. //
  1149. if ( Irp != NULL ) {
  1150. Status = RxFsdPostRequest( RxContext );
  1151. }
  1152. } except(RxExceptionFilter( RxContext, GetExceptionInformation() )) {
  1153. //
  1154. // We had some trouble trying to perform the verify or raised
  1155. // an error ourselves. So we'll abort the I/O request with
  1156. // the error status that we get back from the execption code.
  1157. //
  1158. Status = RxProcessException( RxContext, GetExceptionCode() );
  1159. }
  1160. return Status;
  1161. }
  1162. //
  1163. // Local support routine
  1164. //
  1165. RXSTATUS
  1166. RxMarkDirtyCompletionRoutine(
  1167. IN PDEVICE_OBJECT DeviceObject,
  1168. IN PIRP Irp,
  1169. IN PVOID Contxt
  1170. )
  1171. {
  1172. //
  1173. // Set the event so that our call will wake up.
  1174. //
  1175. KeSetEvent( (PKEVENT)Contxt, 0, FALSE );
  1176. UNREFERENCED_PARAMETER( DeviceObject );
  1177. UNREFERENCED_PARAMETER( Irp );
  1178. return RxStatus(MORE_PROCESSING_REQUIRED);
  1179. }
  1180.