/*++ Copyright (c) 1992 Microsoft Corporation Module Name: cmworker.c Abstract: This module contains support for the worker thread of the registry. The worker thread (actually an executive worker thread is used) is required for operations that must take place in the context of the system process. (particularly file I/O) Author: John Vert (jvert) 21-Oct-1992 Revision History: --*/ #include "cmp.h" extern LIST_ENTRY CmpHiveListHead; VOID CmpInitializeHiveList( VOID ); // // ----- LAZY FLUSH CONTROL ----- // // LAZY_FLUSH_INTERVAL_IN_SECONDS controls how many seconds will elapse // between when the hive is marked dirty and when the lazy flush worker // thread is queued to write the data to disk. // ULONG CmpLazyFlushIntervalInSeconds = 5; // // number of hive flushed at one time (default to all system hive + 2 = current logged on user hives) // ULONG CmpLazyFlushHiveCount = 7; // // LAZY_FLUSH_TIMEOUT_IN_SECONDS controls how long the lazy flush worker // thread will wait for the registry lock before giving up and queueing // the lazy flush timer again. // #define LAZY_FLUSH_TIMEOUT_IN_SECONDS 1 #define SECOND_MULT 10*1000*1000 // 10->mic, 1000->mil, 1000->second PKPROCESS CmpSystemProcess; KTIMER CmpLazyFlushTimer; KDPC CmpLazyFlushDpc; WORK_QUEUE_ITEM CmpLazyWorkItem; BOOLEAN CmpLazyFlushPending = FALSE; BOOLEAN CmpForceForceFlush = FALSE; BOOLEAN CmpHoldLazyFlush = TRUE; BOOLEAN CmpDontGrowLogFile = FALSE; extern BOOLEAN CmpNoWrite; extern BOOLEAN CmpWasSetupBoot; extern BOOLEAN HvShutdownComplete; extern BOOLEAN CmpProfileLoaded; // // Indicate whether the "disk full" popup has been triggered yet or not. // extern BOOLEAN CmpDiskFullWorkerPopupDisplayed; // // set to true if disk full when trying to save the changes made between system hive loading and registry initalization // extern BOOLEAN CmpCannotWriteConfiguration; extern UNICODE_STRING SystemHiveFullPathName; extern HIVE_LIST_ENTRY CmpMachineHiveList[]; extern BOOLEAN CmpTrackHiveClose; #if DBG PKTHREAD CmpCallerThread = NULL; #endif #ifdef CMP_STATS #define KCB_STAT_INTERVAL_IN_SECONDS 120 // 2 min. extern struct { ULONG CmpMaxKcbNo; ULONG CmpKcbNo; ULONG CmpStatNo; ULONG CmpNtCreateKeyNo; ULONG CmpNtDeleteKeyNo; ULONG CmpNtDeleteValueKeyNo; ULONG CmpNtEnumerateKeyNo; ULONG CmpNtEnumerateValueKeyNo; ULONG CmpNtFlushKeyNo; ULONG CmpNtNotifyChangeMultipleKeysNo; ULONG CmpNtOpenKeyNo; ULONG CmpNtQueryKeyNo; ULONG CmpNtQueryValueKeyNo; ULONG CmpNtQueryMultipleValueKeyNo; ULONG CmpNtRestoreKeyNo; ULONG CmpNtSaveKeyNo; ULONG CmpNtSaveMergedKeysNo; ULONG CmpNtSetValueKeyNo; ULONG CmpNtLoadKeyNo; ULONG CmpNtUnloadKeyNo; ULONG CmpNtSetInformationKeyNo; ULONG CmpNtReplaceKeyNo; ULONG CmpNtQueryOpenSubKeysNo; } CmpStatsDebug; KTIMER CmpKcbStatTimer; KDPC CmpKcbStatDpc; KSPIN_LOCK CmpKcbStatLock; BOOLEAN CmpKcbStatShutdown; VOID CmpKcbStatDpcRoutine( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2 ); extern ULONG CmpNtFakeCreate; struct { ULONG BasicInformation; UINT64 BasicInformationTimeCounter; UINT64 BasicInformationTimeElapsed; ULONG NodeInformation; UINT64 NodeInformationTimeCounter; UINT64 NodeInformationTimeElapsed; ULONG FullInformation; UINT64 FullInformationTimeCounter; UINT64 FullInformationTimeElapsed; ULONG EnumerateKeyBasicInformation; UINT64 EnumerateKeyBasicInformationTimeCounter; UINT64 EnumerateKeyBasicInformationTimeElapsed; ULONG EnumerateKeyNodeInformation; UINT64 EnumerateKeyNodeInformationTimeCounter; UINT64 EnumerateKeyNodeInformationTimeElapsed; ULONG EnumerateKeyFullInformation; UINT64 EnumerateKeyFullInformationTimeCounter; UINT64 EnumerateKeyFullInformationTimeElapsed; } CmpQueryKeyDataDebug = {0}; #endif VOID CmpLazyFlushWorker( IN PVOID Parameter ); VOID CmpLazyFlushDpcRoutine( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2 ); VOID CmpDiskFullWarningWorker( IN PVOID WorkItem ); VOID CmpDiskFullWarning( VOID ); BOOLEAN CmpDoFlushNextHive( BOOLEAN ForceFlush, PBOOLEAN PostWarning, PULONG DirtyCount ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE,CmpLazyFlush) #pragma alloc_text(PAGE,CmpLazyFlushWorker) #pragma alloc_text(PAGE,CmpDiskFullWarningWorker) #pragma alloc_text(PAGE,CmpDiskFullWarning) #pragma alloc_text(PAGE,CmpCmdHiveClose) #pragma alloc_text(PAGE,CmpCmdInit) #pragma alloc_text(PAGE,CmpCmdRenameHive) #pragma alloc_text(PAGE,CmpCmdHiveOpen) #pragma alloc_text(PAGE,CmSetLazyFlushState) #ifndef CMP_STATS #pragma alloc_text(PAGE,CmpShutdownWorkers) #endif #endif VOID CmpCmdHiveClose( PCMHIVE CmHive ) /*++ Routine Description: Closes all the file handles for the specified hive Arguments: CmHive - the hive to close Return Value: none --*/ { ULONG i; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION BasicInfo; LARGE_INTEGER systemtime; BOOLEAN oldFlag; PAGED_CODE(); // // disable hard error popups, to workaround ObAttachProcessStack // oldFlag = IoSetThreadHardErrorMode(FALSE); // // Close the files associated with this hive. // ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); for (i=0; iFileHandles[i] != NULL) { // // attempt to set change the last write time (profile guys are relying on it!) // if( i == HFILE_TYPE_PRIMARY ) { if( NT_SUCCESS(ZwQueryInformationFile( CmHive->FileHandles[i], &IoStatusBlock, &BasicInfo, sizeof(BasicInfo), FileBasicInformation) ) ) { KeQuerySystemTime(&systemtime); BasicInfo.LastWriteTime = systemtime; BasicInfo.LastAccessTime = systemtime; ZwSetInformationFile( CmHive->FileHandles[i], &IoStatusBlock, &BasicInfo, sizeof(BasicInfo), FileBasicInformation ); } CmpTrackHiveClose = TRUE; CmCloseHandle(CmHive->FileHandles[i]); CmpTrackHiveClose = FALSE; } else { CmCloseHandle(CmHive->FileHandles[i]); } CmHive->FileHandles[i] = NULL; } } // // restore hard error popups mode // IoSetThreadHardErrorMode(oldFlag); } VOID CmpCmdInit( BOOLEAN SetupBoot ) /*++ Routine Description: Initializes cm globals and flushes all hives to the disk. Arguments: SetupBoot - whether the boot is from setup or a regular boot Return Value: none --*/ { PAGED_CODE(); ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); // // Initialize lazy flush timer and DPC // KeInitializeDpc(&CmpLazyFlushDpc, CmpLazyFlushDpcRoutine, NULL); KeInitializeTimer(&CmpLazyFlushTimer); ExInitializeWorkItem(&CmpLazyWorkItem, CmpLazyFlushWorker, NULL); #ifdef CMP_STATS KeInitializeDpc(&CmpKcbStatDpc, CmpKcbStatDpcRoutine, NULL); KeInitializeTimer(&CmpKcbStatTimer); KeInitializeSpinLock(&CmpKcbStatLock); CmpKcbStatShutdown = FALSE; #endif CmpNoWrite = CmpMiniNTBoot; CmpWasSetupBoot = SetupBoot; if (SetupBoot == FALSE) { CmpInitializeHiveList(); } // // Since we are done with initialization, // disable the hive sharing // if (CmpMiniNTBoot && CmpShareSystemHives) { CmpShareSystemHives = FALSE; } #ifdef CMP_STATS CmpKcbStat(); #endif } NTSTATUS CmpCmdRenameHive( PCMHIVE CmHive, POBJECT_NAME_INFORMATION OldName, PUNICODE_STRING NewName, ULONG NameInfoLength ) /*++ Routine Description: rename a cmhive's primary handle replaces old REG_CMD_RENAME_HIVE worker case Arguments: CmHive - hive to rename OldName - old name information NewName - the new name for the file NameInfoLength - sizeof name information structure Return Value: --*/ { NTSTATUS Status; HANDLE Handle; PFILE_RENAME_INFORMATION RenameInfo; IO_STATUS_BLOCK IoStatusBlock; PAGED_CODE(); ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); // // Rename a CmHive's primary handle // Handle = CmHive->FileHandles[HFILE_TYPE_PRIMARY]; if (OldName != NULL) { ASSERT_PASSIVE_LEVEL(); Status = ZwQueryObject(Handle, ObjectNameInformation, OldName, NameInfoLength, &NameInfoLength); if (!NT_SUCCESS(Status)) { return Status; } } RenameInfo = ExAllocatePool(PagedPool, sizeof(FILE_RENAME_INFORMATION) + NewName->Length); if (RenameInfo == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RenameInfo->ReplaceIfExists = FALSE; RenameInfo->RootDirectory = NULL; RenameInfo->FileNameLength = NewName->Length; RtlCopyMemory(RenameInfo->FileName, NewName->Buffer, NewName->Length); Status = ZwSetInformationFile(Handle, &IoStatusBlock, (PVOID)RenameInfo, sizeof(FILE_RENAME_INFORMATION) + NewName->Length, FileRenameInformation); ExFreePool(RenameInfo); return Status; } NTSTATUS CmpCmdHiveOpen( POBJECT_ATTRIBUTES FileAttributes, PSECURITY_CLIENT_CONTEXT ImpersonationContext, PBOOLEAN Allocate, PBOOLEAN RegistryLockAquired, // needed to avoid recursivity deadlock with ZwCreate calls calling back into registry PCMHIVE *NewHive, ULONG CheckFlags ) /*++ Routine Description: replaces old REG_CMD_HIVE_OPEN worker case Arguments: Return Value: --*/ { PUNICODE_STRING FileName; NTSTATUS Status; HANDLE NullHandle; PAGED_CODE(); // // Open the file. // FileName = FileAttributes->ObjectName; Status = CmpInitHiveFromFile(FileName, 0, NewHive, Allocate, RegistryLockAquired, CheckFlags); // // NT Servers will return STATUS_ACCESS_DENIED. Netware 3.1x // servers could return any of the other error codes if the GUEST // account is disabled. // if (((Status == STATUS_ACCESS_DENIED) || (Status == STATUS_NO_SUCH_USER) || (Status == STATUS_WRONG_PASSWORD) || (Status == STATUS_ACCOUNT_EXPIRED) || (Status == STATUS_ACCOUNT_DISABLED) || (Status == STATUS_ACCOUNT_RESTRICTION)) && (ImpersonationContext != NULL)) { // // Impersonate the caller and try it again. This // lets us open hives on a remote machine. // Status = SeImpersonateClientEx( ImpersonationContext, NULL); if ( NT_SUCCESS( Status ) ) { Status = CmpInitHiveFromFile(FileName, 0, NewHive, Allocate, RegistryLockAquired, CheckFlags); NullHandle = NULL; PsRevertToSelf(); } } return Status; } VOID CmpLazyFlush( VOID ) /*++ Routine Description: This routine resets the registry timer to go off at a specified interval in the future (LAZY_FLUSH_INTERVAL_IN_SECONDS). Arguments: None Return Value: None. --*/ { LARGE_INTEGER DueTime; PAGED_CODE(); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"CmpLazyFlush: setting lazy flush timer\n")); if ((!CmpNoWrite) && (!CmpHoldLazyFlush)) { DueTime.QuadPart = Int32x32To64(CmpLazyFlushIntervalInSeconds, - SECOND_MULT); // // Indicate relative time // KeSetTimer(&CmpLazyFlushTimer, DueTime, &CmpLazyFlushDpc); } } VOID CmpLazyFlushDpcRoutine( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2 ) /*++ Routine Description: This is the DPC routine triggered by the lazy flush timer. All it does is queue a work item to an executive worker thread. The work item will do the actual lazy flush to disk. Arguments: Dpc - Supplies a pointer to the DPC object. DeferredContext - not used SystemArgument1 - not used SystemArgument2 - not used Return Value: None. --*/ { UNREFERENCED_PARAMETER (Dpc); UNREFERENCED_PARAMETER (DeferredContext); UNREFERENCED_PARAMETER (SystemArgument1); UNREFERENCED_PARAMETER (SystemArgument2); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"CmpLazyFlushDpc: queuing lazy flush work item\n")); if ((!CmpLazyFlushPending) && (!CmpHoldLazyFlush)) { CmpLazyFlushPending = TRUE; ExQueueWorkItem(&CmpLazyWorkItem, DelayedWorkQueue); } } /* #define LAZY_FLUSH_CAPTURE_SLOTS 5000 typedef struct { LARGE_INTEGER SystemTime; ULONG ElapsedMSec; } CM_LAZY_FLUSH_DATA; ULONG CmpLazyFlushCapturedDataCount = 0; CM_LAZY_FLUSH_DATA CmpLazyFlushCapturedData[LAZY_FLUSH_CAPTURE_SLOTS] = {0}; BOOLEAN CmpCaptureLazyFlushData = FALSE; */ ULONG CmpLazyFlushCount = 1; VOID CmpLazyFlushWorker( IN PVOID Parameter ) /*++ Routine Description: Worker routine called to do a lazy flush. Called by an executive worker thread in the system process. Arguments: Parameter - not used. Return Value: None. --*/ { BOOLEAN Result = TRUE; BOOLEAN ForceFlush; BOOLEAN PostNewWorker = FALSE; ULONG DirtyCount = 0; PAGED_CODE(); UNREFERENCED_PARAMETER (Parameter); if( CmpHoldLazyFlush ) { // // lazy flush mode is disabled // return; } CmKdPrintEx((DPFLTR_CONFIG_ID,CML_IO,"CmpLazyFlushWorker: flushing hives\n")); ForceFlush = CmpForceForceFlush; if(ForceFlush == TRUE) { // // something bad happened and we may need to fix hive's use count // CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"CmpLazyFlushWorker: Force Flush - getting the reglock exclusive\n")); CmpLockRegistryExclusive(); } else { CmpLockRegistry(); ENTER_FLUSH_MODE(); } if (!HvShutdownComplete) { // // this call will set CmpForceForceFlush to the right value // //Result = CmpDoFlushAll(ForceFlush); /* if( CmpCaptureLazyFlushData && (CmpLazyFlushCapturedDataCount < LAZY_FLUSH_CAPTURE_SLOTS) ) { KeQuerySystemTime( &(CmpLazyFlushCapturedData[CmpLazyFlushCapturedDataCount].SystemTime) ); } */ PostNewWorker = CmpDoFlushNextHive(ForceFlush,&Result,&DirtyCount); /* if( CmpCaptureLazyFlushData && (CmpLazyFlushCapturedDataCount < LAZY_FLUSH_CAPTURE_SLOTS) ) { LARGE_INTEGER ElapsedTime; KeQuerySystemTime( &ElapsedTime ); ElapsedTime.QuadPart -= CmpLazyFlushCapturedData[CmpLazyFlushCapturedDataCount].SystemTime.QuadPart; CmpLazyFlushCapturedData[CmpLazyFlushCapturedDataCount].ElapsedMSec = (ULONG)((LONGLONG)(ElapsedTime.QuadPart / 10000)); CmpLazyFlushCapturedDataCount++; } */ if( !PostNewWorker ) { // // we have completed a sweep through the entire list of hives // InterlockedIncrement( (PLONG)&CmpLazyFlushCount ); } } else { CmpForceForceFlush = FALSE; } if( ForceFlush == FALSE ) { EXIT_FLUSH_MODE(); } CmpLazyFlushPending = FALSE; CmpUnlockRegistry(); if( CmpCannotWriteConfiguration ) { // // Disk full; system hive has not been saved at initialization // if(!Result) { // // All hives were saved; No need for disk full warning anymore // CmpCannotWriteConfiguration = FALSE; } else { // // Issue another hard error (if not already displayed) and postpone a lazy flush operation // CmpDiskFullWarning(); CmpLazyFlush(); } } // // if we have not yet flushed the whole list; or there are still hives dirty from the curently ended iteration. // if( PostNewWorker || (DirtyCount != 0) ) { // // post a new worker to flush the next hive // CmpLazyFlush(); } } VOID CmpDiskFullWarningWorker( IN PVOID WorkItem ) /*++ Routine Description: Displays hard error popup that indicates the disk is full. Arguments: WorkItem - Supplies pointer to the work item. This routine will free the work item. Return Value: None. --*/ { NTSTATUS Status; ULONG Response; ExFreePool(WorkItem); Status = ExRaiseHardError(STATUS_DISK_FULL, 0, 0, NULL, OptionOk, &Response); } VOID CmpDiskFullWarning( VOID ) /*++ Routine Description: Raises a hard error of type STATUS_DISK_FULL if wasn't already raised Arguments: None Return Value: None --*/ { PWORK_QUEUE_ITEM WorkItem; if( (!CmpDiskFullWorkerPopupDisplayed) && (CmpCannotWriteConfiguration) && (ExReadyForErrors) && (CmpProfileLoaded) ) { // // Queue work item to display popup // WorkItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM)); if (WorkItem != NULL) { CmpDiskFullWorkerPopupDisplayed = TRUE; ExInitializeWorkItem(WorkItem, CmpDiskFullWarningWorker, WorkItem); ExQueueWorkItem(WorkItem, DelayedWorkQueue); } } } VOID CmpShutdownWorkers( VOID ) /*++ Routine Description: Shuts down the lazy flush worker (by killing the timer) Arguments: None Return Value: None --*/ { PAGED_CODE(); KeCancelTimer(&CmpLazyFlushTimer); #ifdef CMP_STATS { KIRQL OldIrql; KeAcquireSpinLock(&CmpKcbStatLock, &OldIrql); CmpKcbStatShutdown = TRUE; KeCancelTimer(&CmpKcbStatTimer); KeReleaseSpinLock(&CmpKcbStatLock, OldIrql); } #endif } VOID CmSetLazyFlushState(BOOLEAN Enable) /*++ Routine Description: Enables/Disables the lazy flusher; Designed for the standby/resume case, where we we don't want the lazy flush to fire off, blocking registry writers until the disk wakes up. Arguments: Enable - TRUE = enable; FALSE = disable Return Value: None. --*/ { PAGED_CODE(); CmpDontGrowLogFile = CmpHoldLazyFlush = !Enable; } #ifdef CMP_STATS VOID CmpKcbStat( VOID ) /*++ Routine Description: This routine resets the KcbStat timer to go off at a specified interval in the future Arguments: None Return Value: None. --*/ { LARGE_INTEGER DueTime; KIRQL OldIrql; DueTime.QuadPart = Int32x32To64(KCB_STAT_INTERVAL_IN_SECONDS, - SECOND_MULT); // // Indicate relative time // KeAcquireSpinLock(&CmpKcbStatLock, &OldIrql); if (! CmpKcbStatShutdown) { KeSetTimer(&CmpKcbStatTimer, DueTime, &CmpKcbStatDpc); } KeReleaseSpinLock(&CmpKcbStatLock, OldIrql); } VOID CmpKcbStatDpcRoutine( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2 ) /*++ Routine Description: Dumps the kcb stats in the debugger and then reschedules another Dpc in the future Arguments: Dpc - Supplies a pointer to the DPC object. DeferredContext - not used SystemArgument1 - not used SystemArgument2 - not used Return Value: None. --*/ { #ifndef _CM_LDR_ DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"\n*********************************************************************\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* Stat No %8lu KcbNo = %8lu [MaxKcbNo = %8lu] *\n",++CmpStatsDebug.CmpStatNo,CmpStatsDebug.CmpKcbNo,CmpStatsDebug.CmpMaxKcbNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*********************************************************************\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* *\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* [Nt]API [No. Of]Calls *\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtCreateKey %8lu Opens = %8lu *\n",CmpStatsDebug.CmpNtCreateKeyNo,CmpNtFakeCreate); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtOpenKey %8lu *\n",CmpStatsDebug.CmpNtOpenKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtEnumerateKey %8lu *\n",CmpStatsDebug.CmpNtEnumerateKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryKey %8lu *\n",CmpStatsDebug.CmpNtQueryKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtDeleteKey %8lu *\n",CmpStatsDebug.CmpNtDeleteKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtSetInformationKey %8lu *\n",CmpStatsDebug.CmpNtSetInformationKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtSetValueKey %8lu *\n",CmpStatsDebug.CmpNtSetValueKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtEnumerateValueKey %8lu *\n",CmpStatsDebug.CmpNtEnumerateValueKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryValueKey %8lu *\n",CmpStatsDebug.CmpNtQueryValueKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryMultipleValueKey %8lu *\n",CmpStatsDebug.CmpNtQueryMultipleValueKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtDeleteValueKey %8lu *\n",CmpStatsDebug.CmpNtDeleteValueKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtFlushKey %8lu *\n",CmpStatsDebug.CmpNtFlushKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtLoadKey %8lu *\n",CmpStatsDebug.CmpNtLoadKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtUnloadKey %8lu *\n",CmpStatsDebug.CmpNtUnloadKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtSaveKey %8lu *\n",CmpStatsDebug.CmpNtSaveKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtSaveMergedKeys %8lu *\n",CmpStatsDebug.CmpNtSaveMergedKeysNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtRestoreKey %8lu *\n",CmpStatsDebug.CmpNtRestoreKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtReplaceKey %8lu *\n",CmpStatsDebug.CmpNtReplaceKeyNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtNotifyChgMultplKeys %8lu *\n",CmpStatsDebug.CmpNtNotifyChangeMultipleKeysNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryOpenSubKeys %8lu *\n",CmpStatsDebug.CmpNtQueryOpenSubKeysNo); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* [No.Of]Calls [Time] *\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*-------------------------------------------------------------------*\n"); DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryKey(KeyBasicInformation) %8lu %8lu *\n", CmpQueryKeyDataDebug.BasicInformation, (ULONG)(CmpQueryKeyDataDebug.BasicInformationTimeCounter?CmpQueryKeyDataDebug.BasicInformationTimeElapsed/CmpQueryKeyDataDebug.BasicInformationTimeCounter:0)); CmpQueryKeyDataDebug.BasicInformationTimeCounter = 0; CmpQueryKeyDataDebug.BasicInformationTimeElapsed = 0; DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryKey(KeyNodeInformation ) %8lu %8lu *\n", CmpQueryKeyDataDebug.NodeInformation, (ULONG)(CmpQueryKeyDataDebug.NodeInformationTimeCounter?CmpQueryKeyDataDebug.NodeInformationTimeElapsed/CmpQueryKeyDataDebug.NodeInformationTimeCounter:0)); CmpQueryKeyDataDebug.NodeInformationTimeCounter = 0; CmpQueryKeyDataDebug.NodeInformationTimeElapsed = 0; DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtQueryKey(KeyFullInformation ) %8lu %8lu *\n", CmpQueryKeyDataDebug.FullInformation, (ULONG)(CmpQueryKeyDataDebug.FullInformationTimeCounter?CmpQueryKeyDataDebug.FullInformationTimeElapsed/CmpQueryKeyDataDebug.FullInformationTimeCounter:0)); CmpQueryKeyDataDebug.FullInformationTimeCounter = 0; CmpQueryKeyDataDebug.FullInformationTimeElapsed = 0; DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtEnumerateKey(KeyBasicInformation) %8lu %8lu *\n", CmpQueryKeyDataDebug.EnumerateKeyBasicInformation, (ULONG)(CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeCounter?CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeElapsed/CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeCounter:0)); CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeCounter = 0; CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeElapsed = 0; DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtEnumerateKey(KeyNodeInformation ) %8lu %8lu *\n", CmpQueryKeyDataDebug.EnumerateKeyNodeInformation, (ULONG)(CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeCounter?CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeElapsed/CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeCounter:0)); CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeCounter = 0; CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeElapsed = 0; DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "* NtEnumerateKey(KeyFullInformation ) %8lu %8lu *\n", CmpQueryKeyDataDebug.EnumerateKeyFullInformation, (ULONG)(CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeCounter?CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeElapsed/CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeCounter:0)); CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeCounter = 0; CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeElapsed = 0; DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL, "*********************************************************************\n\n"); // // reschedule // #endif //_CM_LDR_ CmpKcbStat(); } #endif