Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1035 lines
30 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. cmworker.c
  5. Abstract:
  6. This module contains support for the worker thread of the registry.
  7. The worker thread (actually an executive worker thread is used) is
  8. required for operations that must take place in the context of the
  9. system process. (particularly file I/O)
  10. Author:
  11. John Vert (jvert) 21-Oct-1992
  12. Revision History:
  13. --*/
  14. #include "cmp.h"
  15. extern LIST_ENTRY CmpHiveListHead;
  16. VOID
  17. CmpInitializeHiveList(
  18. VOID
  19. );
  20. //
  21. // ----- LAZY FLUSH CONTROL -----
  22. //
  23. // LAZY_FLUSH_INTERVAL_IN_SECONDS controls how many seconds will elapse
  24. // between when the hive is marked dirty and when the lazy flush worker
  25. // thread is queued to write the data to disk.
  26. //
  27. ULONG CmpLazyFlushIntervalInSeconds = 5;
  28. //
  29. // number of hive flushed at one time (default to all system hive + 2 = current logged on user hives)
  30. //
  31. ULONG CmpLazyFlushHiveCount = 7;
  32. //
  33. // LAZY_FLUSH_TIMEOUT_IN_SECONDS controls how long the lazy flush worker
  34. // thread will wait for the registry lock before giving up and queueing
  35. // the lazy flush timer again.
  36. //
  37. #define LAZY_FLUSH_TIMEOUT_IN_SECONDS 1
  38. #define SECOND_MULT 10*1000*1000 // 10->mic, 1000->mil, 1000->second
  39. PKPROCESS CmpSystemProcess;
  40. KTIMER CmpLazyFlushTimer;
  41. KDPC CmpLazyFlushDpc;
  42. WORK_QUEUE_ITEM CmpLazyWorkItem;
  43. BOOLEAN CmpLazyFlushPending = FALSE;
  44. BOOLEAN CmpForceForceFlush = FALSE;
  45. BOOLEAN CmpHoldLazyFlush = TRUE;
  46. BOOLEAN CmpDontGrowLogFile = FALSE;
  47. extern BOOLEAN CmpNoWrite;
  48. extern BOOLEAN CmpWasSetupBoot;
  49. extern BOOLEAN HvShutdownComplete;
  50. extern BOOLEAN CmpProfileLoaded;
  51. //
  52. // Indicate whether the "disk full" popup has been triggered yet or not.
  53. //
  54. extern BOOLEAN CmpDiskFullWorkerPopupDisplayed;
  55. //
  56. // set to true if disk full when trying to save the changes made between system hive loading and registry initalization
  57. //
  58. extern BOOLEAN CmpCannotWriteConfiguration;
  59. extern UNICODE_STRING SystemHiveFullPathName;
  60. extern HIVE_LIST_ENTRY CmpMachineHiveList[];
  61. extern BOOLEAN CmpTrackHiveClose;
  62. #if DBG
  63. PKTHREAD CmpCallerThread = NULL;
  64. #endif
  65. #ifdef CMP_STATS
  66. #define KCB_STAT_INTERVAL_IN_SECONDS 120 // 2 min.
  67. extern struct {
  68. ULONG CmpMaxKcbNo;
  69. ULONG CmpKcbNo;
  70. ULONG CmpStatNo;
  71. ULONG CmpNtCreateKeyNo;
  72. ULONG CmpNtDeleteKeyNo;
  73. ULONG CmpNtDeleteValueKeyNo;
  74. ULONG CmpNtEnumerateKeyNo;
  75. ULONG CmpNtEnumerateValueKeyNo;
  76. ULONG CmpNtFlushKeyNo;
  77. ULONG CmpNtNotifyChangeMultipleKeysNo;
  78. ULONG CmpNtOpenKeyNo;
  79. ULONG CmpNtQueryKeyNo;
  80. ULONG CmpNtQueryValueKeyNo;
  81. ULONG CmpNtQueryMultipleValueKeyNo;
  82. ULONG CmpNtRestoreKeyNo;
  83. ULONG CmpNtSaveKeyNo;
  84. ULONG CmpNtSaveMergedKeysNo;
  85. ULONG CmpNtSetValueKeyNo;
  86. ULONG CmpNtLoadKeyNo;
  87. ULONG CmpNtUnloadKeyNo;
  88. ULONG CmpNtSetInformationKeyNo;
  89. ULONG CmpNtReplaceKeyNo;
  90. ULONG CmpNtQueryOpenSubKeysNo;
  91. } CmpStatsDebug;
  92. KTIMER CmpKcbStatTimer;
  93. KDPC CmpKcbStatDpc;
  94. KSPIN_LOCK CmpKcbStatLock;
  95. BOOLEAN CmpKcbStatShutdown;
  96. VOID
  97. CmpKcbStatDpcRoutine(
  98. IN PKDPC Dpc,
  99. IN PVOID DeferredContext,
  100. IN PVOID SystemArgument1,
  101. IN PVOID SystemArgument2
  102. );
  103. extern ULONG CmpNtFakeCreate;
  104. struct {
  105. ULONG BasicInformation;
  106. UINT64 BasicInformationTimeCounter;
  107. UINT64 BasicInformationTimeElapsed;
  108. ULONG NodeInformation;
  109. UINT64 NodeInformationTimeCounter;
  110. UINT64 NodeInformationTimeElapsed;
  111. ULONG FullInformation;
  112. UINT64 FullInformationTimeCounter;
  113. UINT64 FullInformationTimeElapsed;
  114. ULONG EnumerateKeyBasicInformation;
  115. UINT64 EnumerateKeyBasicInformationTimeCounter;
  116. UINT64 EnumerateKeyBasicInformationTimeElapsed;
  117. ULONG EnumerateKeyNodeInformation;
  118. UINT64 EnumerateKeyNodeInformationTimeCounter;
  119. UINT64 EnumerateKeyNodeInformationTimeElapsed;
  120. ULONG EnumerateKeyFullInformation;
  121. UINT64 EnumerateKeyFullInformationTimeCounter;
  122. UINT64 EnumerateKeyFullInformationTimeElapsed;
  123. } CmpQueryKeyDataDebug = {0};
  124. #endif
  125. VOID
  126. CmpLazyFlushWorker(
  127. IN PVOID Parameter
  128. );
  129. VOID
  130. CmpLazyFlushDpcRoutine(
  131. IN PKDPC Dpc,
  132. IN PVOID DeferredContext,
  133. IN PVOID SystemArgument1,
  134. IN PVOID SystemArgument2
  135. );
  136. VOID
  137. CmpDiskFullWarningWorker(
  138. IN PVOID WorkItem
  139. );
  140. VOID
  141. CmpDiskFullWarning(
  142. VOID
  143. );
  144. BOOLEAN
  145. CmpDoFlushNextHive(
  146. BOOLEAN ForceFlush,
  147. PBOOLEAN PostWarning,
  148. PULONG DirtyCount
  149. );
  150. #ifdef ALLOC_PRAGMA
  151. #pragma alloc_text(PAGE,CmpLazyFlush)
  152. #pragma alloc_text(PAGE,CmpLazyFlushWorker)
  153. #pragma alloc_text(PAGE,CmpDiskFullWarningWorker)
  154. #pragma alloc_text(PAGE,CmpDiskFullWarning)
  155. #pragma alloc_text(PAGE,CmpCmdHiveClose)
  156. #pragma alloc_text(PAGE,CmpCmdInit)
  157. #pragma alloc_text(PAGE,CmpCmdRenameHive)
  158. #pragma alloc_text(PAGE,CmpCmdHiveOpen)
  159. #pragma alloc_text(PAGE,CmSetLazyFlushState)
  160. #ifndef CMP_STATS
  161. #pragma alloc_text(PAGE,CmpShutdownWorkers)
  162. #endif
  163. #endif
  164. VOID
  165. CmpCmdHiveClose(
  166. PCMHIVE CmHive
  167. )
  168. /*++
  169. Routine Description:
  170. Closes all the file handles for the specified hive
  171. Arguments:
  172. CmHive - the hive to close
  173. Return Value:
  174. none
  175. --*/
  176. {
  177. ULONG i;
  178. IO_STATUS_BLOCK IoStatusBlock;
  179. FILE_BASIC_INFORMATION BasicInfo;
  180. LARGE_INTEGER systemtime;
  181. BOOLEAN oldFlag;
  182. PAGED_CODE();
  183. //
  184. // disable hard error popups, to workaround ObAttachProcessStack
  185. //
  186. oldFlag = IoSetThreadHardErrorMode(FALSE);
  187. //
  188. // Close the files associated with this hive.
  189. //
  190. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  191. for (i=0; i<HFILE_TYPE_MAX; i++) {
  192. if (CmHive->FileHandles[i] != NULL) {
  193. //
  194. // attempt to set change the last write time (profile guys are relying on it!)
  195. //
  196. if( i == HFILE_TYPE_PRIMARY ) {
  197. if( NT_SUCCESS(ZwQueryInformationFile(
  198. CmHive->FileHandles[i],
  199. &IoStatusBlock,
  200. &BasicInfo,
  201. sizeof(BasicInfo),
  202. FileBasicInformation) ) ) {
  203. KeQuerySystemTime(&systemtime);
  204. BasicInfo.LastWriteTime = systemtime;
  205. BasicInfo.LastAccessTime = systemtime;
  206. ZwSetInformationFile(
  207. CmHive->FileHandles[i],
  208. &IoStatusBlock,
  209. &BasicInfo,
  210. sizeof(BasicInfo),
  211. FileBasicInformation
  212. );
  213. }
  214. CmpTrackHiveClose = TRUE;
  215. CmCloseHandle(CmHive->FileHandles[i]);
  216. CmpTrackHiveClose = FALSE;
  217. } else {
  218. CmCloseHandle(CmHive->FileHandles[i]);
  219. }
  220. CmHive->FileHandles[i] = NULL;
  221. }
  222. }
  223. //
  224. // restore hard error popups mode
  225. //
  226. IoSetThreadHardErrorMode(oldFlag);
  227. }
  228. VOID
  229. CmpCmdInit(
  230. BOOLEAN SetupBoot
  231. )
  232. /*++
  233. Routine Description:
  234. Initializes cm globals and flushes all hives to the disk.
  235. Arguments:
  236. SetupBoot - whether the boot is from setup or a regular boot
  237. Return Value:
  238. none
  239. --*/
  240. {
  241. PAGED_CODE();
  242. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  243. //
  244. // Initialize lazy flush timer and DPC
  245. //
  246. KeInitializeDpc(&CmpLazyFlushDpc,
  247. CmpLazyFlushDpcRoutine,
  248. NULL);
  249. KeInitializeTimer(&CmpLazyFlushTimer);
  250. ExInitializeWorkItem(&CmpLazyWorkItem, CmpLazyFlushWorker, NULL);
  251. #ifdef CMP_STATS
  252. KeInitializeDpc(&CmpKcbStatDpc,
  253. CmpKcbStatDpcRoutine,
  254. NULL);
  255. KeInitializeTimer(&CmpKcbStatTimer);
  256. KeInitializeSpinLock(&CmpKcbStatLock);
  257. CmpKcbStatShutdown = FALSE;
  258. #endif
  259. CmpNoWrite = CmpMiniNTBoot;
  260. CmpWasSetupBoot = SetupBoot;
  261. if (SetupBoot == FALSE) {
  262. CmpInitializeHiveList();
  263. }
  264. //
  265. // Since we are done with initialization,
  266. // disable the hive sharing
  267. //
  268. if (CmpMiniNTBoot && CmpShareSystemHives) {
  269. CmpShareSystemHives = FALSE;
  270. }
  271. #ifdef CMP_STATS
  272. CmpKcbStat();
  273. #endif
  274. }
  275. NTSTATUS
  276. CmpCmdRenameHive(
  277. PCMHIVE CmHive,
  278. POBJECT_NAME_INFORMATION OldName,
  279. PUNICODE_STRING NewName,
  280. ULONG NameInfoLength
  281. )
  282. /*++
  283. Routine Description:
  284. rename a cmhive's primary handle
  285. replaces old REG_CMD_RENAME_HIVE worker case
  286. Arguments:
  287. CmHive - hive to rename
  288. OldName - old name information
  289. NewName - the new name for the file
  290. NameInfoLength - sizeof name information structure
  291. Return Value:
  292. <TBD>
  293. --*/
  294. {
  295. NTSTATUS Status;
  296. HANDLE Handle;
  297. PFILE_RENAME_INFORMATION RenameInfo;
  298. IO_STATUS_BLOCK IoStatusBlock;
  299. PAGED_CODE();
  300. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  301. //
  302. // Rename a CmHive's primary handle
  303. //
  304. Handle = CmHive->FileHandles[HFILE_TYPE_PRIMARY];
  305. if (OldName != NULL) {
  306. ASSERT_PASSIVE_LEVEL();
  307. Status = ZwQueryObject(Handle,
  308. ObjectNameInformation,
  309. OldName,
  310. NameInfoLength,
  311. &NameInfoLength);
  312. if (!NT_SUCCESS(Status)) {
  313. return Status;
  314. }
  315. }
  316. RenameInfo = ExAllocatePool(PagedPool,
  317. sizeof(FILE_RENAME_INFORMATION) + NewName->Length);
  318. if (RenameInfo == NULL) {
  319. return STATUS_INSUFFICIENT_RESOURCES;
  320. }
  321. RenameInfo->ReplaceIfExists = FALSE;
  322. RenameInfo->RootDirectory = NULL;
  323. RenameInfo->FileNameLength = NewName->Length;
  324. RtlCopyMemory(RenameInfo->FileName,
  325. NewName->Buffer,
  326. NewName->Length);
  327. Status = ZwSetInformationFile(Handle,
  328. &IoStatusBlock,
  329. (PVOID)RenameInfo,
  330. sizeof(FILE_RENAME_INFORMATION) +
  331. NewName->Length,
  332. FileRenameInformation);
  333. ExFreePool(RenameInfo);
  334. return Status;
  335. }
  336. NTSTATUS
  337. CmpCmdHiveOpen(
  338. POBJECT_ATTRIBUTES FileAttributes,
  339. PSECURITY_CLIENT_CONTEXT ImpersonationContext,
  340. PBOOLEAN Allocate,
  341. PBOOLEAN RegistryLockAquired, // needed to avoid recursivity deadlock with ZwCreate calls calling back into registry
  342. PCMHIVE *NewHive,
  343. ULONG CheckFlags
  344. )
  345. /*++
  346. Routine Description:
  347. replaces old REG_CMD_HIVE_OPEN worker case
  348. Arguments:
  349. Return Value:
  350. <TBD>
  351. --*/
  352. {
  353. PUNICODE_STRING FileName;
  354. NTSTATUS Status;
  355. HANDLE NullHandle;
  356. PAGED_CODE();
  357. //
  358. // Open the file.
  359. //
  360. FileName = FileAttributes->ObjectName;
  361. Status = CmpInitHiveFromFile(FileName,
  362. 0,
  363. NewHive,
  364. Allocate,
  365. RegistryLockAquired,
  366. CheckFlags);
  367. //
  368. // NT Servers will return STATUS_ACCESS_DENIED. Netware 3.1x
  369. // servers could return any of the other error codes if the GUEST
  370. // account is disabled.
  371. //
  372. if (((Status == STATUS_ACCESS_DENIED) ||
  373. (Status == STATUS_NO_SUCH_USER) ||
  374. (Status == STATUS_WRONG_PASSWORD) ||
  375. (Status == STATUS_ACCOUNT_EXPIRED) ||
  376. (Status == STATUS_ACCOUNT_DISABLED) ||
  377. (Status == STATUS_ACCOUNT_RESTRICTION)) &&
  378. (ImpersonationContext != NULL)) {
  379. //
  380. // Impersonate the caller and try it again. This
  381. // lets us open hives on a remote machine.
  382. //
  383. Status = SeImpersonateClientEx(
  384. ImpersonationContext,
  385. NULL);
  386. if ( NT_SUCCESS( Status ) ) {
  387. Status = CmpInitHiveFromFile(FileName,
  388. 0,
  389. NewHive,
  390. Allocate,
  391. RegistryLockAquired,
  392. CheckFlags);
  393. NullHandle = NULL;
  394. PsRevertToSelf();
  395. }
  396. }
  397. return Status;
  398. }
  399. VOID
  400. CmpLazyFlush(
  401. VOID
  402. )
  403. /*++
  404. Routine Description:
  405. This routine resets the registry timer to go off at a specified interval
  406. in the future (LAZY_FLUSH_INTERVAL_IN_SECONDS).
  407. Arguments:
  408. None
  409. Return Value:
  410. None.
  411. --*/
  412. {
  413. LARGE_INTEGER DueTime;
  414. PAGED_CODE();
  415. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"CmpLazyFlush: setting lazy flush timer\n"));
  416. if ((!CmpNoWrite) && (!CmpHoldLazyFlush)) {
  417. DueTime.QuadPart = Int32x32To64(CmpLazyFlushIntervalInSeconds,
  418. - SECOND_MULT);
  419. //
  420. // Indicate relative time
  421. //
  422. KeSetTimer(&CmpLazyFlushTimer,
  423. DueTime,
  424. &CmpLazyFlushDpc);
  425. }
  426. }
  427. VOID
  428. CmpLazyFlushDpcRoutine(
  429. IN PKDPC Dpc,
  430. IN PVOID DeferredContext,
  431. IN PVOID SystemArgument1,
  432. IN PVOID SystemArgument2
  433. )
  434. /*++
  435. Routine Description:
  436. This is the DPC routine triggered by the lazy flush timer. All it does
  437. is queue a work item to an executive worker thread. The work item will
  438. do the actual lazy flush to disk.
  439. Arguments:
  440. Dpc - Supplies a pointer to the DPC object.
  441. DeferredContext - not used
  442. SystemArgument1 - not used
  443. SystemArgument2 - not used
  444. Return Value:
  445. None.
  446. --*/
  447. {
  448. UNREFERENCED_PARAMETER (Dpc);
  449. UNREFERENCED_PARAMETER (DeferredContext);
  450. UNREFERENCED_PARAMETER (SystemArgument1);
  451. UNREFERENCED_PARAMETER (SystemArgument2);
  452. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"CmpLazyFlushDpc: queuing lazy flush work item\n"));
  453. if ((!CmpLazyFlushPending) && (!CmpHoldLazyFlush)) {
  454. CmpLazyFlushPending = TRUE;
  455. ExQueueWorkItem(&CmpLazyWorkItem, DelayedWorkQueue);
  456. }
  457. }
  458. /*
  459. #define LAZY_FLUSH_CAPTURE_SLOTS 5000
  460. typedef struct {
  461. LARGE_INTEGER SystemTime;
  462. ULONG ElapsedMSec;
  463. } CM_LAZY_FLUSH_DATA;
  464. ULONG CmpLazyFlushCapturedDataCount = 0;
  465. CM_LAZY_FLUSH_DATA CmpLazyFlushCapturedData[LAZY_FLUSH_CAPTURE_SLOTS] = {0};
  466. BOOLEAN CmpCaptureLazyFlushData = FALSE;
  467. */
  468. ULONG CmpLazyFlushCount = 1;
  469. VOID
  470. CmpLazyFlushWorker(
  471. IN PVOID Parameter
  472. )
  473. /*++
  474. Routine Description:
  475. Worker routine called to do a lazy flush. Called by an executive worker
  476. thread in the system process.
  477. Arguments:
  478. Parameter - not used.
  479. Return Value:
  480. None.
  481. --*/
  482. {
  483. BOOLEAN Result = TRUE;
  484. BOOLEAN ForceFlush;
  485. BOOLEAN PostNewWorker = FALSE;
  486. ULONG DirtyCount = 0;
  487. PAGED_CODE();
  488. UNREFERENCED_PARAMETER (Parameter);
  489. if( CmpHoldLazyFlush ) {
  490. //
  491. // lazy flush mode is disabled
  492. //
  493. return;
  494. }
  495. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"CmpLazyFlushWorker: flushing hives\n"));
  496. ForceFlush = CmpForceForceFlush;
  497. if(ForceFlush == TRUE) {
  498. //
  499. // something bad happened and we may need to fix hive's use count
  500. //
  501. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"CmpLazyFlushWorker: Force Flush - getting the reglock exclusive\n"));
  502. CmpLockRegistryExclusive();
  503. } else {
  504. CmpLockRegistry();
  505. ENTER_FLUSH_MODE();
  506. }
  507. if (!HvShutdownComplete) {
  508. //
  509. // this call will set CmpForceForceFlush to the right value
  510. //
  511. //Result = CmpDoFlushAll(ForceFlush);
  512. /*
  513. if( CmpCaptureLazyFlushData && (CmpLazyFlushCapturedDataCount < LAZY_FLUSH_CAPTURE_SLOTS) ) {
  514. KeQuerySystemTime( &(CmpLazyFlushCapturedData[CmpLazyFlushCapturedDataCount].SystemTime) );
  515. }
  516. */
  517. PostNewWorker = CmpDoFlushNextHive(ForceFlush,&Result,&DirtyCount);
  518. /*
  519. if( CmpCaptureLazyFlushData && (CmpLazyFlushCapturedDataCount < LAZY_FLUSH_CAPTURE_SLOTS) ) {
  520. LARGE_INTEGER ElapsedTime;
  521. KeQuerySystemTime( &ElapsedTime );
  522. ElapsedTime.QuadPart -= CmpLazyFlushCapturedData[CmpLazyFlushCapturedDataCount].SystemTime.QuadPart;
  523. CmpLazyFlushCapturedData[CmpLazyFlushCapturedDataCount].ElapsedMSec = (ULONG)((LONGLONG)(ElapsedTime.QuadPart / 10000));
  524. CmpLazyFlushCapturedDataCount++;
  525. }
  526. */
  527. if( !PostNewWorker ) {
  528. //
  529. // we have completed a sweep through the entire list of hives
  530. //
  531. InterlockedIncrement( (PLONG)&CmpLazyFlushCount );
  532. }
  533. } else {
  534. CmpForceForceFlush = FALSE;
  535. }
  536. if( ForceFlush == FALSE ) {
  537. EXIT_FLUSH_MODE();
  538. }
  539. CmpLazyFlushPending = FALSE;
  540. CmpUnlockRegistry();
  541. if( CmpCannotWriteConfiguration ) {
  542. //
  543. // Disk full; system hive has not been saved at initialization
  544. //
  545. if(!Result) {
  546. //
  547. // All hives were saved; No need for disk full warning anymore
  548. //
  549. CmpCannotWriteConfiguration = FALSE;
  550. } else {
  551. //
  552. // Issue another hard error (if not already displayed) and postpone a lazy flush operation
  553. //
  554. CmpDiskFullWarning();
  555. CmpLazyFlush();
  556. }
  557. }
  558. //
  559. // if we have not yet flushed the whole list; or there are still hives dirty from the curently ended iteration.
  560. //
  561. if( PostNewWorker || (DirtyCount != 0) ) {
  562. //
  563. // post a new worker to flush the next hive
  564. //
  565. CmpLazyFlush();
  566. }
  567. }
  568. VOID
  569. CmpDiskFullWarningWorker(
  570. IN PVOID WorkItem
  571. )
  572. /*++
  573. Routine Description:
  574. Displays hard error popup that indicates the disk is full.
  575. Arguments:
  576. WorkItem - Supplies pointer to the work item. This routine will
  577. free the work item.
  578. Return Value:
  579. None.
  580. --*/
  581. {
  582. NTSTATUS Status;
  583. ULONG Response;
  584. ExFreePool(WorkItem);
  585. Status = ExRaiseHardError(STATUS_DISK_FULL,
  586. 0,
  587. 0,
  588. NULL,
  589. OptionOk,
  590. &Response);
  591. }
  592. VOID
  593. CmpDiskFullWarning(
  594. VOID
  595. )
  596. /*++
  597. Routine Description:
  598. Raises a hard error of type STATUS_DISK_FULL if wasn't already raised
  599. Arguments:
  600. None
  601. Return Value:
  602. None
  603. --*/
  604. {
  605. PWORK_QUEUE_ITEM WorkItem;
  606. if( (!CmpDiskFullWorkerPopupDisplayed) && (CmpCannotWriteConfiguration) && (ExReadyForErrors) && (CmpProfileLoaded) ) {
  607. //
  608. // Queue work item to display popup
  609. //
  610. WorkItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
  611. if (WorkItem != NULL) {
  612. CmpDiskFullWorkerPopupDisplayed = TRUE;
  613. ExInitializeWorkItem(WorkItem,
  614. CmpDiskFullWarningWorker,
  615. WorkItem);
  616. ExQueueWorkItem(WorkItem, DelayedWorkQueue);
  617. }
  618. }
  619. }
  620. VOID
  621. CmpShutdownWorkers(
  622. VOID
  623. )
  624. /*++
  625. Routine Description:
  626. Shuts down the lazy flush worker (by killing the timer)
  627. Arguments:
  628. None
  629. Return Value:
  630. None
  631. --*/
  632. {
  633. PAGED_CODE();
  634. KeCancelTimer(&CmpLazyFlushTimer);
  635. #ifdef CMP_STATS
  636. {
  637. KIRQL OldIrql;
  638. KeAcquireSpinLock(&CmpKcbStatLock, &OldIrql);
  639. CmpKcbStatShutdown = TRUE;
  640. KeCancelTimer(&CmpKcbStatTimer);
  641. KeReleaseSpinLock(&CmpKcbStatLock, OldIrql);
  642. }
  643. #endif
  644. }
  645. VOID
  646. CmSetLazyFlushState(BOOLEAN Enable)
  647. /*++
  648. Routine Description:
  649. Enables/Disables the lazy flusher; Designed for the standby/resume case, where
  650. we we don't want the lazy flush to fire off, blocking registry writers until the
  651. disk wakes up.
  652. Arguments:
  653. Enable - TRUE = enable; FALSE = disable
  654. Return Value:
  655. None.
  656. --*/
  657. {
  658. PAGED_CODE();
  659. CmpDontGrowLogFile = CmpHoldLazyFlush = !Enable;
  660. }
  661. #ifdef CMP_STATS
  662. VOID
  663. CmpKcbStat(
  664. VOID
  665. )
  666. /*++
  667. Routine Description:
  668. This routine resets the KcbStat timer to go off at a specified interval
  669. in the future
  670. Arguments:
  671. None
  672. Return Value:
  673. None.
  674. --*/
  675. {
  676. LARGE_INTEGER DueTime;
  677. KIRQL OldIrql;
  678. DueTime.QuadPart = Int32x32To64(KCB_STAT_INTERVAL_IN_SECONDS,
  679. - SECOND_MULT);
  680. //
  681. // Indicate relative time
  682. //
  683. KeAcquireSpinLock(&CmpKcbStatLock, &OldIrql);
  684. if (! CmpKcbStatShutdown) {
  685. KeSetTimer(&CmpKcbStatTimer,
  686. DueTime,
  687. &CmpKcbStatDpc);
  688. }
  689. KeReleaseSpinLock(&CmpKcbStatLock, OldIrql);
  690. }
  691. VOID
  692. CmpKcbStatDpcRoutine(
  693. IN PKDPC Dpc,
  694. IN PVOID DeferredContext,
  695. IN PVOID SystemArgument1,
  696. IN PVOID SystemArgument2
  697. )
  698. /*++
  699. Routine Description:
  700. Dumps the kcb stats in the debugger and then reschedules another
  701. Dpc in the future
  702. Arguments:
  703. Dpc - Supplies a pointer to the DPC object.
  704. DeferredContext - not used
  705. SystemArgument1 - not used
  706. SystemArgument2 - not used
  707. Return Value:
  708. None.
  709. --*/
  710. {
  711. #ifndef _CM_LDR_
  712. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"\n*********************************************************************\n");
  713. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* Stat No %8lu KcbNo = %8lu [MaxKcbNo = %8lu] *\n",++CmpStatsDebug.CmpStatNo,CmpStatsDebug.CmpKcbNo,CmpStatsDebug.CmpMaxKcbNo);
  714. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*********************************************************************\n");
  715. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* *\n");
  716. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* [Nt]API [No. Of]Calls *\n");
  717. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n");
  718. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtCreateKey %8lu Opens = %8lu *\n",CmpStatsDebug.CmpNtCreateKeyNo,CmpNtFakeCreate);
  719. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtOpenKey %8lu *\n",CmpStatsDebug.CmpNtOpenKeyNo);
  720. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtEnumerateKey %8lu *\n",CmpStatsDebug.CmpNtEnumerateKeyNo);
  721. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryKey %8lu *\n",CmpStatsDebug.CmpNtQueryKeyNo);
  722. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtDeleteKey %8lu *\n",CmpStatsDebug.CmpNtDeleteKeyNo);
  723. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtSetInformationKey %8lu *\n",CmpStatsDebug.CmpNtSetInformationKeyNo);
  724. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n");
  725. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtSetValueKey %8lu *\n",CmpStatsDebug.CmpNtSetValueKeyNo);
  726. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtEnumerateValueKey %8lu *\n",CmpStatsDebug.CmpNtEnumerateValueKeyNo);
  727. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryValueKey %8lu *\n",CmpStatsDebug.CmpNtQueryValueKeyNo);
  728. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryMultipleValueKey %8lu *\n",CmpStatsDebug.CmpNtQueryMultipleValueKeyNo);
  729. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtDeleteValueKey %8lu *\n",CmpStatsDebug.CmpNtDeleteValueKeyNo);
  730. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n");
  731. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtFlushKey %8lu *\n",CmpStatsDebug.CmpNtFlushKeyNo);
  732. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtLoadKey %8lu *\n",CmpStatsDebug.CmpNtLoadKeyNo);
  733. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtUnloadKey %8lu *\n",CmpStatsDebug.CmpNtUnloadKeyNo);
  734. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtSaveKey %8lu *\n",CmpStatsDebug.CmpNtSaveKeyNo);
  735. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtSaveMergedKeys %8lu *\n",CmpStatsDebug.CmpNtSaveMergedKeysNo);
  736. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtRestoreKey %8lu *\n",CmpStatsDebug.CmpNtRestoreKeyNo);
  737. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtReplaceKey %8lu *\n",CmpStatsDebug.CmpNtReplaceKeyNo);
  738. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n");
  739. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtNotifyChgMultplKeys %8lu *\n",CmpStatsDebug.CmpNtNotifyChangeMultipleKeysNo);
  740. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryOpenSubKeys %8lu *\n",CmpStatsDebug.CmpNtQueryOpenSubKeysNo);
  741. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n");
  742. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* [No.Of]Calls [Time] *\n");
  743. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n");
  744. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryKey(KeyBasicInformation) %8lu %8lu *\n",
  745. CmpQueryKeyDataDebug.BasicInformation,
  746. (ULONG)(CmpQueryKeyDataDebug.BasicInformationTimeCounter?CmpQueryKeyDataDebug.BasicInformationTimeElapsed/CmpQueryKeyDataDebug.BasicInformationTimeCounter:0));
  747. CmpQueryKeyDataDebug.BasicInformationTimeCounter = 0;
  748. CmpQueryKeyDataDebug.BasicInformationTimeElapsed = 0;
  749. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryKey(KeyNodeInformation ) %8lu %8lu *\n",
  750. CmpQueryKeyDataDebug.NodeInformation,
  751. (ULONG)(CmpQueryKeyDataDebug.NodeInformationTimeCounter?CmpQueryKeyDataDebug.NodeInformationTimeElapsed/CmpQueryKeyDataDebug.NodeInformationTimeCounter:0));
  752. CmpQueryKeyDataDebug.NodeInformationTimeCounter = 0;
  753. CmpQueryKeyDataDebug.NodeInformationTimeElapsed = 0;
  754. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryKey(KeyFullInformation ) %8lu %8lu *\n",
  755. CmpQueryKeyDataDebug.FullInformation,
  756. (ULONG)(CmpQueryKeyDataDebug.FullInformationTimeCounter?CmpQueryKeyDataDebug.FullInformationTimeElapsed/CmpQueryKeyDataDebug.FullInformationTimeCounter:0));
  757. CmpQueryKeyDataDebug.FullInformationTimeCounter = 0;
  758. CmpQueryKeyDataDebug.FullInformationTimeElapsed = 0;
  759. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtEnumerateKey(KeyBasicInformation) %8lu %8lu *\n",
  760. CmpQueryKeyDataDebug.EnumerateKeyBasicInformation,
  761. (ULONG)(CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeCounter?CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeElapsed/CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeCounter:0));
  762. CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeCounter = 0;
  763. CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeElapsed = 0;
  764. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtEnumerateKey(KeyNodeInformation ) %8lu %8lu *\n",
  765. CmpQueryKeyDataDebug.EnumerateKeyNodeInformation,
  766. (ULONG)(CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeCounter?CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeElapsed/CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeCounter:0));
  767. CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeCounter = 0;
  768. CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeElapsed = 0;
  769. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtEnumerateKey(KeyFullInformation ) %8lu %8lu *\n",
  770. CmpQueryKeyDataDebug.EnumerateKeyFullInformation,
  771. (ULONG)(CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeCounter?CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeElapsed/CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeCounter:0));
  772. CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeCounter = 0;
  773. CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeElapsed = 0;
  774. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*********************************************************************\n\n");
  775. //
  776. // reschedule
  777. //
  778. #endif //_CM_LDR_
  779. CmpKcbStat();
  780. }
  781. #endif