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.

3027 lines
87 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. VerfySup.c
  5. Abstract:
  6. This module implements the Ntfs Verify volume and fcb support
  7. routines
  8. Author:
  9. Gary Kimura [GaryKi] 30-Jan-1992
  10. Revision History:
  11. --*/
  12. #include "NtfsProc.h"
  13. //
  14. // The Debug trace level for this module
  15. //
  16. #define Dbg (DEBUG_TRACE_VERFYSUP)
  17. //
  18. // Define a tag for general pool allocations from this module
  19. //
  20. #undef MODULE_POOL_TAG
  21. #define MODULE_POOL_TAG ('VFtN')
  22. #if DBG
  23. extern BOOLEAN NtfsCheckQuota;
  24. #endif
  25. BOOLEAN NtfsSuppressPopup = FALSE;
  26. //
  27. // Local procedure prototypes
  28. //
  29. VOID
  30. NtfsPerformVerifyDiskRead (
  31. IN PIRP_CONTEXT IrpContext,
  32. IN PVCB Vcb,
  33. IN PVOID Buffer,
  34. IN LONGLONG Offset,
  35. IN ULONG NumberOfBytesToRead
  36. );
  37. NTSTATUS
  38. NtfsVerifyReadCompletionRoutine(
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN PIRP Irp,
  41. IN PVOID Contxt
  42. );
  43. VOID
  44. NtOfsCloseIndexSafe (
  45. IN PIRP_CONTEXT IrpContext,
  46. IN PSCB *Scb
  47. );
  48. typedef struct _EVENTLOG_ERROR_PACKET {
  49. PVCB Vcb;
  50. UCHAR MajorFunction;
  51. ULONG TransactionId;
  52. PQUOTA_USER_DATA UserData;
  53. ULONG LogCode;
  54. NTSTATUS FinalStatus;
  55. } EVENTLOG_ERROR_PACKET, *PEVENTLOG_ERROR_PACKET;
  56. VOID
  57. NtfsResolveVolumeAndLogEventSpecial (
  58. IN PIRP_CONTEXT IrpContext,
  59. IN OUT PVOID Context
  60. );
  61. BOOLEAN
  62. NtfsLogEventInternal (
  63. IN PVCB Vcb,
  64. IN UCHAR MajorFunction,
  65. IN ULONG TransactionId,
  66. IN PUNICODE_STRING String OPTIONAL,
  67. IN PQUOTA_USER_DATA UserData OPTIONAL,
  68. IN NTSTATUS LogCode,
  69. IN NTSTATUS FinalStatus
  70. );
  71. #ifdef ALLOC_PRAGMA
  72. #pragma alloc_text(PAGE, NtfsCheckpointAllVolumes)
  73. #pragma alloc_text(PAGE, NtfsCheckUsnTimeOut)
  74. #pragma alloc_text(PAGE, NtfsMarkVolumeDirty)
  75. #pragma alloc_text(PAGE, NtfsPerformVerifyOperation)
  76. #pragma alloc_text(PAGE, NtfsPingVolume)
  77. #pragma alloc_text(PAGE, NtfsUpdateVolumeInfo)
  78. #pragma alloc_text(PAGE, NtOfsCloseAttributeSafe)
  79. #pragma alloc_text(PAGE, NtOfsCloseIndexSafe)
  80. #pragma alloc_text(PAGE, NtfsResolveVolumeAndLogEventSpecial)
  81. #pragma alloc_text(PAGE, NtfsLogEventInternal)
  82. #endif
  83. BOOLEAN
  84. NtfsPerformVerifyOperation (
  85. IN PIRP_CONTEXT IrpContext,
  86. IN PVCB Vcb
  87. )
  88. /*++
  89. Routine Description:
  90. This routine is used to force a verification of the volume. It assumes
  91. that everything might be resource/mutex locked so it cannot take out
  92. any resources. It will read in the boot sector and the dasd file record
  93. and from those determine if the volume is okay. This routine is called
  94. whenever the real device has started rejecting I/O requests with
  95. VERIFY_REQUIRED.
  96. If the volume verifies okay then we will return TRUE otherwise we will
  97. return FALSE.
  98. It does not alter the Vcb state.
  99. Arguments:
  100. Vcb - Supplies the Vcb being queried.
  101. Return Value:
  102. BOOLEAN - TRUE if the volume verified okay, and FALSE otherwise.
  103. --*/
  104. {
  105. BOOLEAN Results = FALSE;
  106. PPACKED_BOOT_SECTOR BootSector;
  107. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  108. VCN LogFileVcn;
  109. LCN LogFileLcn;
  110. LONGLONG ClusterCount;
  111. ULONG RemainingLogBytes;
  112. LONGLONG CurrentLogBytes;
  113. PVOID CurrentLogBuffer;
  114. PVOID LogFileHeader = NULL;
  115. LONGLONG Offset;
  116. PSTANDARD_INFORMATION StandardInformation;
  117. ASSERT_IRP_CONTEXT( IrpContext );
  118. ASSERT_VCB( Vcb );
  119. PAGED_CODE();
  120. DebugTrace( +1, Dbg, ("NtfsPerformVerifyOperation, Vcb = %08lx\n", Vcb) );
  121. BootSector = NULL;
  122. FileRecord = NULL;
  123. try {
  124. //
  125. // Forget this volume if we have already failed the remount once.
  126. //
  127. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  128. leave;
  129. }
  130. //
  131. // Allocate a buffer for the boot sector, read it in, and then check if
  132. // it some of the fields still match. The starting lcn is zero and the
  133. // size is the size of a disk sector.
  134. //
  135. BootSector = NtfsAllocatePool( NonPagedPool,
  136. (ULONG) ROUND_TO_PAGES( Vcb->BytesPerSector ));
  137. NtfsPerformVerifyDiskRead( IrpContext, Vcb, BootSector, (LONGLONG)0, Vcb->BytesPerSector );
  138. //
  139. // For now we will only check that the serial numbers, mft lcn's and
  140. // number of sectors match up with what they use to be.
  141. //
  142. if ((BootSector->SerialNumber != Vcb->VolumeSerialNumber) ||
  143. (BootSector->MftStartLcn != Vcb->MftStartLcn) ||
  144. (BootSector->Mft2StartLcn != Vcb->Mft2StartLcn) ||
  145. (BootSector->NumberSectors != Vcb->NumberSectors)) {
  146. leave;
  147. }
  148. //
  149. // Allocate a buffer for the dasd file record, read it in, and then check
  150. // if some of the fields still match. The size of the record is the number
  151. // of bytes in a file record segment, and because the dasd file record is
  152. // known to be contiguous with the start of the mft we can compute the starting
  153. // lcn as the base of the mft plus the dasd number mulitplied by the clusters
  154. // per file record segment.
  155. //
  156. FileRecord = NtfsAllocatePool( NonPagedPoolCacheAligned,
  157. (ULONG) ROUND_TO_PAGES( Vcb->BytesPerFileRecordSegment ));
  158. Offset = LlBytesFromClusters(Vcb, Vcb->MftStartLcn) +
  159. (VOLUME_DASD_NUMBER * Vcb->BytesPerFileRecordSegment);
  160. NtfsPerformVerifyDiskRead( IrpContext, Vcb, FileRecord, Offset, Vcb->BytesPerFileRecordSegment );
  161. //
  162. // Given a pointer to a file record we want the value of the first attribute which
  163. // will be the standard information attribute. Then we will check the
  164. // times stored in the standard information attribute against the times we
  165. // have saved in the vcb. Note that last access time will be modified if
  166. // the disk was moved and mounted on a different system without doing a dismount
  167. // on this system.
  168. //
  169. StandardInformation = NtfsGetValue(((PATTRIBUTE_RECORD_HEADER)Add2Ptr( FileRecord,
  170. FileRecord->FirstAttributeOffset )));
  171. if ((StandardInformation->CreationTime != Vcb->VolumeCreationTime) ||
  172. (StandardInformation->LastModificationTime != Vcb->VolumeLastModificationTime) ||
  173. (StandardInformation->LastChangeTime != Vcb->VolumeLastChangeTime) ||
  174. (StandardInformation->LastAccessTime != Vcb->VolumeLastAccessTime)) {
  175. leave;
  176. }
  177. //
  178. // If the device is not writable we won't remount it.
  179. //
  180. if (NtfsDeviceIoControlAsync( IrpContext,
  181. Vcb->TargetDeviceObject,
  182. IOCTL_DISK_IS_WRITABLE,
  183. NULL,
  184. 0 ) == STATUS_MEDIA_WRITE_PROTECTED) {
  185. leave;
  186. }
  187. //
  188. // We need to read the start of the log file for Lfs to verify the log file.
  189. //
  190. LogFileHeader = NtfsAllocatePool( NonPagedPoolCacheAligned, PAGE_SIZE * 2 );
  191. //
  192. // Now read in the first two pages. We may have to perform multiple reads to
  193. // get the whole thing.
  194. //
  195. RemainingLogBytes = PAGE_SIZE * 2;
  196. CurrentLogBuffer = LogFileHeader;
  197. LogFileVcn = 0;
  198. do {
  199. //
  200. // Find the location of the log file start.
  201. //
  202. NtfsLookupAllocation( IrpContext,
  203. Vcb->LogFileScb,
  204. LogFileVcn,
  205. &LogFileLcn,
  206. &ClusterCount,
  207. NULL,
  208. NULL );
  209. CurrentLogBytes = LlBytesFromClusters( Vcb, ClusterCount );
  210. if (CurrentLogBytes > RemainingLogBytes) {
  211. CurrentLogBytes = RemainingLogBytes;
  212. }
  213. NtfsPerformVerifyDiskRead( IrpContext,
  214. Vcb,
  215. CurrentLogBuffer,
  216. LlBytesFromClusters( Vcb, LogFileLcn ),
  217. (ULONG) CurrentLogBytes );
  218. //
  219. // Move through the log file.
  220. //
  221. RemainingLogBytes -= (ULONG) CurrentLogBytes;
  222. CurrentLogBuffer = Add2Ptr( CurrentLogBuffer, (ULONG) CurrentLogBytes );
  223. LogFileVcn += ClusterCount;
  224. } while (RemainingLogBytes);
  225. //
  226. // We need to perform the revert operation on this buffer.
  227. //
  228. if (NtfsVerifyAndRevertUsaBlock( IrpContext,
  229. Vcb->LogFileScb,
  230. LogFileHeader,
  231. PAGE_SIZE * 2,
  232. 0 )) {
  233. //
  234. // Now call Lfs to verify the header.
  235. //
  236. Results = LfsVerifyLogFile( Vcb->LogHandle, LogFileHeader, PAGE_SIZE * 2 );
  237. }
  238. } finally {
  239. if (BootSector != NULL) { NtfsFreePool( BootSector ); }
  240. if (FileRecord != NULL) { NtfsFreePool( FileRecord ); }
  241. if (LogFileHeader != NULL) { NtfsFreePool( LogFileHeader ); }
  242. }
  243. DebugTrace( -1, Dbg, ("NtfsPerformVerifyOperation -> %08lx\n", Results) );
  244. return Results;
  245. }
  246. VOID
  247. NtOfsCloseIndexSafe (
  248. IN PIRP_CONTEXT IrpContext,
  249. IN PSCB *Scb
  250. )
  251. /*++
  252. Routine Description:
  253. This routine checks whether the given Scb is NULL, and if not,
  254. calls NtOfsCloseIndex to close the index.
  255. Arguments:
  256. Scb - Supplies the Scb of the index to close safely.
  257. Return Value:
  258. None.
  259. --*/
  260. {
  261. if (*Scb != NULL) {
  262. //
  263. // Notice that we don't release the Scbs, since
  264. // NtOfsCloseIndex might tear the Scbs down and make
  265. // trying to release them unsafe. When this request is
  266. // completed, the Scbs will be released anyway.
  267. //
  268. NtfsAcquireExclusiveScb( IrpContext, *Scb );
  269. NtOfsCloseIndex( IrpContext, *Scb );
  270. *Scb = NULL;
  271. }
  272. }
  273. VOID
  274. NtOfsCloseAttributeSafe (
  275. IN PIRP_CONTEXT IrpContext,
  276. IN PSCB Scb
  277. )
  278. /*++
  279. Routine Description:
  280. This routine checks whether the given Scb is NULL, and if not,
  281. calls NtOfsCloseAttribute to close the attribute.
  282. Arguments:
  283. Scb - Supplies the Scb of the attribute to close safely.
  284. Return Value:
  285. None.
  286. --*/
  287. {
  288. if (Scb != NULL) {
  289. NtOfsCloseAttribute( IrpContext, Scb );
  290. }
  291. }
  292. VOID
  293. NtfsPerformDismountOnVcb (
  294. IN PIRP_CONTEXT IrpContext,
  295. IN PVCB Vcb,
  296. IN BOOLEAN DoCompleteDismount,
  297. OUT PVPB *NewVpbReturn OPTIONAL
  298. )
  299. /*++
  300. Routine Description:
  301. This routine is called to start the dismount process on a vcb.
  302. It marks the Vcb as not mounted and dereferences all opened stream
  303. file objects, and gets the Vcb out of the Vpb's mounted volume
  304. structures.
  305. Arguments:
  306. Vcb - Supplies the Vcb being dismounted
  307. DoCompleteDismount - Indicates if we are to actually mark the volume
  308. as dismounted or if we are simply to stop the logfile and close
  309. the internal attribute streams.
  310. NewVpbReturn - If supplied, provides a way to return to the caller
  311. the new Vpb created in here. If we do not need to
  312. create a new Vpb in this function, we store NULL in
  313. NewVpbReturn.
  314. Return Value:
  315. None.
  316. --*/
  317. {
  318. PFCB Fcb;
  319. PFCB NextFcb = NULL;
  320. PSCB Scb;
  321. PVOID RestartKey;
  322. PLIST_ENTRY Links;
  323. PIRP UsnNotifyIrp;
  324. BOOLEAN CheckSystemScb;
  325. PVPB NewVpb;
  326. DebugTrace( +1, Dbg, ("NtfsPerformDismountOnVcb, Vcb = %08lx\n", Vcb) );
  327. #ifdef DISMOUNT_DBG
  328. NtfsData.DismountCount += 1;
  329. #endif
  330. //
  331. // We should always be syncrhonized with checkpoints when dismounting initially
  332. //
  333. ASSERT( !FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) ||
  334. (Vcb->CheckpointOwnerThread == PsGetCurrentThread()) ||
  335. ((IrpContext->TopLevelIrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
  336. (IrpContext->TopLevelIrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME)) );
  337. //
  338. // Blow away our delayed close file object.
  339. //
  340. if (!IsListEmpty( &NtfsData.AsyncCloseList ) ||
  341. !IsListEmpty( &NtfsData.DelayedCloseList )) {
  342. NtfsFspClose( Vcb );
  343. }
  344. //
  345. // Commit any current transaction before we start tearing down the volume.
  346. //
  347. NtfsCommitCurrentTransaction( IrpContext );
  348. //
  349. // Add one more checkpoint at the front of the logfile if we haven't hit any errors yet
  350. //
  351. if ((IrpContext->ExceptionStatus == STATUS_SUCCESS) &&
  352. FlagOn( Vcb->VcbState, VCB_STATE_VALID_LOG_HANDLE ) &&
  353. FlagOn( Vcb->VcbState, VCB_STATE_MOUNT_COMPLETED )) {
  354. try {
  355. NtfsCheckpointVolume( IrpContext, Vcb, TRUE, TRUE, FALSE, LFS_WRITE_FLAG_WRITE_AT_FRONT, Li0 );
  356. } except( EXCEPTION_EXECUTE_HANDLER ) {
  357. //
  358. // Swallow any errors while checkpointing
  359. //
  360. #ifdef BENL_DBG
  361. KdPrint(( "NTFS: exception in dismount checkpoint 0x%x\n", GetExceptionCode() ));
  362. #endif
  363. NtfsMinimumExceptionProcessing( IrpContext );
  364. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  365. }
  366. }
  367. //
  368. // Use a try-finally to facilitate cleanup.
  369. //
  370. try {
  371. //
  372. // Get rid of all the Ofs indices for Security, Quota, and Object Ids, etc.
  373. //
  374. NtOfsCloseIndexSafe( IrpContext, &Vcb->QuotaTableScb );
  375. NtOfsCloseIndexSafe( IrpContext, &Vcb->ReparsePointTableScb );
  376. NtOfsCloseIndexSafe( IrpContext, &Vcb->OwnerIdTableScb );
  377. NtOfsCloseIndexSafe( IrpContext, &Vcb->ObjectIdTableScb );
  378. NtOfsCloseIndexSafe( IrpContext, &Vcb->SecurityIdIndex );
  379. NtOfsCloseIndexSafe( IrpContext, &Vcb->SecurityDescriptorHashIndex );
  380. NtOfsCloseAttributeSafe( IrpContext, Vcb->SecurityDescriptorStream );
  381. //
  382. // Walk through and complete any Irps in the ReadUsn queue.
  383. //
  384. if (Vcb->UsnJournal != NULL) {
  385. PWAIT_FOR_NEW_LENGTH Waiter, NextWaiter;
  386. PSCB UsnJournal = Vcb->UsnJournal;
  387. NtfsAcquireExclusiveScb( IrpContext, UsnJournal );
  388. NtfsAcquireFsrtlHeader( UsnJournal );
  389. Waiter = (PWAIT_FOR_NEW_LENGTH) UsnJournal->ScbType.Data.WaitForNewLength.Flink;
  390. while (Waiter != (PWAIT_FOR_NEW_LENGTH) &UsnJournal->ScbType.Data.WaitForNewLength) {
  391. NextWaiter = (PWAIT_FOR_NEW_LENGTH) Waiter->WaitList.Flink;
  392. //
  393. // Make sure we own the Irp and there is not an active cancel
  394. // on this Irp.
  395. //
  396. if (NtfsClearCancelRoutine( Waiter->Irp )) {
  397. //
  398. // If this is an async request then simply complete the request.
  399. //
  400. if (FlagOn( Waiter->Flags, NTFS_WAIT_FLAG_ASYNC )) {
  401. //
  402. // Make sure we decrement the reference count in the Scb.
  403. // Then remove the waiter from the queue and complete the Irp.
  404. //
  405. InterlockedDecrement( &UsnJournal->CloseCount );
  406. RemoveEntryList( &Waiter->WaitList );
  407. NtfsCompleteRequest( NULL, Waiter->Irp, STATUS_VOLUME_DISMOUNTED );
  408. NtfsFreePool( Waiter );
  409. //
  410. // This is a synch Irp. All we can do is set the event and note the status
  411. // code.
  412. //
  413. } else {
  414. Waiter->Status = STATUS_VOLUME_DISMOUNTED;
  415. KeSetEvent( &Waiter->Event, 0, FALSE );
  416. }
  417. }
  418. //
  419. // Move to the next waiter.
  420. //
  421. Waiter = NextWaiter;
  422. }
  423. NtfsReleaseFsrtlHeader( UsnJournal );
  424. }
  425. //
  426. // Walk through and remove all of the entries on the UsnDeleteNotify queue.
  427. //
  428. NtfsAcquireUsnNotify( Vcb );
  429. Links = Vcb->NotifyUsnDeleteIrps.Flink;
  430. while (Links != &Vcb->NotifyUsnDeleteIrps) {
  431. UsnNotifyIrp = CONTAINING_RECORD( Links,
  432. IRP,
  433. Tail.Overlay.ListEntry );
  434. //
  435. // Remember to move forward in any case.
  436. //
  437. Links = Links->Flink;
  438. //
  439. // Clear the notify routine and detect if cancel has
  440. // already been called.
  441. //
  442. if (NtfsClearCancelRoutine( UsnNotifyIrp )) {
  443. RemoveEntryList( &UsnNotifyIrp->Tail.Overlay.ListEntry );
  444. NtfsCompleteRequest( NULL, UsnNotifyIrp, STATUS_VOLUME_DISMOUNTED );
  445. }
  446. }
  447. ClearFlag( Vcb->VcbState, VCB_STATE_USN_JOURNAL_ACTIVE );
  448. NtfsReleaseUsnNotify( Vcb );
  449. NtOfsCloseAttributeSafe( IrpContext, Vcb->UsnJournal );
  450. #ifdef SYSCACHE_DEBUG
  451. if (Vcb->SyscacheScb) {
  452. CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent;
  453. NTSTATUS WaitStatus;
  454. NtfsAcquireExclusiveScb( IrpContext, Vcb->SyscacheScb );
  455. KeInitializeEvent( &UninitializeCompleteEvent.Event,
  456. SynchronizationEvent,
  457. FALSE);
  458. CcUninitializeCacheMap( Vcb->SyscacheScb->FileObject,
  459. &Li0,
  460. &UninitializeCompleteEvent );
  461. //
  462. // Now wait for the cache manager to finish purging the file.
  463. // This will guarantee that Mm gets the purge before we
  464. // delete the Vcb.
  465. //
  466. WaitStatus = KeWaitForSingleObject( &UninitializeCompleteEvent.Event,
  467. Executive,
  468. KernelMode,
  469. FALSE,
  470. NULL);
  471. ASSERT( NT_SUCCESS( WaitStatus ) );
  472. ObDereferenceObject( Vcb->SyscacheScb->FileObject );
  473. Vcb->SyscacheScb->FileObject = NULL;
  474. NtfsDecrementCleanupCounts( Vcb->SyscacheScb, NULL, FALSE );
  475. NtOfsCloseAttributeSafe( IrpContext, Vcb->SyscacheScb );
  476. NtfsReleaseScb( IrpContext, Vcb->SyscacheScb );
  477. Vcb->SyscacheScb = NULL;
  478. }
  479. #endif
  480. //
  481. // Free the quota control template if necessary.
  482. //
  483. if (Vcb->QuotaControlTemplate != NULL) {
  484. NtfsFreePool( Vcb->QuotaControlTemplate );
  485. Vcb->QuotaControlTemplate = NULL;
  486. }
  487. //
  488. // Stop the log file.
  489. //
  490. NtfsStopLogFile( Vcb );
  491. //
  492. // Mark the volume as not mounted.
  493. //
  494. ClearFlag( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED );
  495. //
  496. // Now for every file Scb with an opened stream file we will delete
  497. // the internal attribute stream. Before the days of forced dismount
  498. // we were basically looking at system files. Restarting the enumeration
  499. // when we found an internal stream wasn't very expensive. Now that there
  500. // may be hundreds or even thousands of Fcbs we really don't want to resume
  501. // from the beginning. Instead we will reference the following entry
  502. // while removing the fileobject from the current Fcb. Then we know
  503. // the next entry will remain.
  504. //
  505. RestartKey = NULL;
  506. do {
  507. Fcb = NextFcb;
  508. NtfsAcquireFcbTable( IrpContext, Vcb );
  509. NextFcb = NtfsGetNextFcbTableEntry( Vcb, &RestartKey );
  510. //
  511. // We always want to reference the next entry if present to keep our order correct in the
  512. // list.
  513. //
  514. if (NextFcb != NULL) {
  515. //
  516. // We'll use this Fcb next time through the loop.
  517. //
  518. NextFcb->ReferenceCount += 1;
  519. }
  520. //
  521. // If our starting Fcb is NULL then we are at the first entry in the list or
  522. // we have exhausted the list. In either case our exist test in the loop
  523. // will handle it.
  524. //
  525. if (Fcb == NULL) {
  526. NtfsReleaseFcbTable( IrpContext, Vcb );
  527. continue;
  528. }
  529. //
  530. // Remove the extra reference on this Fcb.
  531. //
  532. ASSERT_FCB( Fcb );
  533. Fcb->ReferenceCount -= 1;
  534. NtfsReleaseFcbTable( IrpContext, Vcb );
  535. Scb = NULL;
  536. while ((Fcb != NULL) && ((Scb = NtfsGetNextChildScb( Fcb, Scb )) != NULL)) {
  537. FCB_CONTEXT FcbContext;
  538. ASSERT_SCB( Scb );
  539. if (Scb->FileObject != NULL) {
  540. //
  541. // Assume we want to see if we should check whether to clear a system Scb field.
  542. //
  543. CheckSystemScb = TRUE;
  544. //
  545. // For the VolumeDasdScb and bad cluster file, we simply decrement
  546. // the counts that we incremented.
  547. //
  548. if ((Scb == Vcb->VolumeDasdScb) ||
  549. (Scb == Vcb->BadClusterFileScb)) {
  550. Scb->FileObject = NULL;
  551. //
  552. // We need to know if the Fcb gets deleted.
  553. //
  554. Fcb->FcbContext = &FcbContext;
  555. FcbContext.FcbDeleted = FALSE;
  556. NtfsDecrementCloseCounts( IrpContext,
  557. Scb,
  558. NULL,
  559. TRUE,
  560. FALSE,
  561. FALSE );
  562. if (FcbContext.FcbDeleted) {
  563. Fcb = NULL;
  564. } else {
  565. Fcb->FcbContext = NULL;
  566. }
  567. //
  568. // Dereference the file object in the Scb unless it is the one in
  569. // the Vcb for the Log File. This routine may not be able to
  570. // dereference file object because of synchronization problems (there
  571. // can be a lazy writer callback in process which owns the paging
  572. // io resource). In that case we don't want to go back to the beginning
  573. // of Fcb table or we will loop indefinitely.
  574. //
  575. } else if (Scb->FileObject != Vcb->LogFileObject) {
  576. //
  577. // If this is the Usn journal then make sure to empty
  578. // the queue of modified Fcb's.
  579. //
  580. if (Scb == Vcb->UsnJournal) {
  581. PLIST_ENTRY Links;
  582. //
  583. // Before we remove the journal we want to remove all
  584. // of the entries in the modified list.
  585. //
  586. NtfsLockFcb( IrpContext, Scb->Fcb );
  587. Links = Vcb->ModifiedOpenFiles.Flink;
  588. while (Vcb->ModifiedOpenFiles.Flink != &Vcb->ModifiedOpenFiles) {
  589. RemoveEntryList( Links );
  590. Links->Flink = NULL;
  591. //
  592. // Look to see if we need to remove the TimeOut link as well.
  593. //
  594. Links = &(CONTAINING_RECORD( Links, FCB_USN_RECORD, ModifiedOpenFilesLinks ))->TimeOutLinks;
  595. if (Links->Flink != NULL) {
  596. RemoveEntryList( Links );
  597. }
  598. Links = Vcb->ModifiedOpenFiles.Flink;
  599. }
  600. NtfsUnlockFcb( IrpContext, Scb->Fcb );
  601. }
  602. //
  603. // Acquire the fcb rather than the scb since the scb may go away
  604. //
  605. NtfsAcquireExclusiveFcb( IrpContext, Fcb, Scb, ACQUIRE_NO_DELETE_CHECK );
  606. //
  607. // We need to know if the Fcb gets deleted.
  608. //
  609. Fcb->FcbContext = &FcbContext;
  610. FcbContext.FcbDeleted = FALSE;
  611. try {
  612. CheckSystemScb = NtfsDeleteInternalAttributeStream( Scb, TRUE, FALSE );
  613. } finally {
  614. if (FcbContext.FcbDeleted) {
  615. Fcb = NULL;
  616. } else {
  617. NtfsReleaseFcb( IrpContext, Fcb );
  618. Fcb->FcbContext = NULL;
  619. }
  620. }
  621. //
  622. // This is the file object for the Log file. Remove our
  623. // extra reference on the logfile Scb.
  624. //
  625. } else if (Scb->FileObject != NULL) {
  626. //
  627. // Remember the log file object so we can defer the dereference.
  628. //
  629. NtfsDecrementCloseCounts( IrpContext,
  630. Vcb->LogFileScb,
  631. NULL,
  632. TRUE,
  633. FALSE,
  634. TRUE );
  635. Scb->FileObject = NULL;
  636. }
  637. if (CheckSystemScb) {
  638. if (Scb == Vcb->MftScb) { Vcb->MftScb = NULL; }
  639. else if (Scb == Vcb->Mft2Scb) { Vcb->Mft2Scb = NULL; }
  640. else if (Scb == Vcb->LogFileScb) { Vcb->LogFileScb = NULL; }
  641. else if (Scb == Vcb->VolumeDasdScb) { Vcb->VolumeDasdScb = NULL; }
  642. else if (Scb == Vcb->AttributeDefTableScb) { Vcb->AttributeDefTableScb = NULL; }
  643. else if (Scb == Vcb->UpcaseTableScb) { Vcb->UpcaseTableScb = NULL; }
  644. else if (Scb == Vcb->RootIndexScb) { Vcb->RootIndexScb = NULL; }
  645. else if (Scb == Vcb->BitmapScb) { Vcb->BitmapScb = NULL; }
  646. else if (Scb == Vcb->BadClusterFileScb) { Vcb->BadClusterFileScb = NULL; }
  647. else if (Scb == Vcb->QuotaTableScb) { Vcb->QuotaTableScb = NULL; }
  648. else if (Scb == Vcb->MftBitmapScb) { Vcb->MftBitmapScb = NULL; }
  649. else if (Scb == Vcb->SecurityIdIndex) { Vcb->SecurityIdIndex = NULL; }
  650. else if (Scb == Vcb->SecurityDescriptorHashIndex)
  651. { Vcb->SecurityDescriptorHashIndex = NULL; }
  652. else if (Scb == Vcb->SecurityDescriptorStream)
  653. { Vcb->SecurityDescriptorStream = NULL; }
  654. else if (Scb == Vcb->ExtendDirectory) { Vcb->ExtendDirectory = NULL; }
  655. else if (Scb == Vcb->UsnJournal) { Vcb->UsnJournal = NULL; }
  656. //
  657. // Restart the Scb scan for this Fcb.
  658. // our call to Delete Internal Attribute Stream just messed up our
  659. // enumeration.
  660. //
  661. Scb = NULL;
  662. }
  663. }
  664. }
  665. } while (NextFcb != NULL);
  666. DebugTrace( 0, Dbg, ("Vcb->CloseCount = %08lx\n", Vcb->CloseCount) );
  667. //
  668. // Do any deleayed closes now so we can get the Vcb->CloseCount as
  669. // low as we possibly can so we have a good chance of being able to
  670. // close the logfile now.
  671. //
  672. if (!IsListEmpty( &NtfsData.AsyncCloseList ) ||
  673. !IsListEmpty( &NtfsData.DelayedCloseList )) {
  674. NtfsFspClose( Vcb );
  675. }
  676. //
  677. // The code above may have dropped the CloseCount to 0 even though
  678. // there's still a file object for the log file. If the count
  679. // isn't 0 yet, there's a chance that a lazy write could still
  680. // happen, in which case we need to keep the logfile around.
  681. // Often we can close the logfile now, so the Vpb refcount can go
  682. // to zero and show the PnP code that we're ready to be removed.
  683. // Any queued closes (async or delayed) don't matter either, since
  684. // we know no more writes will be coming in for those file objects.
  685. // The FspClose call above may not have caught all the outstanding
  686. // closes, since another thread may have just pulled a file from
  687. // one of the queues, but not yet processed the actual close.
  688. //
  689. if (((Vcb->CloseCount - Vcb->QueuedCloseCount) == 0) &&
  690. (Vcb->LogFileObject != NULL) &&
  691. !FlagOn( Vcb->CheckpointFlags, VCB_DEREFERENCED_LOG_FILE )) {
  692. CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent;
  693. NTSTATUS WaitStatus;
  694. KeInitializeEvent( &UninitializeCompleteEvent.Event,
  695. SynchronizationEvent,
  696. FALSE);
  697. CcUninitializeCacheMap( Vcb->LogFileObject,
  698. &Li0,
  699. &UninitializeCompleteEvent );
  700. //
  701. // Now wait for the cache manager to finish purging the file.
  702. // This will guarantee that Mm gets the purge before we
  703. // delete the Vcb.
  704. //
  705. WaitStatus = KeWaitForSingleObject( &UninitializeCompleteEvent.Event,
  706. Executive,
  707. KernelMode,
  708. FALSE,
  709. NULL);
  710. ASSERT( NT_SUCCESS( WaitStatus ) );
  711. //
  712. // Set a flag indicating that we are dereferencing the LogFileObject.
  713. //
  714. SetFlag( Vcb->CheckpointFlags, VCB_DEREFERENCED_LOG_FILE );
  715. ObDereferenceObject( Vcb->LogFileObject );
  716. }
  717. //
  718. // Now only really dismount the volume if that's what our caller wants.
  719. //
  720. if (DoCompleteDismount && !FlagOn( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT )) {
  721. PREVENT_MEDIA_REMOVAL Prevent;
  722. KIRQL SavedIrql;
  723. //
  724. // Attempt to unlock any removable media, ignoring status. We can't
  725. // do this if some previous PnP operation has stopped the device below
  726. // us. Remember that we may be dismounting now after the last async
  727. // close has been processed, so we can't just test whether the current
  728. // operation is a PnP remove.
  729. //
  730. if (!FlagOn( Vcb->VcbState, VCB_STATE_TARGET_DEVICE_STOPPED )) {
  731. Prevent.PreventMediaRemoval = FALSE;
  732. (VOID)NtfsDeviceIoControl( IrpContext,
  733. Vcb->TargetDeviceObject,
  734. IOCTL_DISK_MEDIA_REMOVAL,
  735. &Prevent,
  736. sizeof(PREVENT_MEDIA_REMOVAL),
  737. NULL,
  738. 0,
  739. NULL );
  740. }
  741. //
  742. // Remove this voldo from the mounted disk structures
  743. //
  744. IoAcquireVpbSpinLock( &SavedIrql );
  745. //
  746. // If there are no file objects and no reference counts in the
  747. // Vpb then we can use the existing Vpb. Or if we're cleaning
  748. // up a vcb where allocation for the spare vpb failed also use it.
  749. //
  750. if (((Vcb->CloseCount == 0) &&
  751. (Vcb->Vpb->ReferenceCount == 0)) ||
  752. (Vcb->SpareVpb == NULL)) {
  753. //
  754. // Make a new vpb the io subsys can delete
  755. //
  756. Vcb->Vpb->DeviceObject = NULL;
  757. ClearFlag( Vcb->Vpb->Flags, VPB_MOUNTED );
  758. if (ARGUMENT_PRESENT( NewVpbReturn )) {
  759. //
  760. // Let our caller know we did not end up needing the new vpb.
  761. //
  762. *NewVpbReturn = NULL;
  763. }
  764. //
  765. // Otherwise we will swap out the Vpb.
  766. //
  767. } else {
  768. //
  769. // Use the spare Vpb in the Vcb.
  770. //
  771. NewVpb = Vcb->SpareVpb;
  772. Vcb->SpareVpb = NULL;
  773. //
  774. // It better be there.
  775. //
  776. ASSERT( NewVpb != NULL );
  777. RtlZeroMemory( NewVpb, sizeof( VPB ) );
  778. //
  779. // Set a few important fields in the Vpb.
  780. //
  781. NewVpb->Type = IO_TYPE_VPB;
  782. NewVpb->Size = sizeof( VPB );
  783. NewVpb->RealDevice = Vcb->Vpb->RealDevice;
  784. NewVpb->DeviceObject = NULL;
  785. NewVpb->Flags = FlagOn( Vcb->Vpb->Flags, VPB_REMOVE_PENDING );
  786. if (ARGUMENT_PRESENT( NewVpbReturn )) {
  787. //
  788. // Let our caller know we will indeed need the new vpb.
  789. //
  790. *NewVpbReturn = NewVpb;
  791. }
  792. Vcb->Vpb->RealDevice->Vpb = NewVpb;
  793. SetFlag( Vcb->VcbState, VCB_STATE_TEMP_VPB );
  794. SetFlag( Vcb->Vpb->Flags, VPB_PERSISTENT );
  795. }
  796. IoReleaseVpbSpinLock( SavedIrql );
  797. SetFlag( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT );
  798. }
  799. } finally {
  800. //
  801. // We should never be leaking a reference count on an Fcb.
  802. //
  803. ASSERT( NextFcb == NULL );
  804. //
  805. // And return to our caller
  806. //
  807. DebugTrace( -1, Dbg, ("NtfsPerformDismountOnVcb -> VOID\n") );
  808. }
  809. return;
  810. }
  811. BOOLEAN
  812. NtfsPingVolume (
  813. IN PIRP_CONTEXT IrpContext,
  814. IN PVCB Vcb,
  815. IN OUT PBOOLEAN OwnsVcb OPTIONAL
  816. )
  817. /*++
  818. Routine Description:
  819. This routine will ping the volume to see if the device needs to
  820. be verified. It is used for create operations to see if the
  821. create should proceed or if we should complete the create Irp
  822. with a remount status.
  823. Arguments:
  824. Vcb - Supplies the Vcb being pinged
  825. OwnsVcb - Indicates if this thread already owns the Vcb. Updated here if we
  826. need serialization on the Vcb and it isn't already acquired. If not
  827. specified then we assume the Vcb is held.
  828. Return Value:
  829. BOOLEAN - TRUE if the volume is fine and the operation should
  830. proceed and FALSE if the volume needs to be verified
  831. --*/
  832. {
  833. BOOLEAN Results;
  834. ULONG ChangeCount = 0;
  835. PAGED_CODE();
  836. DebugTrace( +1, Dbg, ("NtfsPingVolume, Vcb = %08lx\n", Vcb) );
  837. //
  838. // If the media is removable and the verify volume flag in the
  839. // device object is not set then we want to ping the device
  840. // to see if it needs to be verified.
  841. //
  842. // Note that we only force this ping for create operations.
  843. // For others we take a sporting chance. If in the end we
  844. // have to physically access the disk, the right thing will happen.
  845. //
  846. if (FlagOn( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA ) &&
  847. !FlagOn( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME )) {
  848. PDEVICE_OBJECT TargetDevice;
  849. NTSTATUS Status;
  850. if (ARGUMENT_PRESENT( OwnsVcb ) && !(*OwnsVcb)) {
  851. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  852. *OwnsVcb = TRUE;
  853. }
  854. TargetDevice = Vcb->TargetDeviceObject;
  855. Status = NtfsDeviceIoControlAsync( IrpContext,
  856. TargetDevice,
  857. IOCTL_DISK_CHECK_VERIFY,
  858. (PVOID)&ChangeCount,
  859. sizeof(ChangeCount) );
  860. if (!NT_SUCCESS( Status )) {
  861. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  862. }
  863. if (ChangeCount != Vcb->DeviceChangeCount) {
  864. //
  865. // The disk driver lost a media change event, possibly
  866. // because it was eaten by a user request before the
  867. // volume was mounted. We set things up as they would
  868. // be if the driver had returned VERIFY_REQUIRED.
  869. //
  870. Vcb->DeviceChangeCount = ChangeCount;
  871. IoSetDeviceToVerify( PsGetCurrentThread(), TargetDevice );
  872. SetFlag( TargetDevice->Flags, DO_VERIFY_VOLUME );
  873. NtfsRaiseStatus( IrpContext, STATUS_VERIFY_REQUIRED, NULL, NULL );
  874. }
  875. }
  876. if (FlagOn( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME )) {
  877. Results = FALSE;
  878. } else {
  879. Results = TRUE;
  880. }
  881. DebugTrace( -1, Dbg, ("NtfsPingVolume -> %08lx\n", Results) );
  882. return Results;
  883. }
  884. VOID
  885. NtfsVolumeCheckpointDpc (
  886. IN PKDPC Dpc,
  887. IN PVOID DeferredContext,
  888. IN PVOID SystemArgument1,
  889. IN PVOID SystemArgument2
  890. )
  891. /*++
  892. Routine Description:
  893. This routine is dispatched every 5 seconds when disk structure is being
  894. modified. It had the ExWorker thread to volume checkpoints.
  895. Arguments:
  896. DeferredContext - Not Used
  897. Return Value:
  898. None.
  899. --*/
  900. {
  901. TIMER_STATUS TimerStatus;
  902. ULONG VolumeCheckpointStatus;
  903. //
  904. // Atomic reset of status indicating the timer is currently fired. This
  905. // synchronizes with NtfsSetDirtyBcb. After NtfsSetDirtyBcb dirties
  906. // a Bcb, it sees if it should enable this timer routine.
  907. //
  908. // If the status indicates that a timer is active, it does nothing. In this
  909. // case it is guaranteed that when the timer fires, it causes a checkpoint (to
  910. // force out the dirty Bcb data).
  911. //
  912. // If there is no timer active, it enables it, thus queueing a checkpoint later.
  913. //
  914. // If the timer routine actually fires between the dirtying of the Bcb and the
  915. // testing of the status then a single extra checkpoint is generated. This
  916. // extra checkpoint is not considered harmful.
  917. //
  918. //
  919. // Atomically reset status and get previous value
  920. //
  921. TimerStatus = InterlockedExchange( (PLONG)&NtfsData.TimerStatus, TIMER_NOT_SET );
  922. //
  923. // We have only one instance of the work queue item. It can only be
  924. // queued once. In a slow system, this checkpoint item may not be processed
  925. // by the time this timer routine fires again.
  926. //
  927. VolumeCheckpointStatus = InterlockedExchange( &NtfsData.VolumeCheckpointStatus,
  928. CHECKPOINT_POSTED | CHECKPOINT_PENDING );
  929. if (!FlagOn( VolumeCheckpointStatus, CHECKPOINT_POSTED )) {
  930. ASSERT( NtfsData.VolumeCheckpointItem.List.Flink == NULL );
  931. ExQueueWorkItem( &NtfsData.VolumeCheckpointItem, CriticalWorkQueue );
  932. }
  933. return;
  934. UNREFERENCED_PARAMETER( SystemArgument1 );
  935. UNREFERENCED_PARAMETER( SystemArgument2 );
  936. UNREFERENCED_PARAMETER( DeferredContext );
  937. UNREFERENCED_PARAMETER( Dpc );
  938. }
  939. VOID
  940. NtfsCheckpointAllVolumes (
  941. PVOID Parameter
  942. )
  943. /*++
  944. Routine Description:
  945. This routine searches all of the vcbs for Ntfs and tries to clean
  946. them. If the vcb is good and dirty but not almost clean then
  947. we set it almost clean. If the Vcb is good and dirty and almost clean
  948. then we clean it.
  949. Arguments:
  950. Parameter - Not Used.
  951. Return Value:
  952. None.
  953. --*/
  954. {
  955. TOP_LEVEL_CONTEXT TopLevelContext;
  956. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  957. IRP_CONTEXT LocalIrpContext;
  958. PIRP_CONTEXT IrpContext = &LocalIrpContext;
  959. PLIST_ENTRY Links;
  960. PVCB Vcb;
  961. BOOLEAN AcquiredGlobal = FALSE;
  962. BOOLEAN StartTimer = FALSE;
  963. TIMER_STATUS TimerStatus;
  964. ULONG VolumeCheckpointStatus;
  965. PAGED_CODE();
  966. //
  967. // Note that an exception like log file terminates the Vcb scan until the next
  968. // interval. It would be possible to restructure this routine to work on the other
  969. // volumes first, however for deadlock prevention it is also nice to free up this
  970. // thread to handle the checkpoint.
  971. //
  972. try {
  973. //
  974. // Clear the flag that indicates someone is waiting for a checkpoint. That way
  975. // we can tell if the checkpoint timer fires while we are checkpointing.
  976. //
  977. InterlockedExchange( &NtfsData.VolumeCheckpointStatus, CHECKPOINT_POSTED );
  978. //
  979. // Create an IrpContext and make sure it doesn't go away until we are ready.
  980. //
  981. NtfsInitializeIrpContext( NULL, TRUE, &IrpContext );
  982. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_PERSISTENT );
  983. //
  984. // Make sure we don't get any pop-ups
  985. //
  986. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, TRUE, FALSE );
  987. ASSERT( ThreadTopLevelContext == &TopLevelContext );
  988. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  989. NtfsAcquireSharedGlobal( IrpContext, TRUE );
  990. AcquiredGlobal = TRUE;
  991. for (Links = NtfsData.VcbQueue.Flink;
  992. Links != &NtfsData.VcbQueue;
  993. Links = Links->Flink) {
  994. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  995. Vcb = CONTAINING_RECORD(Links, VCB, VcbLinks);
  996. IrpContext->Vcb = Vcb;
  997. if (FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) &&
  998. (!NtfsIsVolumeReadOnly( Vcb ))) {
  999. NtfsCheckpointVolume( IrpContext, Vcb, FALSE, FALSE, TRUE, 0, Li0 );
  1000. //
  1001. // Check to see whether this was not a clean checkpoint.
  1002. //
  1003. if (!FlagOn( Vcb->CheckpointFlags, VCB_LAST_CHECKPOINT_CLEAN )) {
  1004. StartTimer = TRUE;
  1005. }
  1006. NtfsCommitCurrentTransaction( IrpContext );
  1007. #if DBG
  1008. if (NtfsCheckQuota && Vcb->QuotaTableScb != NULL) {
  1009. NtfsPostRepairQuotaIndex( IrpContext, Vcb );
  1010. }
  1011. #endif
  1012. }
  1013. //
  1014. // Clean up this IrpContext.
  1015. //
  1016. NtfsCleanupIrpContext( IrpContext, TRUE );
  1017. }
  1018. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  1019. //
  1020. // Process the exception. We know the IrpContext won't go away here.
  1021. //
  1022. NtfsProcessException( IrpContext, NULL, GetExceptionCode() );
  1023. }
  1024. if (AcquiredGlobal) {
  1025. NtfsReleaseGlobal( IrpContext );
  1026. }
  1027. VolumeCheckpointStatus = InterlockedExchange( &NtfsData.VolumeCheckpointStatus, 0 );
  1028. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_PERSISTENT );
  1029. NtfsCleanupIrpContext( IrpContext, TRUE );
  1030. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  1031. //
  1032. // Synchronize with the checkpoint timer and other instances of this routine.
  1033. //
  1034. // Perform an interlocked exchange to indicate that a timer is being set.
  1035. //
  1036. // If the previous value indicates that no timer was set, then we
  1037. // enable the volume checkpoint timer. This will guarantee that a checkpoint
  1038. // will occur to flush out the dirty Bcb data.
  1039. //
  1040. // If the timer was set previously, then it is guaranteed that a checkpoint
  1041. // will occur without this routine having to reenable the timer.
  1042. //
  1043. // If the timer and checkpoint occurred between the dirtying of the Bcb and
  1044. // the setting of the timer status, then we will be queueing a single extra
  1045. // checkpoint on a clean volume. This is not considered harmful.
  1046. //
  1047. //
  1048. // Atomically set the timer status to indicate a timer is being set and
  1049. // retrieve the previous value.
  1050. //
  1051. if (StartTimer || FlagOn( VolumeCheckpointStatus, CHECKPOINT_PENDING )) {
  1052. TimerStatus = InterlockedExchange( (PLONG)&NtfsData.TimerStatus, TIMER_SET );
  1053. //
  1054. // If the timer is not currently set then we must start the checkpoint timer
  1055. // to make sure the above dirtying is flushed out.
  1056. //
  1057. if (TimerStatus == TIMER_NOT_SET) {
  1058. LONGLONG NewTimerValue;
  1059. //
  1060. // If the timer timed out because the checkpoint took so long then
  1061. // only wait two seconds. Otherwise use our normal time of five seconds.
  1062. //
  1063. if (FlagOn( VolumeCheckpointStatus, CHECKPOINT_PENDING )) {
  1064. NewTimerValue = -2*1000*1000*10;
  1065. } else {
  1066. NewTimerValue = -5*1000*1000*10;
  1067. }
  1068. KeSetTimer( &NtfsData.VolumeCheckpointTimer,
  1069. *(PLARGE_INTEGER) &NewTimerValue,
  1070. &NtfsData.VolumeCheckpointDpc );
  1071. }
  1072. }
  1073. //
  1074. // Pulse the NtfsEncryptionPendingEvent so there's no chance of a waiter waiting forever.
  1075. //
  1076. KeSetEvent( &NtfsEncryptionPendingEvent, 0, FALSE );
  1077. //
  1078. // And return to our caller
  1079. //
  1080. return;
  1081. UNREFERENCED_PARAMETER( Parameter );
  1082. }
  1083. VOID
  1084. NtfsUsnTimeOutDpc (
  1085. IN PKDPC Dpc,
  1086. IN PVOID DeferredContext,
  1087. IN PVOID SystemArgument1,
  1088. IN PVOID SystemArgument2
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. This routine is dispatched every 5 minutes to look for Usn records waiting
  1093. for a close to be issued. It posts a work item to the ExWorker thread.
  1094. Arguments:
  1095. DeferredContext - Not Used
  1096. Return Value:
  1097. None.
  1098. --*/
  1099. {
  1100. ASSERT( NtfsData.UsnTimeOutItem.List.Flink == NULL );
  1101. ExQueueWorkItem( &NtfsData.UsnTimeOutItem, CriticalWorkQueue );
  1102. return;
  1103. UNREFERENCED_PARAMETER( SystemArgument1 );
  1104. UNREFERENCED_PARAMETER( SystemArgument2 );
  1105. UNREFERENCED_PARAMETER( DeferredContext );
  1106. UNREFERENCED_PARAMETER( Dpc );
  1107. }
  1108. VOID
  1109. NtfsCheckUsnTimeOut (
  1110. PVOID Parameter
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. This is the worker routine which walks the queue of UsnRecords waiting for close records. It either
  1115. issues the close record and/or removes it from the queue of TimeOut records. It also toggles the
  1116. two TimeOut queues and restarts the timer for the next break.
  1117. Arguments:
  1118. Return Value:
  1119. None.
  1120. --*/
  1121. {
  1122. TOP_LEVEL_CONTEXT TopLevelContext;
  1123. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  1124. IRP_CONTEXT LocalIrpContext;
  1125. PIRP_CONTEXT IrpContext = &LocalIrpContext;
  1126. PFCB_USN_RECORD FcbUsnRecord;
  1127. PLIST_ENTRY Links;
  1128. PVCB Vcb;
  1129. PFCB Fcb;
  1130. BOOLEAN AcquiredGlobal = FALSE;
  1131. BOOLEAN AcquiredVcb = FALSE;
  1132. BOOLEAN AcquiredFcb = FALSE;
  1133. PLIST_ENTRY Temp;
  1134. PAGED_CODE();
  1135. FsRtlEnterFileSystem();
  1136. //
  1137. // Note that an exception like log file terminates the Vcb scan until the next
  1138. // interval. It would be possible to restructure this routine to work on the other
  1139. // volumes first, however for deadlock prevention it is also nice to free up this
  1140. // thread to handle the checkpoint.
  1141. //
  1142. try {
  1143. //
  1144. // Create an IrpContext and make sure it doesn't go away until we are ready.
  1145. //
  1146. NtfsInitializeIrpContext( NULL, TRUE, &IrpContext );
  1147. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_PERSISTENT );
  1148. //
  1149. // Make sure we don't get any pop-ups
  1150. //
  1151. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, TRUE, FALSE );
  1152. ASSERT( ThreadTopLevelContext == &TopLevelContext );
  1153. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  1154. NtfsAcquireSharedGlobal( IrpContext, TRUE );
  1155. AcquiredGlobal = TRUE;
  1156. for (Links = NtfsData.VcbQueue.Flink;
  1157. Links != &NtfsData.VcbQueue;
  1158. Links = Links->Flink) {
  1159. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  1160. Vcb = CONTAINING_RECORD(Links, VCB, VcbLinks);
  1161. IrpContext->Vcb = Vcb;
  1162. if (FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  1163. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  1164. AcquiredVcb = TRUE;
  1165. if (Vcb->UsnJournal != NULL) {
  1166. do {
  1167. Fcb = NULL;
  1168. //
  1169. // Synchronize with the Fcb table and Usn Journal so that we can
  1170. // see if the next Fcb has to have a close record generated.
  1171. //
  1172. NtfsAcquireFcbTable( IrpContext, Vcb );
  1173. NtfsAcquireFsrtlHeader( Vcb->UsnJournal );
  1174. if (!IsListEmpty( Vcb->AgedTimeOutFiles )) {
  1175. FcbUsnRecord = (PFCB_USN_RECORD)CONTAINING_RECORD( Vcb->AgedTimeOutFiles->Flink,
  1176. FCB_USN_RECORD,
  1177. TimeOutLinks );
  1178. //
  1179. // Since we have a UsnRecord and Fcb we want to reference the Fcb so
  1180. // it won't go away.
  1181. //
  1182. Fcb = FcbUsnRecord->Fcb;
  1183. Fcb->ReferenceCount += 1;
  1184. }
  1185. NtfsReleaseFsrtlHeader( Vcb->UsnJournal );
  1186. NtfsReleaseFcbTable( IrpContext, Vcb );
  1187. //
  1188. // Do we have to generate another close record?
  1189. //
  1190. if (Fcb != NULL) {
  1191. //
  1192. // We must lock out other activity on this file since we are about
  1193. // to reset the Usn reasons.
  1194. //
  1195. if (Fcb->PagingIoResource != NULL) {
  1196. ExAcquireResourceExclusiveLite( Fcb->PagingIoResource, TRUE );
  1197. }
  1198. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, ACQUIRE_NO_DELETE_CHECK );
  1199. AcquiredFcb = TRUE;
  1200. //
  1201. // Skip over system files, files which now have a handle count, deleted
  1202. // files or files which are no longer on the aged list.
  1203. //
  1204. if (!FlagOn( Fcb->FcbState, FCB_STATE_SYSTEM_FILE | FCB_STATE_FILE_DELETED ) &&
  1205. (Fcb->CleanupCount == 0) &&
  1206. (Fcb->FcbUsnRecord != NULL) &&
  1207. (Fcb->FcbUsnRecord->TimeOutLinks.Flink != NULL)) {
  1208. //
  1209. // Post the close to our IrpContext.
  1210. //
  1211. NtfsPostUsnChange( IrpContext, Fcb, USN_REASON_CLOSE );
  1212. //
  1213. // If we did not actually post a change, something is wrong,
  1214. // because when a close change is written, the Fcb is removed from
  1215. // the list.
  1216. //
  1217. ASSERT( IrpContext->Usn.CurrentUsnFcb != NULL );
  1218. //
  1219. // Now generate the close record and checkpoint the transaction.
  1220. //
  1221. NtfsWriteUsnJournalChanges( IrpContext );
  1222. NtfsCheckpointCurrentTransaction( IrpContext );
  1223. //
  1224. // Remove this entry from the time out list if still present.
  1225. //
  1226. } else if ((Fcb->FcbUsnRecord != NULL) &&
  1227. (Fcb->FcbUsnRecord->TimeOutLinks.Flink != NULL)) {
  1228. NtfsAcquireFsrtlHeader( Vcb->UsnJournal );
  1229. RemoveEntryList( &Fcb->FcbUsnRecord->TimeOutLinks );
  1230. Fcb->FcbUsnRecord->TimeOutLinks.Flink = NULL;
  1231. NtfsReleaseFsrtlHeader( Vcb->UsnJournal );
  1232. }
  1233. //
  1234. // Now we will dereference the Fcb.
  1235. //
  1236. NtfsAcquireFcbTable( IrpContext, Vcb );
  1237. Fcb->ReferenceCount -= 1;
  1238. //
  1239. // We may be required to delete this guy. This frees the Fcb Table.
  1240. //
  1241. if (IsListEmpty( &Fcb->ScbQueue ) && (Fcb->ReferenceCount == 0) && (Fcb->CloseCount == 0)) {
  1242. BOOLEAN AcquiredFcbTable = TRUE;
  1243. NtfsDeleteFcb( IrpContext, &Fcb, &AcquiredFcbTable );
  1244. ASSERT( !AcquiredFcbTable );
  1245. //
  1246. // Otherwise free the table and Fcb resources.
  1247. //
  1248. } else {
  1249. NtfsReleaseFcbTable( IrpContext, Vcb );
  1250. //
  1251. // Release in inverse order because only main holds down
  1252. // the fcb
  1253. //
  1254. if (Fcb->PagingIoResource != NULL) {
  1255. ExReleaseResourceLite( Fcb->PagingIoResource );
  1256. }
  1257. NtfsReleaseFcb( IrpContext, Fcb );
  1258. }
  1259. AcquiredFcb = FALSE;
  1260. }
  1261. } while (Fcb != NULL);
  1262. //
  1263. // Now swap the aged lists.
  1264. //
  1265. ASSERT( IsListEmpty( Vcb->AgedTimeOutFiles ));
  1266. NtfsLockFcb( IrpContext, Vcb->UsnJournal->Fcb );
  1267. Temp = Vcb->AgedTimeOutFiles;
  1268. Vcb->AgedTimeOutFiles = Vcb->CurrentTimeOutFiles;
  1269. Vcb->CurrentTimeOutFiles = Temp;
  1270. NtfsUnlockFcb( IrpContext, Vcb->UsnJournal->Fcb );
  1271. }
  1272. //
  1273. // Now we can drop the Vcb before looping back.
  1274. //
  1275. NtfsReleaseVcb( IrpContext, Vcb );
  1276. AcquiredVcb = FALSE;
  1277. //
  1278. // Clean up this IrpContext.
  1279. //
  1280. NtfsCleanupIrpContext( IrpContext, TRUE );
  1281. }
  1282. }
  1283. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  1284. if (AcquiredFcb) {
  1285. NtfsAcquireFcbTable( IrpContext, Vcb );
  1286. Fcb->ReferenceCount -= 1;
  1287. NtfsReleaseFcbTable( IrpContext, Vcb );
  1288. //
  1289. // Only main protects the fcb from being deleted so release in inverse order
  1290. //
  1291. if (Fcb->PagingIoResource != NULL) {
  1292. ExReleaseResourceLite( Fcb->PagingIoResource );
  1293. }
  1294. NtfsReleaseFcb( IrpContext, Fcb );
  1295. }
  1296. AcquiredFcb = FALSE;
  1297. if (AcquiredVcb) {
  1298. NtfsReleaseVcb( IrpContext, Vcb );
  1299. AcquiredVcb = FALSE;
  1300. }
  1301. //
  1302. // Process the exception. We know the IrpContext won't go away here.
  1303. //
  1304. NtfsProcessException( IrpContext, NULL, GetExceptionCode() );
  1305. }
  1306. if (AcquiredFcb) {
  1307. NtfsReleaseFcb( IrpContext, Fcb );
  1308. if (Fcb->PagingIoResource != NULL) {
  1309. ExReleaseResourceLite( Fcb->PagingIoResource );
  1310. }
  1311. }
  1312. if (AcquiredVcb) {
  1313. NtfsReleaseVcb( IrpContext, Vcb );
  1314. }
  1315. if (AcquiredGlobal) {
  1316. NtfsReleaseGlobal( IrpContext );
  1317. }
  1318. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_PERSISTENT );
  1319. NtfsCleanupIrpContext( IrpContext, TRUE );
  1320. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  1321. //
  1322. // Now start the timer again.
  1323. //
  1324. {
  1325. LONGLONG FiveMinutesFromNow = -5*1000*1000*10;
  1326. FiveMinutesFromNow *= 60;
  1327. KeSetTimer( &NtfsData.UsnTimeOutTimer,
  1328. *(PLARGE_INTEGER)&FiveMinutesFromNow,
  1329. &NtfsData.UsnTimeOutDpc );
  1330. }
  1331. FsRtlExitFileSystem();
  1332. return;
  1333. UNREFERENCED_PARAMETER( Parameter );
  1334. }
  1335. NTSTATUS
  1336. NtfsDeviceIoControlAsync (
  1337. IN PIRP_CONTEXT IrpContext,
  1338. IN PDEVICE_OBJECT DeviceObject,
  1339. IN ULONG IoCtl,
  1340. IN OUT PVOID Buffer OPTIONAL,
  1341. IN ULONG BufferLength
  1342. )
  1343. /*++
  1344. Routine Description:
  1345. This routine is used to perform an IoCtl when we may be at the APC level
  1346. and calling NtfsDeviceIoControl could be unsafe.
  1347. Arguments:
  1348. DeviceObject - Supplies the device object to which to send the ioctl.
  1349. IoCtl - Supplies the I/O control code.
  1350. Buffer - Points to a buffer for any extra input/output for the given ioctl.
  1351. BufferLength - The size, in bytes, of the above buffer.
  1352. Return Value:
  1353. Status.
  1354. --*/
  1355. {
  1356. KEVENT Event;
  1357. PIRP Irp;
  1358. NTSTATUS Status;
  1359. PIO_STACK_LOCATION IrpSp;
  1360. ASSERT_IRP_CONTEXT( IrpContext );
  1361. //
  1362. // Initialize the event we're going to use
  1363. //
  1364. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  1365. //
  1366. // Build the irp for the operation and also set the overrride flag
  1367. //
  1368. // Note that we may be at APC level, so do this asyncrhonously and
  1369. // use an event for synchronization normal request completion
  1370. // cannot occur at APC level.
  1371. //
  1372. // We use IRP_MJ_FLUSH_BUFFERS since it (ironically) doesn't require
  1373. // a buffer.
  1374. //
  1375. Irp = IoBuildAsynchronousFsdRequest( IRP_MJ_FLUSH_BUFFERS,
  1376. DeviceObject,
  1377. NULL,
  1378. 0,
  1379. NULL,
  1380. NULL );
  1381. if ( Irp == NULL ) {
  1382. NtfsRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES, NULL, NULL );
  1383. }
  1384. IrpSp = IoGetNextIrpStackLocation( Irp );
  1385. SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  1386. IrpSp->Parameters.DeviceIoControl.IoControlCode = IoCtl;
  1387. Irp->AssociatedIrp.SystemBuffer = Buffer;
  1388. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = BufferLength;
  1389. //
  1390. // Reset the major code to the correct value.
  1391. //
  1392. IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  1393. //
  1394. // Set up the completion routine.
  1395. //
  1396. IoSetCompletionRoutine( Irp,
  1397. NtfsVerifyReadCompletionRoutine,
  1398. &Event,
  1399. TRUE,
  1400. TRUE,
  1401. TRUE );
  1402. //
  1403. // Call the device to do the io and wait for it to finish.
  1404. //
  1405. (VOID)IoCallDriver( DeviceObject, Irp );
  1406. (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
  1407. //
  1408. // Grab the Status.
  1409. //
  1410. Status = Irp->IoStatus.Status;
  1411. IoFreeIrp( Irp );
  1412. //
  1413. // And return to our caller.
  1414. //
  1415. return Status;
  1416. }
  1417. //
  1418. // Local Support routine
  1419. //
  1420. VOID
  1421. NtfsPerformVerifyDiskRead (
  1422. IN PIRP_CONTEXT IrpContext,
  1423. IN PVCB Vcb,
  1424. IN PVOID Buffer,
  1425. IN LONGLONG Offset,
  1426. IN ULONG NumberOfBytesToRead
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. This routine is used to read in a range of bytes from the disk. It
  1431. bypasses all of the caching and regular I/O logic, and builds and issues
  1432. the requests itself. It does this operation overriding the verify
  1433. volume flag in the device object.
  1434. Arguments:
  1435. Vcb - Supplies the Vcb denoting the device for this operation
  1436. Buffer - Supplies the buffer that will recieve the results of this operation
  1437. Offset - Supplies the offset of where to start reading
  1438. NumberOfBytesToRead - Supplies the number of bytes to read, this must
  1439. be in multiple of bytes units acceptable to the disk driver.
  1440. Return Value:
  1441. None.
  1442. --*/
  1443. {
  1444. KEVENT Event;
  1445. PIRP Irp;
  1446. NTSTATUS Status;
  1447. ASSERT_IRP_CONTEXT( IrpContext );
  1448. ASSERT_VCB( Vcb );
  1449. PAGED_CODE();
  1450. //
  1451. // Initialize the event we're going to use
  1452. //
  1453. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  1454. //
  1455. // Build the irp for the operation and also set the overrride flag
  1456. //
  1457. // Note that we may be at APC level, so do this asyncrhonously and
  1458. // use an event for synchronization normal request completion
  1459. // cannot occur at APC level.
  1460. //
  1461. Irp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ,
  1462. Vcb->TargetDeviceObject,
  1463. Buffer,
  1464. NumberOfBytesToRead,
  1465. (PLARGE_INTEGER)&Offset,
  1466. NULL );
  1467. if ( Irp == NULL ) {
  1468. NtfsRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES, NULL, NULL );
  1469. }
  1470. SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  1471. //
  1472. // Set up the completion routine
  1473. //
  1474. IoSetCompletionRoutine( Irp,
  1475. NtfsVerifyReadCompletionRoutine,
  1476. &Event,
  1477. TRUE,
  1478. TRUE,
  1479. TRUE );
  1480. //
  1481. // Call the device to do the write and wait for it to finish.
  1482. //
  1483. try {
  1484. (VOID)IoCallDriver( Vcb->TargetDeviceObject, Irp );
  1485. (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
  1486. //
  1487. // Grab the Status.
  1488. //
  1489. Status = Irp->IoStatus.Status;
  1490. } finally {
  1491. //
  1492. // If there is an MDL (or MDLs) associated with this I/O
  1493. // request, Free it (them) here. This is accomplished by
  1494. // walking the MDL list hanging off of the IRP and deallocating
  1495. // each MDL encountered.
  1496. //
  1497. while (Irp->MdlAddress != NULL) {
  1498. PMDL NextMdl;
  1499. NextMdl = Irp->MdlAddress->Next;
  1500. MmUnlockPages( Irp->MdlAddress );
  1501. IoFreeMdl( Irp->MdlAddress );
  1502. Irp->MdlAddress = NextMdl;
  1503. }
  1504. IoFreeIrp( Irp );
  1505. }
  1506. //
  1507. // If it doesn't succeed then raise the error
  1508. //
  1509. if (!NT_SUCCESS(Status)) {
  1510. NtfsNormalizeAndRaiseStatus( IrpContext,
  1511. Status,
  1512. STATUS_UNEXPECTED_IO_ERROR );
  1513. }
  1514. //
  1515. // And return to our caller
  1516. //
  1517. return;
  1518. }
  1519. NTSTATUS
  1520. NtfsIoCallSelf (
  1521. IN PIRP_CONTEXT IrpContext,
  1522. IN PFILE_OBJECT FileObject,
  1523. IN UCHAR MajorFunction
  1524. )
  1525. /*++
  1526. Routine Description:
  1527. This routine is used to call ourselves for a simple function. Note that
  1528. if more use is found for this routine than the few current uses, its interface
  1529. may be easily expanded.
  1530. Arguments:
  1531. FileObject - FileObject for request.
  1532. MajorFunction - function to be performed.
  1533. Return Value:
  1534. Status code resulting from the driver call
  1535. --*/
  1536. {
  1537. KEVENT Event;
  1538. PIRP Irp;
  1539. PDEVICE_OBJECT DeviceObject;
  1540. PIO_STACK_LOCATION IrpSp;
  1541. NTSTATUS Status;
  1542. ASSERT_IRP_CONTEXT( IrpContext );
  1543. PAGED_CODE();
  1544. //
  1545. // Initialize the event we're going to use
  1546. //
  1547. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  1548. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  1549. //
  1550. // Build the irp for the operation and also set the overrride flag
  1551. //
  1552. // Note that we may be at APC level, so do this asyncrhonously and
  1553. // use an event for synchronization normal request completion
  1554. // cannot occur at APC level.
  1555. //
  1556. Irp = IoBuildAsynchronousFsdRequest( IRP_MJ_SHUTDOWN,
  1557. DeviceObject,
  1558. NULL,
  1559. 0,
  1560. NULL,
  1561. NULL );
  1562. if (Irp == NULL) {
  1563. return STATUS_INSUFFICIENT_RESOURCES;
  1564. }
  1565. //
  1566. // Fill in a few remaining items
  1567. //
  1568. Irp->Tail.Overlay.OriginalFileObject = FileObject;
  1569. IrpSp = IoGetNextIrpStackLocation(Irp);
  1570. IrpSp->MajorFunction = MajorFunction;
  1571. IrpSp->FileObject = FileObject;
  1572. //
  1573. // Set up the completion routine
  1574. //
  1575. IoSetCompletionRoutine( Irp,
  1576. NtfsVerifyReadCompletionRoutine,
  1577. &Event,
  1578. TRUE,
  1579. TRUE,
  1580. TRUE );
  1581. NtfsPurgeFileRecordCache( IrpContext );
  1582. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CALL_SELF );
  1583. //
  1584. // Call the device to do the write and wait for it to finish.
  1585. //
  1586. try {
  1587. (VOID)IoCallDriver( DeviceObject, Irp );
  1588. (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
  1589. //
  1590. // Grab the Status.
  1591. //
  1592. Status = Irp->IoStatus.Status;
  1593. } finally {
  1594. //
  1595. // There should never be an MDL here.
  1596. //
  1597. ASSERT(Irp->MdlAddress == NULL);
  1598. IoFreeIrp( Irp );
  1599. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CALL_SELF );
  1600. }
  1601. //
  1602. // If it doesn't succeed then raise the error
  1603. //
  1604. // And return to our caller
  1605. //
  1606. return Status;
  1607. }
  1608. BOOLEAN
  1609. NtfsLogEventInternal (
  1610. IN PVCB Vcb,
  1611. IN UCHAR MajorFunction,
  1612. IN ULONG TransactionId,
  1613. IN PUNICODE_STRING String OPTIONAL,
  1614. IN PQUOTA_USER_DATA UserData OPTIONAL,
  1615. IN NTSTATUS LogCode,
  1616. IN NTSTATUS FinalStatus
  1617. )
  1618. /*++
  1619. Routine Description:
  1620. Create an eventlogentry. This version is given all the strings and user data
  1621. it needs.
  1622. Arguments:
  1623. Vcb - the vcb
  1624. MajorFunction - irp majorfunction when log was generated
  1625. TransactionId - transaction id for transaction if any
  1626. String - Any string needed in the message
  1627. UserData - Any userdata
  1628. LogCode - IO_ type code (NOT an NTSTATUS) see ntiologc.h
  1629. FinalStatus - NTSTATUS of error
  1630. Return Value:
  1631. TRUE if successful
  1632. --*/
  1633. {
  1634. PIO_ERROR_LOG_PACKET ErrorLogEntry;
  1635. PFILE_QUOTA_INFORMATION FileQuotaInfo;
  1636. ULONG SidLength;
  1637. ULONG DumpDataLength = 0;
  1638. ULONG StringLength = 0;
  1639. ULONG LogSize = sizeof( IO_ERROR_LOG_PACKET );
  1640. PWCHAR RecordString;
  1641. if (Vcb == NULL) {
  1642. return FALSE;
  1643. }
  1644. if (ARGUMENT_PRESENT( String )) {
  1645. StringLength = String->Length + sizeof(WCHAR);
  1646. LogSize += StringLength;
  1647. }
  1648. if (ARGUMENT_PRESENT( UserData )) {
  1649. //
  1650. // Calculate the required length of the Sid.
  1651. //
  1652. SidLength = RtlLengthSid( &UserData->QuotaSid );
  1653. DumpDataLength = SidLength +
  1654. FIELD_OFFSET( FILE_QUOTA_INFORMATION, Sid );
  1655. //
  1656. // The error packet already has 1 ulong for dump data in it
  1657. //
  1658. LogSize += DumpDataLength - sizeof( ULONG );
  1659. }
  1660. if (LogSize > ERROR_LOG_MAXIMUM_SIZE) {
  1661. LogSize = ERROR_LOG_MAXIMUM_SIZE;
  1662. }
  1663. //
  1664. // We don't deal with the user dump data not fitting in the record
  1665. //
  1666. ASSERT( DumpDataLength - sizeof( ULONG ) + sizeof( IO_ERROR_LOG_PACKET ) <= LogSize );
  1667. ErrorLogEntry = (PIO_ERROR_LOG_PACKET)
  1668. IoAllocateErrorLogEntry( (CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb ))->DeviceObject.DriverObject,
  1669. (UCHAR) (LogSize) );
  1670. if (ErrorLogEntry == NULL) {
  1671. return FALSE;
  1672. }
  1673. ErrorLogEntry->EventCategory = ELF_CATEGORY_DISK;
  1674. ErrorLogEntry->ErrorCode = LogCode;
  1675. ErrorLogEntry->FinalStatus = FinalStatus;
  1676. ErrorLogEntry->SequenceNumber = TransactionId;
  1677. ErrorLogEntry->MajorFunctionCode = MajorFunction;
  1678. ErrorLogEntry->RetryCount = 0;
  1679. ErrorLogEntry->DumpDataSize = (USHORT) DumpDataLength;
  1680. //
  1681. // The label string at the end of the error log entry.
  1682. //
  1683. ErrorLogEntry->NumberOfStrings = 1;
  1684. ErrorLogEntry->StringOffset = (USHORT) (sizeof( IO_ERROR_LOG_PACKET ) + DumpDataLength - sizeof( ULONG ));
  1685. RecordString = (PWCHAR) Add2Ptr( ErrorLogEntry, ErrorLogEntry->StringOffset );
  1686. if (LogSize - ErrorLogEntry->StringOffset < StringLength) {
  1687. RtlCopyMemory( RecordString,
  1688. String->Buffer,
  1689. LogSize - ErrorLogEntry->StringOffset - sizeof( WCHAR ) * 4 );
  1690. RecordString += (LogSize - ErrorLogEntry->StringOffset - sizeof( WCHAR ) * 4) / sizeof(WCHAR);
  1691. RtlCopyMemory( RecordString, L"...", sizeof( WCHAR ) * 4 );
  1692. } else {
  1693. RtlCopyMemory( RecordString,
  1694. String->Buffer,
  1695. String->Length );
  1696. //
  1697. // Make sure the string is null terminated.
  1698. //
  1699. RecordString += String->Length / sizeof( WCHAR );
  1700. *RecordString = L'\0';
  1701. }
  1702. if (ARGUMENT_PRESENT( UserData )) {
  1703. FileQuotaInfo = (PFILE_QUOTA_INFORMATION) ErrorLogEntry->DumpData;
  1704. FileQuotaInfo->NextEntryOffset = 0;
  1705. FileQuotaInfo->SidLength = SidLength;
  1706. FileQuotaInfo->ChangeTime.QuadPart = UserData->QuotaChangeTime;
  1707. FileQuotaInfo->QuotaUsed.QuadPart = UserData->QuotaUsed;
  1708. FileQuotaInfo->QuotaThreshold.QuadPart = UserData->QuotaThreshold;
  1709. FileQuotaInfo->QuotaLimit.QuadPart = UserData->QuotaLimit;
  1710. RtlCopyMemory( &FileQuotaInfo->Sid,
  1711. &UserData->QuotaSid,
  1712. SidLength );
  1713. }
  1714. IoWriteErrorLogEntry( ErrorLogEntry );
  1715. return TRUE;
  1716. }
  1717. BOOLEAN
  1718. NtfsLogEvent (
  1719. IN PIRP_CONTEXT IrpContext,
  1720. IN PQUOTA_USER_DATA UserData OPTIONAL,
  1721. IN NTSTATUS LogCode,
  1722. IN NTSTATUS FinalStatus
  1723. )
  1724. /*++
  1725. Routine Description:
  1726. This routine logs an io event. If UserData is supplied then the
  1727. data logged is a FILE_QUOTA_INFORMATION structure
  1728. Arguments:
  1729. UserData - Supplies the optional quota user data index entry.
  1730. LogCode - Supplies the Io Log code to use for the ErrorCode field.
  1731. FinalStauts - Supplies the final status of the operation.
  1732. Return Value:
  1733. True - if the event was successfully logged.
  1734. --*/
  1735. {
  1736. PEVENTLOG_ERROR_PACKET Packet;
  1737. ULONG OldCount;
  1738. UNICODE_STRING Label;
  1739. if (IrpContext->Vcb == NULL) {
  1740. return FALSE;
  1741. }
  1742. OldCount = InterlockedCompareExchange( &(NtfsData.VolumeNameLookupsInProgress), 1, 0 );
  1743. if (OldCount == 0) {
  1744. Packet = NtfsAllocatePoolWithTagNoRaise( PagedPool, sizeof( EVENTLOG_ERROR_PACKET ), MODULE_POOL_TAG );
  1745. if (Packet) {
  1746. RtlZeroMemory( Packet, sizeof( EVENTLOG_ERROR_PACKET ) );
  1747. //
  1748. // Copy UserData if necc. since the resolution is asynch
  1749. //
  1750. if (ARGUMENT_PRESENT( UserData )) {
  1751. ULONG SidLength;
  1752. ULONG UserDataLength;
  1753. SidLength = RtlLengthSid( &UserData->QuotaSid );
  1754. UserDataLength = SidLength +
  1755. SIZEOF_QUOTA_USER_DATA;
  1756. Packet->UserData = NtfsAllocatePoolWithTagNoRaise( PagedPool, UserDataLength, MODULE_POOL_TAG );
  1757. if (!Packet->UserData) {
  1758. NtfsFreePool( Packet );
  1759. return NtfsLogEventInternal( IrpContext->Vcb, IrpContext->MajorFunction, IrpContext->TransactionId, NULL, UserData, LogCode, FinalStatus );
  1760. }
  1761. RtlCopyMemory( Packet->UserData, UserData, UserDataLength );
  1762. }
  1763. Packet->FinalStatus = FinalStatus;
  1764. Packet->LogCode = LogCode;
  1765. Packet->MajorFunction = IrpContext->MajorFunction;
  1766. Packet->TransactionId = IrpContext->TransactionId;
  1767. Packet->Vcb = IrpContext->Vcb;
  1768. NtfsPostSpecial( IrpContext, IrpContext->Vcb, NtfsResolveVolumeAndLogEventSpecial, Packet );
  1769. return TRUE;
  1770. } else {
  1771. Label.Length = Label.MaximumLength = IrpContext->Vcb->Vpb->VolumeLabelLength;
  1772. Label.Buffer = &(IrpContext->Vcb->Vpb->VolumeLabel[0]);
  1773. return NtfsLogEventInternal( IrpContext->Vcb, IrpContext->MajorFunction, IrpContext->TransactionId, &Label, NULL, LogCode, FinalStatus );
  1774. }
  1775. } else {
  1776. Label.Length = Label.MaximumLength = IrpContext->Vcb->Vpb->VolumeLabelLength;
  1777. Label.Buffer = &(IrpContext->Vcb->Vpb->VolumeLabel[0]);
  1778. return NtfsLogEventInternal( IrpContext->Vcb, IrpContext->MajorFunction, IrpContext->TransactionId, &Label, NULL, LogCode, FinalStatus );
  1779. }
  1780. }
  1781. VOID
  1782. NtfsResolveVolumeAndLogEventSpecial (
  1783. IN PIRP_CONTEXT IrpContext,
  1784. IN OUT PVOID Context
  1785. )
  1786. /*++
  1787. Routine Description:
  1788. Resolve Vcb's win32 devicename and raise an io hard error. This is done in
  1789. a separate thread in order to have enough stack to re-enter the filesys if necc.
  1790. Also because we may reenter. Starting from here means we own no resources other than
  1791. having inc'ed the close count on the underlying vcb to prevent its going away
  1792. Arguments:
  1793. IrpContext - IrpContext containing vcb we're interested in
  1794. Context - String to append to volume win32 name
  1795. Return Value:
  1796. none
  1797. --*/
  1798. {
  1799. PEVENTLOG_ERROR_PACKET EventCtx = 0;
  1800. UNICODE_STRING VolumeName;
  1801. NTSTATUS Status;
  1802. WCHAR *NewBuffer = NULL;
  1803. ULONG DumpDataLength = 0;
  1804. ULONG LabelLength = 0;
  1805. BOOLEAN AllocatedVolName = FALSE;
  1806. UNREFERENCED_PARAMETER( IrpContext );
  1807. ASSERT( Context != NULL );
  1808. EventCtx = (PEVENTLOG_ERROR_PACKET) Context;
  1809. VolumeName.Length = 0;
  1810. VolumeName.Buffer = NULL;
  1811. try {
  1812. Status = IoVolumeDeviceToDosName( EventCtx->Vcb->TargetDeviceObject, &VolumeName );
  1813. ASSERT( (STATUS_SUCCESS == Status) || (VolumeName.Length == 0) );
  1814. //
  1815. // We're stuck using the label
  1816. //
  1817. if (VolumeName.Length == 0) {
  1818. VolumeName.Length = EventCtx->Vcb->Vpb->VolumeLabelLength;
  1819. VolumeName.Buffer = &(EventCtx->Vcb->Vpb->VolumeLabel[0]);
  1820. } else if (STATUS_SUCCESS == Status) {
  1821. AllocatedVolName = TRUE;
  1822. }
  1823. //
  1824. // Ignore status from LogEventInternal at this point if we fail
  1825. //
  1826. NtfsLogEventInternal( EventCtx->Vcb, EventCtx->MajorFunction, EventCtx->TransactionId, &VolumeName, EventCtx->UserData, EventCtx->LogCode, EventCtx->FinalStatus );
  1827. } finally {
  1828. //
  1829. // Indicate we're done and other lookups can occur
  1830. //
  1831. InterlockedDecrement( &(NtfsData.VolumeNameLookupsInProgress) );
  1832. if (EventCtx) {
  1833. if (EventCtx->UserData) {
  1834. NtfsFreePool( EventCtx->UserData );
  1835. }
  1836. NtfsFreePool( EventCtx );
  1837. }
  1838. if (AllocatedVolName) {
  1839. NtfsFreePool( VolumeName.Buffer );
  1840. }
  1841. }
  1842. }
  1843. VOID
  1844. NtfsPostVcbIsCorrupt (
  1845. IN PIRP_CONTEXT IrpContext,
  1846. IN NTSTATUS Status OPTIONAL,
  1847. IN PFILE_REFERENCE FileReference OPTIONAL,
  1848. IN PFCB Fcb OPTIONAL
  1849. )
  1850. /*++
  1851. Routine Description:
  1852. This routine is called to mark the volume dirty and possibly raise a hard error.
  1853. Arguments:
  1854. Status - If not zero, then this is the error code for the popup.
  1855. FileReference - If specified, then this is the file reference for the corrupt file.
  1856. Fcb - If specified, then this is the Fcb for the corrupt file.
  1857. Return Value:
  1858. None
  1859. --*/
  1860. {
  1861. PVCB Vcb = IrpContext->Vcb;
  1862. //
  1863. // Set this flag to keep the volume from ever getting set clean.
  1864. //
  1865. if (Vcb != NULL) {
  1866. NtfsMarkVolumeDirty( IrpContext, Vcb, TRUE );
  1867. //
  1868. // This would be the appropriate place to raise a hard error popup,
  1869. // ala the code in FastFat. We should do it after marking the volume
  1870. // dirty so that if anything goes wrong with the popup, the volume is
  1871. // already marked anyway.
  1872. //
  1873. if ((Status != 0) &&
  1874. !NtfsSuppressPopup &&
  1875. ((IrpContext->MajorFunction != IRP_MJ_FILE_SYSTEM_CONTROL) ||
  1876. (IrpContext->MinorFunction != IRP_MN_MOUNT_VOLUME))) {
  1877. NtfsRaiseInformationHardError( IrpContext,
  1878. Status,
  1879. FileReference,
  1880. Fcb );
  1881. }
  1882. }
  1883. }
  1884. VOID
  1885. NtfsMarkVolumeDirty (
  1886. IN PIRP_CONTEXT IrpContext,
  1887. IN PVCB Vcb,
  1888. IN BOOLEAN UpdateWithinTransaction
  1889. )
  1890. /*++
  1891. Routine Description:
  1892. This routine may be called any time the Mft is open to mark the volume
  1893. dirty.
  1894. Arguments:
  1895. Vcb - Vcb for volume to mark dirty
  1896. UpdateWithinTransaction - Use TRUE if it is safe to log this operation.
  1897. Return Value:
  1898. None
  1899. --*/
  1900. {
  1901. PAGED_CODE();
  1902. #if ((DBG || defined( NTFS_FREE_ASSERTS )) && !defined( LFS_CLUSTER_CHECK ))
  1903. KdPrint(("NTFS: Marking volume dirty, Vcb: %08lx\n", Vcb));
  1904. if (NtfsBreakOnCorrupt) {
  1905. KdPrint(("NTFS: Marking volume dirty\n", 0));
  1906. DbgBreakPoint();
  1907. }
  1908. #endif
  1909. //
  1910. // Return if the volume is already marked dirty. This also prevents
  1911. // endless recursion if the volume file itself is corrupt.
  1912. // Noop if the volume was mounted read only.
  1913. //
  1914. if (FlagOn(Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED_DIRTY) ||
  1915. (FlagOn( Vcb->VcbState, VCB_STATE_MOUNT_READ_ONLY ))) {
  1916. return;
  1917. }
  1918. SetFlag(Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED_DIRTY);
  1919. NtfsSetVolumeInfoFlagState( IrpContext,
  1920. Vcb,
  1921. VOLUME_DIRTY,
  1922. TRUE,
  1923. UpdateWithinTransaction );
  1924. //
  1925. // If this is chkdsk marking the volume dirty, let's not scare
  1926. // the user by putting a 'volume corrupt' message in the log.
  1927. // If an exception has occured, we want to log the event regardless.
  1928. //
  1929. if ((IrpContext->MajorFunction != IRP_MJ_FILE_SYSTEM_CONTROL) ||
  1930. (IrpContext->MinorFunction != IRP_MN_USER_FS_REQUEST) ||
  1931. (IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp )->Parameters.FileSystemControl.FsControlCode
  1932. != FSCTL_MARK_VOLUME_DIRTY) ||
  1933. (IrpContext->ExceptionStatus != 0)) {
  1934. NtfsLogEvent( IrpContext,
  1935. NULL,
  1936. IO_FILE_SYSTEM_CORRUPT_WITH_NAME,
  1937. STATUS_DISK_CORRUPT_ERROR );
  1938. }
  1939. }
  1940. VOID
  1941. NtfsSetVolumeInfoFlagState (
  1942. IN PIRP_CONTEXT IrpContext,
  1943. IN PVCB Vcb,
  1944. IN ULONG FlagsToSet,
  1945. IN BOOLEAN NewState,
  1946. IN BOOLEAN UpdateWithinTransaction
  1947. )
  1948. /*++
  1949. Routine Description:
  1950. This routine sets or clears one or more bits in the given vcb's
  1951. volume information.
  1952. Arguments:
  1953. Vcb - Vcb for volume.
  1954. FlagsToSet - The bit(s) to set or clear.
  1955. NewState - Use TRUE to set the given bit(s), or FALSE to clear them.
  1956. UpdateWithinTransaction - Use TRUE if this flag change should be done
  1957. inside a transaction.
  1958. Return Value:
  1959. None
  1960. --*/
  1961. {
  1962. LONGLONG Offset;
  1963. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  1964. PVOLUME_INFORMATION VolumeInformation;
  1965. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  1966. PATTRIBUTE_RECORD_HEADER Attribute;
  1967. ULONG RecordOffset;
  1968. ULONG AttributeOffset;
  1969. BOOLEAN CleanupAttributeContext = TRUE;
  1970. //
  1971. // If we don't have the VolumeDasdScb open yet, we can't do anything,
  1972. // so we need to exit gracefully now.
  1973. //
  1974. if ((Vcb == NULL) ||
  1975. (Vcb->VolumeDasdScb == NULL)) {
  1976. ASSERTMSG( "Attempting to set volume info flag state for a non-mounted volume", FALSE );
  1977. return;
  1978. }
  1979. NtfsInitializeAttributeContext( &AttributeContext );
  1980. try {
  1981. if (NtfsLookupAttributeByCode( IrpContext,
  1982. Vcb->VolumeDasdScb->Fcb,
  1983. &Vcb->VolumeDasdScb->Fcb->FileReference,
  1984. $VOLUME_INFORMATION,
  1985. &AttributeContext )) {
  1986. VolumeInformation =
  1987. (PVOLUME_INFORMATION)NtfsAttributeValue( NtfsFoundAttribute( &AttributeContext ));
  1988. NtfsPinMappedAttribute( IrpContext, Vcb, &AttributeContext );
  1989. //
  1990. // Extract the relevant pointers and calculate offsets.
  1991. //
  1992. FileRecord = NtfsContainingFileRecord(&AttributeContext);
  1993. Attribute = NtfsFoundAttribute(&AttributeContext);
  1994. Offset = PtrOffset(VolumeInformation, &VolumeInformation->VolumeFlags);
  1995. RecordOffset = PtrOffset(FileRecord, Attribute);
  1996. AttributeOffset = Attribute->Form.Resident.ValueOffset + (ULONG)Offset;
  1997. if (NewState) {
  1998. SetFlag( VolumeInformation->VolumeFlags, FlagsToSet );
  1999. } else {
  2000. ClearFlag( VolumeInformation->VolumeFlags, FlagsToSet );
  2001. }
  2002. if (UpdateWithinTransaction) {
  2003. //
  2004. // Log the change while we still have the old data.
  2005. //
  2006. FileRecord->Lsn =
  2007. NtfsWriteLog( IrpContext,
  2008. Vcb->MftScb,
  2009. NtfsFoundBcb(&AttributeContext),
  2010. UpdateResidentValue,
  2011. &(VolumeInformation->VolumeFlags),
  2012. sizeof(VolumeInformation->VolumeFlags),
  2013. UpdateResidentValue,
  2014. Add2Ptr(Attribute, Attribute->Form.Resident.ValueOffset + (ULONG)Offset),
  2015. sizeof(VolumeInformation->VolumeFlags),
  2016. NtfsMftOffset(&AttributeContext),
  2017. RecordOffset,
  2018. AttributeOffset,
  2019. Vcb->BytesPerFileRecordSegment );
  2020. }
  2021. //
  2022. // Now update this data by calling the same routine as restart.
  2023. //
  2024. NtfsRestartChangeValue( IrpContext,
  2025. FileRecord,
  2026. RecordOffset,
  2027. AttributeOffset,
  2028. &(VolumeInformation->VolumeFlags),
  2029. sizeof(VolumeInformation->VolumeFlags),
  2030. FALSE );
  2031. //
  2032. // If this is not a transaction then mark the page dirty and flush
  2033. // this to disk.
  2034. //
  2035. if (!UpdateWithinTransaction) {
  2036. LONGLONG MftOffset = NtfsMftOffset( &AttributeContext );
  2037. CcSetDirtyPinnedData( NtfsFoundBcb( &AttributeContext ), NULL );
  2038. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  2039. CleanupAttributeContext = FALSE;
  2040. CcFlushCache( &Vcb->MftScb->NonpagedScb->SegmentObject,
  2041. (PLARGE_INTEGER) &MftOffset,
  2042. Vcb->BytesPerFileRecordSegment,
  2043. NULL );
  2044. }
  2045. }
  2046. } finally {
  2047. if (CleanupAttributeContext) {
  2048. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  2049. }
  2050. }
  2051. }
  2052. BOOLEAN
  2053. NtfsUpdateVolumeInfo (
  2054. IN PIRP_CONTEXT IrpContext,
  2055. IN PVCB Vcb,
  2056. IN UCHAR DiskMajorVersion,
  2057. IN UCHAR DiskMinorVersion
  2058. )
  2059. /*++
  2060. Routine Description:
  2061. This routine is called to update the volume information on disk. This includes
  2062. version numbers, and last mounted version Disk versions are only updated if they
  2063. are greater than the on disk ones.
  2064. Arguments:
  2065. Vcb - Vcb for volume.
  2066. DiskMajorVersion - This is the Major Version number for the on disk format.
  2067. DiskMinorVersion - This is the Minor Version number for the on disk format.
  2068. Return Value:
  2069. TRUE if disk version was updated
  2070. --*/
  2071. {
  2072. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  2073. PVOLUME_INFORMATION VolumeInformation;
  2074. PATTRIBUTE_RECORD_HEADER Attribute;
  2075. VOLUME_INFORMATION NewVolumeInformation;
  2076. BOOLEAN UpdatedVersion = TRUE;
  2077. ULONG VolInfoSize;
  2078. PAGED_CODE();
  2079. NtfsInitializeAttributeContext( &AttributeContext );
  2080. try {
  2081. //
  2082. // Lookup the volume information attribute.
  2083. //
  2084. if (NtfsLookupAttributeByCode( IrpContext,
  2085. Vcb->VolumeDasdScb->Fcb,
  2086. &Vcb->VolumeDasdScb->Fcb->FileReference,
  2087. $VOLUME_INFORMATION,
  2088. &AttributeContext )) {
  2089. Attribute = NtfsFoundAttribute(&AttributeContext);
  2090. ASSERT( Attribute->FormCode == RESIDENT_FORM );
  2091. VolumeInformation =
  2092. (PVOLUME_INFORMATION)NtfsAttributeValue( NtfsFoundAttribute( &AttributeContext ));
  2093. NtfsPinMappedAttribute( IrpContext, Vcb, &AttributeContext );
  2094. RtlCopyMemory( &NewVolumeInformation, VolumeInformation, Attribute->Form.Resident.ValueLength );
  2095. if (NewVolumeInformation.MajorVersion < DiskMajorVersion) {
  2096. NewVolumeInformation.MajorVersion = DiskMajorVersion;
  2097. NewVolumeInformation.MinorVersion = DiskMinorVersion;
  2098. Vcb->MajorVersion = DiskMajorVersion;
  2099. Vcb->MinorVersion = DiskMinorVersion;
  2100. } else if (NewVolumeInformation.MinorVersion < DiskMinorVersion) {
  2101. NewVolumeInformation.MinorVersion = DiskMinorVersion;
  2102. Vcb->MinorVersion = DiskMinorVersion;
  2103. } else {
  2104. UpdatedVersion = FALSE;
  2105. }
  2106. //
  2107. // We can use the new volinfo for version 4 and greater
  2108. //
  2109. if (DiskMajorVersion > 3) {
  2110. #ifdef BENL_DBG
  2111. KdPrint(( "NTFS: new volinfo for version 4+\n" ));
  2112. #endif
  2113. NewVolumeInformation.LastMountedMajorVersion = DiskMajorVersion;
  2114. NewVolumeInformation.LastMountedMinorVersion = DiskMinorVersion;
  2115. VolInfoSize = sizeof( VOLUME_INFORMATION );
  2116. UpdatedVersion = TRUE;
  2117. } else {
  2118. VolInfoSize = FIELD_OFFSET( VOLUME_INFORMATION, LastMountedMajorVersion );
  2119. }
  2120. if (UpdatedVersion) {
  2121. NtfsChangeAttributeValue( IrpContext, Vcb->VolumeDasdScb->Fcb, 0, &NewVolumeInformation, VolInfoSize, TRUE, FALSE, FALSE, TRUE, &AttributeContext );
  2122. }
  2123. }
  2124. } finally {
  2125. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  2126. }
  2127. return UpdatedVersion;
  2128. }
  2129. //
  2130. // Local support routine
  2131. //
  2132. NTSTATUS
  2133. NtfsVerifyReadCompletionRoutine(
  2134. IN PDEVICE_OBJECT DeviceObject,
  2135. IN PIRP Irp,
  2136. IN PVOID Contxt
  2137. )
  2138. {
  2139. //
  2140. // Set the event so that our call will wake up.
  2141. //
  2142. KeSetEvent( (PKEVENT)Contxt, 0, FALSE );
  2143. UNREFERENCED_PARAMETER( DeviceObject );
  2144. UNREFERENCED_PARAMETER( Irp );
  2145. //
  2146. // If we change this return value then NtfsIoCallSelf needs to reference the
  2147. // file object.
  2148. //
  2149. return STATUS_MORE_PROCESSING_REQUIRED;
  2150. }