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

/*++
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; i<HFILE_TYPE_MAX; i++) {
if (CmHive->FileHandles[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:
<TBD>
--*/
{
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:
<TBD>
--*/
{
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