mirror of
https://github.com/reactos/reactos.git
synced 2025-06-10 04:14:53 +00:00
- Merge KCB/NCB code (and related delay alloc/free implementation) from cm-rewrite branch. Only "used" in one call so it shouldn't affect anything.
svn path=/trunk/; revision=29954
This commit is contained in:
parent
4318124a73
commit
babcc56c4a
8 changed files with 1497 additions and 134 deletions
|
@ -226,7 +226,7 @@ CmpRosGetHardwareHive(OUT PULONG Length)
|
||||||
/* Precondition: Must not hold the hive lock CmpRegistryLock */
|
/* Precondition: Must not hold the hive lock CmpRegistryLock */
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
EnlistKeyBodyWithKCB(IN PKEY_OBJECT KeyObject,
|
EnlistKeyBodyWithKeyObject(IN PKEY_OBJECT KeyObject,
|
||||||
IN ULONG Flags)
|
IN ULONG Flags)
|
||||||
{
|
{
|
||||||
/* Acquire hive lock */
|
/* Acquire hive lock */
|
||||||
|
|
|
@ -308,6 +308,15 @@ typedef struct _CM_ALLOC_PAGE
|
||||||
PVOID AllocPage;
|
PVOID AllocPage;
|
||||||
} CM_ALLOC_PAGE, *PCM_ALLOC_PAGE;
|
} CM_ALLOC_PAGE, *PCM_ALLOC_PAGE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Allocation Page Entry
|
||||||
|
//
|
||||||
|
typedef struct _CM_DELAY_ALLOC
|
||||||
|
{
|
||||||
|
LIST_ENTRY ListEntry;
|
||||||
|
PCM_KEY_CONTROL_BLOCK Kcb;
|
||||||
|
} CM_DELAY_ALLOC, *PCM_DELAY_ALLOC;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Delayed Close Entry
|
// Delayed Close Entry
|
||||||
//
|
//
|
||||||
|
@ -788,6 +797,9 @@ CmpUnlockRegistry(
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Delay Functions
|
||||||
|
//
|
||||||
PVOID
|
PVOID
|
||||||
NTAPI
|
NTAPI
|
||||||
CmpAllocateDelayItem(
|
CmpAllocateDelayItem(
|
||||||
|
@ -800,6 +812,29 @@ CmpFreeDelayItem(
|
||||||
PVOID Entry
|
PVOID Entry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpDelayDerefKeyControlBlock(
|
||||||
|
IN PCM_KEY_CONTROL_BLOCK Kcb
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpAddToDelayedClose(
|
||||||
|
IN PCM_KEY_CONTROL_BLOCK Kcb,
|
||||||
|
IN BOOLEAN LockHeldExclusively
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpRemoveFromDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpInitializeDelayedCloseTable(
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// KCB Functions
|
// KCB Functions
|
||||||
//
|
//
|
||||||
|
@ -814,9 +849,28 @@ CmpCreateKeyControlBlock(
|
||||||
IN PUNICODE_STRING KeyName
|
IN PUNICODE_STRING KeyName
|
||||||
);
|
);
|
||||||
|
|
||||||
|
PCM_KEY_CONTROL_BLOCK
|
||||||
|
NTAPI
|
||||||
|
CmpAllocateKeyControlBlock(
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
CmpDereferenceKcbWithLock(
|
CmpFreeKeyControlBlock(
|
||||||
|
IN PCM_KEY_CONTROL_BLOCK Kcb
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpCleanUpKcbCacheWithLock(
|
||||||
|
IN PCM_KEY_CONTROL_BLOCK Kcb,
|
||||||
|
IN BOOLEAN LockHeldExclusively
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpDereferenceKeyControlBlockWithLock(
|
||||||
IN PCM_KEY_CONTROL_BLOCK Kcb,
|
IN PCM_KEY_CONTROL_BLOCK Kcb,
|
||||||
IN BOOLEAN LockHeldExclusively
|
IN BOOLEAN LockHeldExclusively
|
||||||
);
|
);
|
||||||
|
@ -824,11 +878,14 @@ CmpDereferenceKcbWithLock(
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
EnlistKeyBodyWithKCB(
|
EnlistKeyBodyWithKCB(
|
||||||
#if 0
|
|
||||||
IN PCM_KEY_BODY KeyObject,
|
IN PCM_KEY_BODY KeyObject,
|
||||||
#else
|
IN ULONG Flags
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
EnlistKeyBodyWithKeyObject(
|
||||||
IN PKEY_OBJECT KeyObject,
|
IN PKEY_OBJECT KeyObject,
|
||||||
#endif
|
|
||||||
IN ULONG Flags
|
IN ULONG Flags
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1276,6 +1333,7 @@ extern HANDLE CmpRegistryRootHandle;
|
||||||
extern BOOLEAN ExpInTextModeSetup;
|
extern BOOLEAN ExpInTextModeSetup;
|
||||||
extern BOOLEAN InitIsWinPEMode;
|
extern BOOLEAN InitIsWinPEMode;
|
||||||
extern ULONG CmpHashTableSize;
|
extern ULONG CmpHashTableSize;
|
||||||
|
extern ULONG CmpDelayedCloseSize, CmpDelayedCloseIndex;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Inlined functions
|
// Inlined functions
|
||||||
|
|
|
@ -199,6 +199,18 @@ CmpTryToConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k)
|
||||||
(k)).Lock); \
|
(k)).Lock); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Converts a KCB lock
|
||||||
|
//
|
||||||
|
FORCEINLINE
|
||||||
|
VOID
|
||||||
|
CmpConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k)
|
||||||
|
{
|
||||||
|
ASSERT(CmpIsKcbLockedExclusive(k) == FALSE);
|
||||||
|
CmpReleaseKcbLock(k);
|
||||||
|
CmpAcquireKcbLockExclusive(k);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Exclusively acquires an NCB
|
// Exclusively acquires an NCB
|
||||||
//
|
//
|
||||||
|
@ -208,6 +220,15 @@ CmpTryToConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k)
|
||||||
(n)->ConvKey).Lock); \
|
(n)->ConvKey).Lock); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Exclusively acquires an NCB by key
|
||||||
|
//
|
||||||
|
#define CmpAcquireNcbLockExclusiveByKey(k) \
|
||||||
|
{ \
|
||||||
|
ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \
|
||||||
|
(k)).Lock); \
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Releases an exlusively or shared acquired NCB
|
// Releases an exlusively or shared acquired NCB
|
||||||
//
|
//
|
||||||
|
@ -216,3 +237,12 @@ CmpTryToConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k)
|
||||||
ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \
|
ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \
|
||||||
(k)->ConvKey).Lock); \
|
(k)->ConvKey).Lock); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Releases an exlusively or shared acquired NCB by key
|
||||||
|
//
|
||||||
|
#define CmpReleaseNcbLockByKey(k) \
|
||||||
|
{ \
|
||||||
|
ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \
|
||||||
|
(k)).Lock); \
|
||||||
|
}
|
||||||
|
|
305
reactos/ntoskrnl/config/cmalloc.c
Normal file
305
reactos/ntoskrnl/config/cmalloc.c
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Kernel
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: ntoskrnl/config/cmalloc.c
|
||||||
|
* PURPOSE: Routines for allocating and freeing registry structures
|
||||||
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
|
#include <ntoskrnl.h>
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
#include "cm.h"
|
||||||
|
|
||||||
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
BOOLEAN CmpAllocInited;
|
||||||
|
KGUARDED_MUTEX CmpAllocBucketLock, CmpDelayAllocBucketLock;
|
||||||
|
|
||||||
|
LIST_ENTRY CmpFreeKCBListHead;
|
||||||
|
KGUARDED_MUTEX CmpDelayAllocBucketLock;
|
||||||
|
LIST_ENTRY CmpFreeDelayItemsListHead;
|
||||||
|
|
||||||
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpInitCmPrivateAlloc(VOID)
|
||||||
|
{
|
||||||
|
/* Make sure we didn't already do this */
|
||||||
|
if (!CmpAllocInited)
|
||||||
|
{
|
||||||
|
/* Setup the lock and list */
|
||||||
|
KeInitializeGuardedMutex(&CmpAllocBucketLock);
|
||||||
|
InitializeListHead(&CmpFreeKCBListHead);
|
||||||
|
CmpAllocInited = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpInitCmPrivateDelayAlloc(VOID)
|
||||||
|
{
|
||||||
|
/* Initialize the delay allocation list and lock */
|
||||||
|
KeInitializeGuardedMutex(&CmpDelayAllocBucketLock);
|
||||||
|
InitializeListHead(&CmpFreeDelayItemsListHead);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpFreeKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
|
||||||
|
{
|
||||||
|
ULONG i;
|
||||||
|
PCM_ALLOC_PAGE AllocPage;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
|
ASSERT(IsListEmpty(&(Kcb->KeyBodyListHead)) == TRUE);
|
||||||
|
for (i = 0; i < 4; i++) ASSERT(Kcb->KeyBodyArray[i] == NULL);
|
||||||
|
|
||||||
|
/* Check if it wasn't privately allocated */
|
||||||
|
if (!Kcb->PrivateAlloc)
|
||||||
|
{
|
||||||
|
/* Free it from the pool */
|
||||||
|
ExFreePool(Kcb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Acquire the private allocation lock */
|
||||||
|
KeAcquireGuardedMutex(&CmpAllocBucketLock);
|
||||||
|
|
||||||
|
/* Sanity check on lock ownership */
|
||||||
|
ASSERT((GET_HASH_ENTRY(CmpCacheTable, Kcb->ConvKey).Owner ==
|
||||||
|
KeGetCurrentThread()) ||
|
||||||
|
(CmpTestRegistryLockExclusive() == TRUE));
|
||||||
|
|
||||||
|
/* Add us to the free list */
|
||||||
|
InsertTailList(&CmpFreeKCBListHead, &Kcb->FreeListEntry);
|
||||||
|
|
||||||
|
/* Get the allocation page */
|
||||||
|
AllocPage = (PCM_ALLOC_PAGE)((ULONG_PTR)Kcb & 0xFFFFF000);
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT(AllocPage->FreeCount != CM_KCBS_PER_PAGE);
|
||||||
|
|
||||||
|
/* Increase free count */
|
||||||
|
if (++AllocPage->FreeCount == CM_KCBS_PER_PAGE)
|
||||||
|
{
|
||||||
|
/* Loop all the entries */
|
||||||
|
for (i = CM_KCBS_PER_PAGE; i; i--)
|
||||||
|
{
|
||||||
|
/* Get the KCB */
|
||||||
|
Kcb = (PVOID)((ULONG_PTR)AllocPage +
|
||||||
|
FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
|
||||||
|
i * sizeof(CM_KEY_CONTROL_BLOCK));
|
||||||
|
|
||||||
|
/* Remove the entry */
|
||||||
|
RemoveEntryList(&Kcb->FreeListEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the page */
|
||||||
|
ExFreePool(AllocPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the lock */
|
||||||
|
KeReleaseGuardedMutex(&CmpAllocBucketLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
PCM_KEY_CONTROL_BLOCK
|
||||||
|
NTAPI
|
||||||
|
CmpAllocateKeyControlBlock(VOID)
|
||||||
|
{
|
||||||
|
PLIST_ENTRY NextEntry;
|
||||||
|
PCM_KEY_CONTROL_BLOCK CurrentKcb;
|
||||||
|
PCM_ALLOC_PAGE AllocPage;
|
||||||
|
ULONG i;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Check if private allocations are initialized */
|
||||||
|
if (CmpAllocInited)
|
||||||
|
{
|
||||||
|
/* They are, acquire the bucket lock */
|
||||||
|
KeAcquireGuardedMutex(&CmpAllocBucketLock);
|
||||||
|
|
||||||
|
/* See if there's something on the free KCB list */
|
||||||
|
SearchKcbList:
|
||||||
|
if (!IsListEmpty(&CmpFreeKCBListHead))
|
||||||
|
{
|
||||||
|
/* Remove the entry */
|
||||||
|
NextEntry = RemoveHeadList(&CmpFreeKCBListHead);
|
||||||
|
|
||||||
|
/* Get the KCB */
|
||||||
|
CurrentKcb = CONTAINING_RECORD(NextEntry,
|
||||||
|
CM_KEY_CONTROL_BLOCK,
|
||||||
|
FreeListEntry);
|
||||||
|
|
||||||
|
/* Get the allocation page */
|
||||||
|
AllocPage = (PCM_ALLOC_PAGE)((ULONG_PTR)CurrentKcb & 0xFFFFF000);
|
||||||
|
|
||||||
|
/* Decrease the free count */
|
||||||
|
ASSERT(AllocPage->FreeCount != 0);
|
||||||
|
AllocPage->FreeCount--;
|
||||||
|
|
||||||
|
/* Make sure this KCB is privately allocated */
|
||||||
|
ASSERT(CurrentKcb->PrivateAlloc == 1);
|
||||||
|
|
||||||
|
/* Release the allocation lock */
|
||||||
|
KeReleaseGuardedMutex(&CmpAllocBucketLock);
|
||||||
|
|
||||||
|
/* Return the KCB */
|
||||||
|
return CurrentKcb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate an allocation page */
|
||||||
|
AllocPage = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM);
|
||||||
|
if (AllocPage)
|
||||||
|
{
|
||||||
|
/* Set default entries */
|
||||||
|
AllocPage->FreeCount = CM_KCBS_PER_PAGE;
|
||||||
|
|
||||||
|
/* Loop each entry */
|
||||||
|
for (i = 0; i < CM_KCBS_PER_PAGE; i++)
|
||||||
|
{
|
||||||
|
/* Get this entry */
|
||||||
|
CurrentKcb = (PVOID)((ULONG_PTR)AllocPage +
|
||||||
|
FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
|
||||||
|
i * sizeof(CM_KEY_CONTROL_BLOCK));
|
||||||
|
|
||||||
|
/* Set it up */
|
||||||
|
CurrentKcb->PrivateAlloc = TRUE;
|
||||||
|
CurrentKcb->DelayCloseEntry = NULL;
|
||||||
|
InsertHeadList(&CmpFreeKCBListHead,
|
||||||
|
&CurrentKcb->FreeListEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now go back and search the list */
|
||||||
|
goto SearchKcbList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a KCB only */
|
||||||
|
CurrentKcb = ExAllocatePoolWithTag(PagedPool,
|
||||||
|
sizeof(CM_KEY_CONTROL_BLOCK),
|
||||||
|
TAG_CM);
|
||||||
|
if (CurrentKcb)
|
||||||
|
{
|
||||||
|
/* Set it up */
|
||||||
|
CurrentKcb->PrivateAlloc = 0;
|
||||||
|
CurrentKcb->DelayCloseEntry = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return it */
|
||||||
|
return CurrentKcb;
|
||||||
|
}
|
||||||
|
|
||||||
|
PVOID
|
||||||
|
NTAPI
|
||||||
|
CmpAllocateDelayItem(VOID)
|
||||||
|
{
|
||||||
|
PCM_DELAY_ALLOC Entry;
|
||||||
|
PCM_ALLOC_PAGE AllocPage;
|
||||||
|
ULONG i;
|
||||||
|
PLIST_ENTRY NextEntry;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Lock the allocation buckets */
|
||||||
|
KeAcquireGuardedMutex(&CmpDelayAllocBucketLock);
|
||||||
|
|
||||||
|
/* Look for an item on the free list */
|
||||||
|
SearchList:
|
||||||
|
if (!IsListEmpty(&CmpFreeDelayItemsListHead))
|
||||||
|
{
|
||||||
|
/* Get the current entry in the list */
|
||||||
|
NextEntry = RemoveHeadList(&CmpFreeDelayItemsListHead);
|
||||||
|
|
||||||
|
/* Grab the item */
|
||||||
|
Entry = CONTAINING_RECORD(NextEntry, CM_DELAY_ALLOC, ListEntry);
|
||||||
|
|
||||||
|
/* Clear the list */
|
||||||
|
Entry->ListEntry.Flink = Entry->ListEntry.Blink = NULL;
|
||||||
|
|
||||||
|
/* Grab the alloc page */
|
||||||
|
AllocPage = (PCM_ALLOC_PAGE)((ULONG_PTR)Entry & 0xFFFFF000);
|
||||||
|
|
||||||
|
/* Decrease free entries */
|
||||||
|
ASSERT(AllocPage->FreeCount != 0);
|
||||||
|
AllocPage->FreeCount--;
|
||||||
|
|
||||||
|
/* Release the lock */
|
||||||
|
KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
|
||||||
|
return Entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate an allocation page */
|
||||||
|
AllocPage = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM);
|
||||||
|
if (AllocPage)
|
||||||
|
{
|
||||||
|
/* Set default entries */
|
||||||
|
AllocPage->FreeCount = CM_DELAYS_PER_PAGE;
|
||||||
|
|
||||||
|
/* Loop each entry */
|
||||||
|
for (i = 0; i < CM_DELAYS_PER_PAGE; i++)
|
||||||
|
{
|
||||||
|
/* Get this entry and link it */
|
||||||
|
Entry = (PVOID)((ULONG_PTR)AllocPage +
|
||||||
|
FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
|
||||||
|
i * sizeof(CM_DELAY_ALLOC));
|
||||||
|
InsertTailList(&CmpFreeDelayItemsListHead,
|
||||||
|
&Entry->ListEntry);
|
||||||
|
|
||||||
|
/* Clear the KCB pointer */
|
||||||
|
Entry->Kcb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Release the lock */
|
||||||
|
KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the search again */
|
||||||
|
goto SearchList;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpFreeDelayItem(PVOID Entry)
|
||||||
|
{
|
||||||
|
PCM_DELAY_ALLOC AllocEntry = (PCM_DELAY_ALLOC)Entry;
|
||||||
|
PCM_ALLOC_PAGE AllocPage;
|
||||||
|
ULONG i;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Lock the table */
|
||||||
|
KeAcquireGuardedMutex(&CmpDelayAllocBucketLock);
|
||||||
|
|
||||||
|
/* Add the entry at the end */
|
||||||
|
InsertTailList(&CmpFreeDelayItemsListHead, &AllocEntry->ListEntry);
|
||||||
|
|
||||||
|
/* Get the alloc page */
|
||||||
|
AllocPage = (PCM_ALLOC_PAGE)((ULONG_PTR)Entry & 0xFFFFF000);
|
||||||
|
ASSERT(AllocPage->FreeCount != CM_DELAYS_PER_PAGE);
|
||||||
|
|
||||||
|
/* Increase the number of free items */
|
||||||
|
if (++AllocPage->FreeCount == CM_DELAYS_PER_PAGE)
|
||||||
|
{
|
||||||
|
/* Page is totally free now, loop each entry */
|
||||||
|
for (i = 0; i < CM_DELAYS_PER_PAGE; i++)
|
||||||
|
{
|
||||||
|
/* Get the entry and unlink it */
|
||||||
|
AllocEntry = (PVOID)((ULONG_PTR)AllocPage +
|
||||||
|
FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
|
||||||
|
i * sizeof(CM_DELAY_ALLOC));
|
||||||
|
RemoveEntryList(&AllocEntry->ListEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now free the page */
|
||||||
|
ExFreePool(AllocPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the lock */
|
||||||
|
KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
|
||||||
|
}
|
307
reactos/ntoskrnl/config/cmdelay.c
Normal file
307
reactos/ntoskrnl/config/cmdelay.c
Normal file
|
@ -0,0 +1,307 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Kernel
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: ntoskrnl/config/cmdelay.c
|
||||||
|
* PURPOSE: Routines for handling delay close and allocate.
|
||||||
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
|
#include <ntoskrnl.h>
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
#include "cm.h"
|
||||||
|
|
||||||
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
WORK_QUEUE_ITEM CmpDelayDerefKCBWorkItem;
|
||||||
|
LIST_ENTRY CmpFreeDelayItemsListHead;
|
||||||
|
|
||||||
|
ULONG CmpDelayedCloseSize = 2048;
|
||||||
|
ULONG CmpDelayedCloseElements;
|
||||||
|
KGUARDED_MUTEX CmpDelayedCloseTableLock;
|
||||||
|
BOOLEAN CmpDelayCloseWorkItemActive;
|
||||||
|
WORK_QUEUE_ITEM CmpDelayCloseWorkItem;
|
||||||
|
LIST_ENTRY CmpDelayedLRUListHead;
|
||||||
|
ULONG CmpDelayCloseIntervalInSeconds = 5;
|
||||||
|
KDPC CmpDelayCloseDpc;
|
||||||
|
KTIMER CmpDelayCloseTimer;
|
||||||
|
|
||||||
|
KGUARDED_MUTEX CmpDelayDerefKCBLock;
|
||||||
|
BOOLEAN CmpDelayDerefKCBWorkItemActive;
|
||||||
|
LIST_ENTRY CmpDelayDerefKCBListHead;
|
||||||
|
ULONG CmpDelayDerefKCBIntervalInSeconds = 5;
|
||||||
|
KDPC CmpDelayDerefKCBDpc;
|
||||||
|
KTIMER CmpDelayDerefKCBTimer;
|
||||||
|
|
||||||
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpDelayCloseDpcRoutine(IN PKDPC Dpc,
|
||||||
|
IN PVOID DeferredContext,
|
||||||
|
IN PVOID SystemArgument1,
|
||||||
|
IN PVOID SystemArgument2)
|
||||||
|
{
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT(CmpDelayCloseWorkItemActive);
|
||||||
|
|
||||||
|
/* Queue the work item */
|
||||||
|
ExQueueWorkItem(&CmpDelayCloseWorkItem, DelayedWorkQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpDelayCloseWorker(IN PVOID Context)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT(CmpDelayCloseWorkItemActive);
|
||||||
|
|
||||||
|
/* FIXME: TODO */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpInitializeDelayedCloseTable(VOID)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Setup the delayed close lock */
|
||||||
|
KeInitializeGuardedMutex(&CmpDelayedCloseTableLock);
|
||||||
|
|
||||||
|
/* Setup the work item */
|
||||||
|
ExInitializeWorkItem(&CmpDelayCloseWorkItem, CmpDelayCloseWorker, NULL);
|
||||||
|
|
||||||
|
/* Setup the list head */
|
||||||
|
InitializeListHead(&CmpDelayedLRUListHead);
|
||||||
|
|
||||||
|
/* Setup the DPC and its timer */
|
||||||
|
KeInitializeDpc(&CmpDelayCloseDpc, CmpDelayCloseDpcRoutine, NULL);
|
||||||
|
KeInitializeTimer(&CmpDelayCloseTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpDelayDerefKCBDpcRoutine(IN PKDPC Dpc,
|
||||||
|
IN PVOID DeferredContext,
|
||||||
|
IN PVOID SystemArgument1,
|
||||||
|
IN PVOID SystemArgument2)
|
||||||
|
{
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT(CmpDelayDerefKCBWorkItemActive);
|
||||||
|
|
||||||
|
/* Queue the work item */
|
||||||
|
ExQueueWorkItem(&CmpDelayDerefKCBWorkItem, DelayedWorkQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpDelayDerefKCBWorker(IN PVOID Context)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT(CmpDelayDerefKCBWorkItemActive);
|
||||||
|
|
||||||
|
/* FIXME: TODO */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpInitDelayDerefKCBEngine(VOID)
|
||||||
|
{
|
||||||
|
/* Initialize lock and list */
|
||||||
|
KeInitializeGuardedMutex(&CmpDelayDerefKCBLock);
|
||||||
|
InitializeListHead(&CmpDelayDerefKCBListHead);
|
||||||
|
|
||||||
|
/* Setup the work item */
|
||||||
|
ExInitializeWorkItem(&CmpDelayDerefKCBWorkItem,
|
||||||
|
CmpDelayDerefKCBWorker,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Setup the DPC and timer for it */
|
||||||
|
KeInitializeDpc(&CmpDelayDerefKCBDpc, CmpDelayDerefKCBDpcRoutine, NULL);
|
||||||
|
KeInitializeTimer(&CmpDelayDerefKCBTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpDelayDerefKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
|
||||||
|
{
|
||||||
|
USHORT OldRefCount, NewRefCount;
|
||||||
|
LARGE_INTEGER Timeout;
|
||||||
|
PCM_DELAY_DEREF_KCB_ITEM Entry;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Get the previous reference count */
|
||||||
|
OldRefCount = Kcb->RefCount;
|
||||||
|
|
||||||
|
/* Write the new one */
|
||||||
|
NewRefCount = (USHORT)InterlockedCompareExchange((PLONG)&Kcb->RefCount,
|
||||||
|
OldRefCount - 1,
|
||||||
|
OldRefCount);
|
||||||
|
if (NewRefCount != OldRefCount) return;
|
||||||
|
|
||||||
|
/* Allocate a delay item */
|
||||||
|
Entry = CmpAllocateDelayItem();
|
||||||
|
if (!Entry) return;
|
||||||
|
|
||||||
|
/* Set the KCB */
|
||||||
|
Entry->Kcb = Kcb;
|
||||||
|
|
||||||
|
/* Acquire the delayed deref table lock */
|
||||||
|
KeAcquireGuardedMutex(&CmpDelayDerefKCBLock);
|
||||||
|
|
||||||
|
/* Insert the entry into the list */
|
||||||
|
InsertTailList(&CmpDelayDerefKCBListHead, &Entry->ListEntry);
|
||||||
|
|
||||||
|
/* Check if we need to enable anything */
|
||||||
|
if (!CmpDelayDerefKCBWorkItemActive)
|
||||||
|
{
|
||||||
|
/* Yes, we have no work item, setup the interval */
|
||||||
|
Timeout.QuadPart = CmpDelayDerefKCBIntervalInSeconds * -10000000;
|
||||||
|
KeSetTimer(&CmpDelayDerefKCBTimer, Timeout, &CmpDelayDerefKCBDpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the table lock */
|
||||||
|
KeReleaseGuardedMutex(&CmpDelayDerefKCBLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpArmDelayedCloseTimer(VOID)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER Timeout;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Setup the interval */
|
||||||
|
Timeout.QuadPart = CmpDelayCloseIntervalInSeconds * -10000000;
|
||||||
|
KeSetTimer(&CmpDelayCloseTimer, Timeout, &CmpDelayCloseDpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpAddToDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb,
|
||||||
|
IN BOOLEAN LockHeldExclusively)
|
||||||
|
{
|
||||||
|
ULONG i;
|
||||||
|
ULONG OldRefCount, NewRefCount;
|
||||||
|
PCM_DELAYED_CLOSE_ENTRY Entry;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
|
||||||
|
(CmpTestRegistryLockExclusive() == TRUE));
|
||||||
|
|
||||||
|
/* Make sure it's valid */
|
||||||
|
if (Kcb->DelayedCloseIndex != CmpDelayedCloseSize) ASSERT(FALSE);
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
|
ASSERT(Kcb->RefCount == 0);
|
||||||
|
ASSERT(IsListEmpty(&Kcb->KeyBodyListHead) == TRUE);
|
||||||
|
for (i = 0; i < 4; i++) ASSERT(Kcb->KeyBodyArray[i] == NULL);
|
||||||
|
|
||||||
|
/* Allocate a delay item */
|
||||||
|
Entry = CmpAllocateDelayItem();
|
||||||
|
if (!Entry)
|
||||||
|
{
|
||||||
|
/* Cleanup immediately */
|
||||||
|
CmpCleanUpKcbCacheWithLock(Kcb, LockHeldExclusively);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (Kcb->InDelayClose) ASSERT(FALSE);
|
||||||
|
|
||||||
|
/* Get the previous reference count */
|
||||||
|
OldRefCount = Kcb->InDelayClose;
|
||||||
|
ASSERT(OldRefCount == 0);
|
||||||
|
|
||||||
|
/* Write the new one */
|
||||||
|
NewRefCount = InterlockedCompareExchange((PLONG)&Kcb->InDelayClose,
|
||||||
|
1,
|
||||||
|
OldRefCount);
|
||||||
|
if (NewRefCount != OldRefCount) ASSERT(FALSE);
|
||||||
|
|
||||||
|
/* Reset the delayed close index */
|
||||||
|
Kcb->DelayedCloseIndex = 0;
|
||||||
|
|
||||||
|
/* Set up the close entry */
|
||||||
|
Kcb->DelayCloseEntry = Entry;
|
||||||
|
Entry->KeyControlBlock = Kcb;
|
||||||
|
|
||||||
|
/* Increase the number of elements */
|
||||||
|
InterlockedIncrement((PLONG)&CmpDelayedCloseElements);
|
||||||
|
|
||||||
|
/* Acquire the delayed close table lock */
|
||||||
|
KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
|
||||||
|
|
||||||
|
/* Insert the entry into the list */
|
||||||
|
InsertHeadList(&CmpDelayedLRUListHead, &Entry->DelayedLRUList);
|
||||||
|
|
||||||
|
/* Check if we need to enable anything */
|
||||||
|
if ((CmpDelayedCloseElements > CmpDelayedCloseSize) &&
|
||||||
|
!(CmpDelayCloseWorkItemActive))
|
||||||
|
{
|
||||||
|
/* Yes, we have too many elements to close, and no work item */
|
||||||
|
CmpArmDelayedCloseTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the table lock */
|
||||||
|
KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpRemoveFromDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb)
|
||||||
|
{
|
||||||
|
PCM_DELAYED_CLOSE_ENTRY Entry;
|
||||||
|
ULONG NewRefCount, OldRefCount;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
|
ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
|
||||||
|
(CmpTestRegistryLockExclusive() == TRUE));
|
||||||
|
if (Kcb->DelayedCloseIndex == CmpDelayedCloseSize) ASSERT(FALSE);
|
||||||
|
|
||||||
|
/* Get the entry and lock the table */
|
||||||
|
Entry = Kcb->DelayCloseEntry;
|
||||||
|
ASSERT(Entry);
|
||||||
|
KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
|
||||||
|
|
||||||
|
/* Remove the entry */
|
||||||
|
RemoveEntryList(&Entry->DelayedLRUList);
|
||||||
|
|
||||||
|
/* Release the lock */
|
||||||
|
KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
|
||||||
|
|
||||||
|
/* Free the entry */
|
||||||
|
CmpFreeDelayItem(Entry);
|
||||||
|
|
||||||
|
/* Reduce the number of elements */
|
||||||
|
InterlockedDecrement((PLONG)&CmpDelayedCloseElements);
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (!Kcb->InDelayClose) ASSERT(FALSE);
|
||||||
|
|
||||||
|
/* Get the old reference count */
|
||||||
|
OldRefCount = Kcb->InDelayClose;
|
||||||
|
ASSERT(OldRefCount == 1);
|
||||||
|
|
||||||
|
/* Set it to 0 */
|
||||||
|
NewRefCount = InterlockedCompareExchange((PLONG)&Kcb->InDelayClose,
|
||||||
|
0,
|
||||||
|
OldRefCount);
|
||||||
|
if (NewRefCount != OldRefCount) ASSERT(FALSE);
|
||||||
|
|
||||||
|
/* Remove the link to the entry */
|
||||||
|
Kcb->DelayCloseEntry = NULL;
|
||||||
|
|
||||||
|
/* Set new delay size and remove the delete flag */
|
||||||
|
Kcb->DelayedCloseIndex = CmpDelayedCloseSize;
|
||||||
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
* PROJECT: ReactOS Kernel
|
* PROJECT: ReactOS Kernel
|
||||||
* LICENSE: GPL - See COPYING in the top level directory
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
* FILE: ntoskrnl/config/cmkcbncb.c
|
* FILE: ntoskrnl/config/cmkcbncb.c
|
||||||
* PURPOSE: Configuration Manager - Key Control and Name Control Blocks
|
* PURPOSE: Routines for handling KCBs, NCBs, as well as key hashes.
|
||||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES ******************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
#include "ntoskrnl.h"
|
#include <ntoskrnl.h>
|
||||||
#include "cm.h"
|
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include "debug.h"
|
#include <debug.h>
|
||||||
|
#include "cm.h"
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
@ -19,159 +19,530 @@ ULONG CmpHashTableSize = 2048;
|
||||||
PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable;
|
PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable;
|
||||||
PCM_NAME_HASH_TABLE_ENTRY CmpNameCacheTable;
|
PCM_NAME_HASH_TABLE_ENTRY CmpNameCacheTable;
|
||||||
|
|
||||||
LIST_ENTRY CmpFreeKCBListHead;
|
|
||||||
|
|
||||||
BOOLEAN CmpAllocInited;
|
|
||||||
KGUARDED_MUTEX CmpAllocBucketLock, CmpDelayAllocBucketLock;
|
|
||||||
WORK_QUEUE_ITEM CmpDelayDerefKCBWorkItem;
|
|
||||||
LIST_ENTRY CmpFreeDelayItemsListHead;
|
|
||||||
|
|
||||||
ULONG CmpDelayedCloseSize;
|
|
||||||
ULONG CmpDelayedCloseElements;
|
|
||||||
KGUARDED_MUTEX CmpDelayedCloseTableLock;
|
|
||||||
BOOLEAN CmpDelayCloseWorkItemActive;
|
|
||||||
WORK_QUEUE_ITEM CmpDelayCloseWorkItem;
|
|
||||||
LIST_ENTRY CmpDelayedLRUListHead;
|
|
||||||
ULONG CmpDelayCloseIntervalInSeconds = 5;
|
|
||||||
KDPC CmpDelayCloseDpc;
|
|
||||||
KTIMER CmpDelayCloseTimer;
|
|
||||||
|
|
||||||
KGUARDED_MUTEX CmpDelayDerefKCBLock;
|
|
||||||
BOOLEAN CmpDelayDerefKCBWorkItemActive;
|
|
||||||
LIST_ENTRY CmpDelayDerefKCBListHead;
|
|
||||||
ULONG CmpDelayDerefKCBIntervalInSeconds = 5;
|
|
||||||
KDPC CmpDelayDerefKCBDpc;
|
|
||||||
KTIMER CmpDelayDerefKCBTimer;
|
|
||||||
|
|
||||||
BOOLEAN CmpHoldLazyFlush;
|
BOOLEAN CmpHoldLazyFlush;
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
CmpDelayCloseDpcRoutine(IN PKDPC Dpc,
|
|
||||||
IN PVOID DeferredContext,
|
|
||||||
IN PVOID SystemArgument1,
|
|
||||||
IN PVOID SystemArgument2)
|
|
||||||
{
|
|
||||||
/* Sanity check */
|
|
||||||
ASSERT(CmpDelayCloseWorkItemActive);
|
|
||||||
|
|
||||||
/* Queue the work item */
|
|
||||||
ExQueueWorkItem(&CmpDelayCloseWorkItem, DelayedWorkQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
CmpDelayCloseWorker(IN PVOID Context)
|
|
||||||
{
|
|
||||||
PAGED_CODE();
|
|
||||||
|
|
||||||
/* Sanity check */
|
|
||||||
ASSERT(CmpDelayCloseWorkItemActive);
|
|
||||||
|
|
||||||
/* FIXME: TODO */
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
CmpInitializeCache(VOID)
|
CmpInitializeCache(VOID)
|
||||||
{
|
{
|
||||||
ULONG Length;
|
ULONG Length, i;
|
||||||
|
|
||||||
/* Calculate length for the table */
|
/* Calculate length for the table */
|
||||||
Length = CmpHashTableSize * sizeof(PCM_KEY_HASH);
|
Length = CmpHashTableSize * sizeof(CM_KEY_HASH_TABLE_ENTRY);
|
||||||
|
|
||||||
/* Allocate it */
|
/* Allocate it */
|
||||||
CmpCacheTable = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
|
CmpCacheTable = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
|
||||||
if (!CmpCacheTable) KeBugCheck(CONFIG_INITIALIZATION_FAILED);
|
if (!CmpCacheTable)
|
||||||
|
{
|
||||||
|
/* Take the system down */
|
||||||
|
KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 3, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zero out the table */
|
||||||
RtlZeroMemory(CmpCacheTable, Length);
|
RtlZeroMemory(CmpCacheTable, Length);
|
||||||
|
|
||||||
|
/* Initialize the locks */
|
||||||
|
for (i = 0;i < CmpHashTableSize; i++)
|
||||||
|
{
|
||||||
|
/* Setup the pushlock */
|
||||||
|
ExInitializePushLock((PULONG_PTR)&CmpCacheTable[i].Lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate length for the name cache */
|
/* Calculate length for the name cache */
|
||||||
Length = CmpHashTableSize * sizeof(PCM_NAME_HASH);
|
Length = CmpHashTableSize * sizeof(CM_NAME_HASH_TABLE_ENTRY);
|
||||||
|
|
||||||
/* Now allocate the name cache table */
|
/* Now allocate the name cache table */
|
||||||
CmpNameCacheTable = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
|
CmpNameCacheTable = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
|
||||||
if (!CmpCacheTable) KeBugCheck(CONFIG_INITIALIZATION_FAILED);
|
if (!CmpNameCacheTable)
|
||||||
|
{
|
||||||
|
/* Take the system down */
|
||||||
|
KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 3, 3, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zero out the table */
|
||||||
RtlZeroMemory(CmpNameCacheTable, Length);
|
RtlZeroMemory(CmpNameCacheTable, Length);
|
||||||
|
|
||||||
/* Setup the delayed close lock */
|
/* Initialize the locks */
|
||||||
KeInitializeGuardedMutex(&CmpDelayedCloseTableLock);
|
for (i = 0;i < CmpHashTableSize; i++)
|
||||||
|
|
||||||
/* Setup the work item */
|
|
||||||
ExInitializeWorkItem(&CmpDelayCloseWorkItem, CmpDelayCloseWorker, NULL);
|
|
||||||
|
|
||||||
/* Setup the DPC and its timer */
|
|
||||||
KeInitializeDpc(&CmpDelayCloseDpc, CmpDelayCloseDpcRoutine, NULL);
|
|
||||||
KeInitializeTimer(&CmpDelayCloseTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
CmpInitCmPrivateDelayAlloc(VOID)
|
|
||||||
{
|
|
||||||
/* Initialize the delay allocation list and lock */
|
|
||||||
KeInitializeGuardedMutex(&CmpDelayAllocBucketLock);
|
|
||||||
InitializeListHead(&CmpFreeDelayItemsListHead);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
CmpInitCmPrivateAlloc(VOID)
|
|
||||||
{
|
|
||||||
/* Make sure we didn't already do this */
|
|
||||||
if (!CmpAllocInited)
|
|
||||||
{
|
{
|
||||||
/* Setup the lock and list */
|
/* Setup the pushlock */
|
||||||
KeInitializeGuardedMutex(&CmpAllocBucketLock);
|
ExInitializePushLock((PULONG_PTR)&CmpNameCacheTable[i].Lock);
|
||||||
InitializeListHead(&CmpFreeKCBListHead);
|
}
|
||||||
CmpAllocInited = TRUE;
|
|
||||||
|
/* Setup the delayed close table */
|
||||||
|
CmpInitializeDelayedCloseTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpRemoveKeyHash(IN PCM_KEY_HASH KeyHash)
|
||||||
|
{
|
||||||
|
PCM_KEY_HASH *Prev;
|
||||||
|
PCM_KEY_HASH Current;
|
||||||
|
|
||||||
|
/* Lookup all the keys in this index entry */
|
||||||
|
Prev = &GET_HASH_ENTRY(CmpCacheTable, KeyHash->ConvKey).Entry;
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* Save the current one and make sure it's valid */
|
||||||
|
Current = *Prev;
|
||||||
|
ASSERT(Current != NULL);
|
||||||
|
|
||||||
|
/* Check if it matches */
|
||||||
|
if (Current == KeyHash)
|
||||||
|
{
|
||||||
|
/* Then write the previous one */
|
||||||
|
*Prev = Current->NextHash;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, keep going */
|
||||||
|
Prev = &Current->NextHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PCM_KEY_CONTROL_BLOCK
|
||||||
|
NTAPI
|
||||||
|
CmpInsertKeyHash(IN PCM_KEY_HASH KeyHash,
|
||||||
|
IN BOOLEAN IsFake)
|
||||||
|
{
|
||||||
|
ULONG i;
|
||||||
|
PCM_KEY_HASH Entry;
|
||||||
|
|
||||||
|
/* Get the hash index */
|
||||||
|
i = GET_HASH_INDEX(KeyHash->ConvKey);
|
||||||
|
|
||||||
|
/* If this is a fake key, increase the key cell to use the parent data */
|
||||||
|
if (IsFake) KeyHash->KeyCell++;
|
||||||
|
|
||||||
|
/* Loop the hash table */
|
||||||
|
Entry = CmpCacheTable[i].Entry;
|
||||||
|
while (Entry)
|
||||||
|
{
|
||||||
|
/* Check if this matches */
|
||||||
|
if ((KeyHash->ConvKey == Entry->ConvKey) &&
|
||||||
|
(KeyHash->KeyCell == Entry->KeyCell) &&
|
||||||
|
(KeyHash->KeyHive == Entry->KeyHive))
|
||||||
|
{
|
||||||
|
/* Return it */
|
||||||
|
return CONTAINING_RECORD(Entry, CM_KEY_CONTROL_BLOCK, KeyHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep looping */
|
||||||
|
Entry = Entry->NextHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No entry found, add this one and return NULL since none existed */
|
||||||
|
KeyHash->NextHash = CmpCacheTable[i].Entry;
|
||||||
|
CmpCacheTable[i].Entry = KeyHash;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PCM_NAME_CONTROL_BLOCK
|
||||||
|
NTAPI
|
||||||
|
CmpGetNameControlBlock(IN PUNICODE_STRING NodeName)
|
||||||
|
{
|
||||||
|
PCM_NAME_CONTROL_BLOCK Ncb = NULL;
|
||||||
|
ULONG ConvKey = 0;
|
||||||
|
PWCHAR p, pp;
|
||||||
|
ULONG i;
|
||||||
|
BOOLEAN IsCompressed = TRUE, Found = FALSE;
|
||||||
|
PCM_NAME_HASH HashEntry;
|
||||||
|
ULONG Length, NcbSize;
|
||||||
|
|
||||||
|
/* Loop the name */
|
||||||
|
p = NodeName->Buffer;
|
||||||
|
for (i = 0; i < NodeName->Length; i += sizeof(WCHAR))
|
||||||
|
{
|
||||||
|
/* Make sure it's not a slash */
|
||||||
|
if (*p != OBJ_NAME_PATH_SEPARATOR)
|
||||||
|
{
|
||||||
|
/* Add it to the hash */
|
||||||
|
ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next character */
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set assumed lengh and loop to check */
|
||||||
|
Length = NodeName->Length / sizeof(WCHAR);
|
||||||
|
for (i = 0; i < (NodeName->Length / sizeof(WCHAR)); i++)
|
||||||
|
{
|
||||||
|
/* Check if this is a valid character */
|
||||||
|
if (*NodeName->Buffer > (UCHAR)-1)
|
||||||
|
{
|
||||||
|
/* This is the actual size, and we know we're not compressed */
|
||||||
|
Length = NodeName->Length;
|
||||||
|
IsCompressed = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock the NCB entry */
|
||||||
|
CmpAcquireNcbLockExclusiveByKey(ConvKey);
|
||||||
|
|
||||||
|
/* Get the hash entry */
|
||||||
|
HashEntry = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry;
|
||||||
|
while (HashEntry)
|
||||||
|
{
|
||||||
|
/* Get the current NCB */
|
||||||
|
Ncb = CONTAINING_RECORD(HashEntry, CM_NAME_CONTROL_BLOCK, NameHash);
|
||||||
|
|
||||||
|
/* Check if the hash matches */
|
||||||
|
if ((ConvKey = HashEntry->ConvKey) && (Length = Ncb->NameLength))
|
||||||
|
{
|
||||||
|
/* Assume success */
|
||||||
|
Found = TRUE;
|
||||||
|
|
||||||
|
/* If the NCB is compressed, do a compressed name compare */
|
||||||
|
if (Ncb->Compressed)
|
||||||
|
{
|
||||||
|
/* Compare names */
|
||||||
|
if (CmpCompareCompressedName(NodeName, Ncb->Name, Length))
|
||||||
|
{
|
||||||
|
/* We failed */
|
||||||
|
Found = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Do a manual compare */
|
||||||
|
p = NodeName->Buffer;
|
||||||
|
pp = Ncb->Name;
|
||||||
|
for (i = 0; i < Ncb->NameLength; i += sizeof(WCHAR))
|
||||||
|
{
|
||||||
|
/* Compare the character */
|
||||||
|
if (RtlUpcaseUnicodeChar(*p) != RtlUpcaseUnicodeChar(*pp))
|
||||||
|
{
|
||||||
|
/* Failed */
|
||||||
|
Found = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next chars */
|
||||||
|
p++;
|
||||||
|
pp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we found a name */
|
||||||
|
if (Found)
|
||||||
|
{
|
||||||
|
/* Reference it */
|
||||||
|
Ncb->RefCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Go to the next hash */
|
||||||
|
HashEntry = HashEntry->NextHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we didn't find it */
|
||||||
|
if (!Found)
|
||||||
|
{
|
||||||
|
/* Allocate one */
|
||||||
|
NcbSize = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + Length;
|
||||||
|
Ncb = ExAllocatePoolWithTag(PagedPool, NcbSize, TAG_CM);
|
||||||
|
if (!Ncb)
|
||||||
|
{
|
||||||
|
/* Release the lock and fail */
|
||||||
|
CmpReleaseNcbLockByKey(ConvKey);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear it out */
|
||||||
|
RtlZeroMemory(Ncb, NcbSize);
|
||||||
|
|
||||||
|
/* Check if the name was compressed */
|
||||||
|
if (IsCompressed)
|
||||||
|
{
|
||||||
|
/* Copy the compressed name */
|
||||||
|
Ncb->Compressed = TRUE;
|
||||||
|
for (i = 0; i < Length; i++)
|
||||||
|
{
|
||||||
|
/* Copy Unicode to ANSI */
|
||||||
|
((PCHAR)Ncb->Name)[i] = (CHAR)RtlUpcaseUnicodeChar(NodeName->Buffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Copy the name directly */
|
||||||
|
Ncb->Compressed = FALSE;
|
||||||
|
for (i = 0; i < Length; i++)
|
||||||
|
{
|
||||||
|
/* Copy each unicode character */
|
||||||
|
Ncb->Name[i] = RtlUpcaseUnicodeChar(NodeName->Buffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the rest of the NCB */
|
||||||
|
Ncb->ConvKey = ConvKey;
|
||||||
|
Ncb->RefCount++;
|
||||||
|
Ncb->NameLength = Length;
|
||||||
|
|
||||||
|
/* Insert the name in the hash table */
|
||||||
|
HashEntry = &Ncb->NameHash;
|
||||||
|
HashEntry->NextHash = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry;
|
||||||
|
GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry = HashEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release NCB lock */
|
||||||
|
CmpReleaseNcbLockByKey(ConvKey);
|
||||||
|
|
||||||
|
/* Return the NCB found */
|
||||||
|
return Ncb;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpRemoveKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
|
||||||
|
{
|
||||||
|
/* Make sure that the registry and KCB are utterly locked */
|
||||||
|
ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
|
||||||
|
(CmpTestRegistryLockExclusive() == TRUE));
|
||||||
|
|
||||||
|
/* Remove the key hash */
|
||||||
|
CmpRemoveKeyHash(&Kcb->KeyHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpDereferenceNameControlBlockWithLock(IN PCM_NAME_CONTROL_BLOCK Ncb)
|
||||||
|
{
|
||||||
|
PCM_NAME_HASH Current, *Next;
|
||||||
|
|
||||||
|
/* Lock the NCB */
|
||||||
|
CmpAcquireNcbLockExclusive(Ncb);
|
||||||
|
|
||||||
|
/* Decrease the reference count */
|
||||||
|
if (!(--Ncb->RefCount))
|
||||||
|
{
|
||||||
|
/* Find the NCB in the table */
|
||||||
|
Next = &GET_HASH_ENTRY(CmpNameCacheTable, Ncb->ConvKey).Entry;
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* Check the current entry */
|
||||||
|
Current = *Next;
|
||||||
|
ASSERT(Current != NULL);
|
||||||
|
if (Current == &Ncb->NameHash)
|
||||||
|
{
|
||||||
|
/* Unlink it */
|
||||||
|
*Next = Current->NextHash;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get to the next one */
|
||||||
|
Next = &Current->NextHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Found it, now free it */
|
||||||
|
ExFreePool(Ncb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the lock */
|
||||||
|
CmpReleaseNcbLock(Ncb);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
CmpReferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
|
||||||
|
{
|
||||||
|
/* Check if this is the KCB's first reference */
|
||||||
|
if (Kcb->RefCount == 0)
|
||||||
|
{
|
||||||
|
/* Check if the KCB is locked in shared mode */
|
||||||
|
if (!CmpIsKcbLockedExclusive(Kcb))
|
||||||
|
{
|
||||||
|
/* Convert it to exclusive */
|
||||||
|
if (!CmpTryToConvertKcbSharedToExclusive(Kcb))
|
||||||
|
{
|
||||||
|
/* Set the delayed close index so that we can be ignored */
|
||||||
|
Kcb->DelayedCloseIndex = 1;
|
||||||
|
|
||||||
|
/* Increase the reference count while we release the lock */
|
||||||
|
InterlockedIncrement((PLONG)&Kcb->RefCount);
|
||||||
|
|
||||||
|
/* Go from shared to exclusive */
|
||||||
|
CmpConvertKcbSharedToExclusive(Kcb);
|
||||||
|
|
||||||
|
/* Decrement the reference count; the lock is now held again */
|
||||||
|
InterlockedDecrement((PLONG)&Kcb->RefCount);
|
||||||
|
|
||||||
|
/* Check if we still control the index */
|
||||||
|
if (Kcb->DelayedCloseIndex == 1)
|
||||||
|
{
|
||||||
|
/* Reset it */
|
||||||
|
Kcb->DelayedCloseIndex = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT((Kcb->DelayedCloseIndex == CmpDelayedCloseSize) ||
|
||||||
|
(Kcb->DelayedCloseIndex == 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increase the reference count */
|
||||||
|
if (InterlockedIncrement((PLONG)&Kcb->RefCount) == 0)
|
||||||
|
{
|
||||||
|
/* We've overflown to 64K references, bail out */
|
||||||
|
InterlockedDecrement((PLONG)&Kcb->RefCount);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this was the last close index */
|
||||||
|
if (!Kcb->DelayedCloseIndex)
|
||||||
|
{
|
||||||
|
/* Check if the KCB is locked in shared mode */
|
||||||
|
if (!CmpIsKcbLockedExclusive(Kcb))
|
||||||
|
{
|
||||||
|
/* Convert it to exclusive */
|
||||||
|
if (!CmpTryToConvertKcbSharedToExclusive(Kcb))
|
||||||
|
{
|
||||||
|
/* Go from shared to exclusive */
|
||||||
|
CmpConvertKcbSharedToExclusive(Kcb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're still the last entry, remove us */
|
||||||
|
if (!Kcb->DelayedCloseIndex) CmpRemoveFromDelayedClose(Kcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpCleanUpKcbValueCache(IN PCM_KEY_CONTROL_BLOCK Kcb)
|
||||||
|
{
|
||||||
|
PULONG_PTR CachedList;
|
||||||
|
ULONG i;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
|
||||||
|
(CmpTestRegistryLockExclusive() == TRUE));
|
||||||
|
|
||||||
|
/* Check if the value list is cached */
|
||||||
|
if (CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList))
|
||||||
|
{
|
||||||
|
/* Get the cache list */
|
||||||
|
CachedList = (PULONG_PTR)CMP_GET_CACHED_DATA(Kcb->ValueCache.ValueList);
|
||||||
|
for (i = 0; i < Kcb->ValueCache.Count; i++)
|
||||||
|
{
|
||||||
|
/* Check if this cell is cached */
|
||||||
|
if (CMP_IS_CELL_CACHED(CachedList[i]))
|
||||||
|
{
|
||||||
|
/* Free it */
|
||||||
|
ExFreePool((PVOID)CMP_GET_CACHED_CELL(CachedList[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now free the list */
|
||||||
|
ExFreePool((PVOID)CMP_GET_CACHED_CELL(Kcb->ValueCache.ValueList));
|
||||||
|
Kcb->ValueCache.ValueList = HCELL_NIL;
|
||||||
|
}
|
||||||
|
else if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND)
|
||||||
|
{
|
||||||
|
/* This is a sym link, check if there's only one reference left */
|
||||||
|
if ((((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb)->RefCount == 1) &&
|
||||||
|
!(((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb)->Delete))
|
||||||
|
{
|
||||||
|
/* Disable delay close for the KCB */
|
||||||
|
((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb)->ExtFlags |= CM_KCB_NO_DELAY_CLOSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dereference the KCB */
|
||||||
|
CmpDelayDerefKeyControlBlock((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb);
|
||||||
|
Kcb->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
CmpDelayDerefKCBDpcRoutine(IN PKDPC Dpc,
|
CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb,
|
||||||
IN PVOID DeferredContext,
|
IN BOOLEAN LockHeldExclusively)
|
||||||
IN PVOID SystemArgument1,
|
|
||||||
IN PVOID SystemArgument2)
|
|
||||||
{
|
|
||||||
/* Sanity check */
|
|
||||||
ASSERT(CmpDelayDerefKCBWorkItemActive);
|
|
||||||
|
|
||||||
/* Queue the work item */
|
|
||||||
ExQueueWorkItem(&CmpDelayDerefKCBWorkItem, DelayedWorkQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
CmpDelayDerefKCBWorker(IN PVOID Context)
|
|
||||||
{
|
{
|
||||||
|
PCM_KEY_CONTROL_BLOCK Parent;
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity checks */
|
||||||
ASSERT(CmpDelayDerefKCBWorkItemActive);
|
ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
|
||||||
|
(CmpTestRegistryLockExclusive() == TRUE));
|
||||||
|
ASSERT(Kcb->RefCount == 0);
|
||||||
|
|
||||||
/* FIXME: TODO */
|
/* Cleanup the value cache */
|
||||||
ASSERT(FALSE);
|
CmpCleanUpKcbValueCache(Kcb);
|
||||||
|
|
||||||
|
/* Reference the NCB */
|
||||||
|
CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock);
|
||||||
|
|
||||||
|
/* Check if we have an index hint block and free it */
|
||||||
|
if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) ExFreePool(Kcb->IndexHint);
|
||||||
|
|
||||||
|
/* Check if we were already deleted */
|
||||||
|
Parent = Kcb->ParentKcb;
|
||||||
|
if (!Kcb->Delete) CmpRemoveKeyControlBlock(Kcb);
|
||||||
|
|
||||||
|
/* Free the KCB as well */
|
||||||
|
CmpFreeKeyControlBlock(Kcb);
|
||||||
|
|
||||||
|
/* Check if we have a parent */
|
||||||
|
if (Parent)
|
||||||
|
{
|
||||||
|
/* Dereference the parent */
|
||||||
|
LockHeldExclusively ?
|
||||||
|
CmpDereferenceKeyControlBlockWithLock(Kcb,LockHeldExclusively) :
|
||||||
|
CmpDelayDerefKeyControlBlock(Kcb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
CmpInitDelayDerefKCBEngine(VOID)
|
CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb,
|
||||||
|
IN BOOLEAN LockHeldExclusively)
|
||||||
{
|
{
|
||||||
/* Initialize lock and list */
|
/* Sanity check */
|
||||||
KeInitializeGuardedMutex(&CmpDelayDerefKCBLock);
|
ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
|
||||||
InitializeListHead(&CmpDelayDerefKCBListHead);
|
(CmpTestRegistryLockExclusive() == TRUE));
|
||||||
|
|
||||||
/* Setup the work item */
|
/* Check if this is the last reference */
|
||||||
ExInitializeWorkItem(&CmpDelayDerefKCBWorkItem,
|
if (InterlockedDecrement((PLONG)&Kcb->RefCount) == 0)
|
||||||
CmpDelayDerefKCBWorker,
|
{
|
||||||
NULL);
|
/* Check if we should do a direct delete */
|
||||||
|
if (((CmpHoldLazyFlush) &&
|
||||||
|
!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) &&
|
||||||
|
!(Kcb->Flags & KEY_SYM_LINK)) ||
|
||||||
|
(Kcb->ExtFlags & CM_KCB_NO_DELAY_CLOSE) ||
|
||||||
|
(Kcb->Delete))
|
||||||
|
{
|
||||||
|
/* Clean up the KCB*/
|
||||||
|
CmpCleanUpKcbCacheWithLock(Kcb, LockHeldExclusively);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, use delayed close */
|
||||||
|
CmpAddToDelayedClose(Kcb, LockHeldExclusively);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup the DPC and timer for it */
|
VOID
|
||||||
KeInitializeDpc(&CmpDelayDerefKCBDpc, CmpDelayDerefKCBDpcRoutine, NULL);
|
NTAPI
|
||||||
KeInitializeTimer(&CmpDelayDerefKCBTimer);
|
InitializeKCBKeyBodyList(IN PCM_KEY_CONTROL_BLOCK Kcb)
|
||||||
|
{
|
||||||
|
/* Initialize the list */
|
||||||
|
InitializeListHead(&Kcb->KeyBodyListHead);
|
||||||
|
|
||||||
|
/* Clear the bodies */
|
||||||
|
Kcb->KeyBodyArray[0] =
|
||||||
|
Kcb->KeyBodyArray[1] =
|
||||||
|
Kcb->KeyBodyArray[2] =
|
||||||
|
Kcb->KeyBodyArray[3] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PCM_KEY_CONTROL_BLOCK
|
PCM_KEY_CONTROL_BLOCK
|
||||||
|
@ -183,6 +554,213 @@ CmpCreateKeyControlBlock(IN PHHIVE Hive,
|
||||||
IN ULONG Flags,
|
IN ULONG Flags,
|
||||||
IN PUNICODE_STRING KeyName)
|
IN PUNICODE_STRING KeyName)
|
||||||
{
|
{
|
||||||
/* Temporary hack */
|
PCM_KEY_CONTROL_BLOCK Kcb, FoundKcb = NULL;
|
||||||
return (PVOID)1;
|
UNICODE_STRING NodeName;
|
||||||
|
ULONG ConvKey = 0, i;
|
||||||
|
BOOLEAN IsFake, HashLock;
|
||||||
|
PWCHAR p;
|
||||||
|
|
||||||
|
/* Make sure we own this hive in case it's being unloaded */
|
||||||
|
if ((Hive->HiveFlags & HIVE_IS_UNLOADING) &&
|
||||||
|
(((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread()))
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this is a fake KCB */
|
||||||
|
IsFake = Flags & CMP_CREATE_FAKE_KCB ? TRUE : FALSE;
|
||||||
|
|
||||||
|
/* If we have a parent, use its ConvKey */
|
||||||
|
if (Parent) ConvKey = Parent->ConvKey;
|
||||||
|
|
||||||
|
/* Make a copy of the name */
|
||||||
|
NodeName = *KeyName;
|
||||||
|
|
||||||
|
/* Remove leading slash */
|
||||||
|
while ((NodeName.Length) && (*NodeName.Buffer == OBJ_NAME_PATH_SEPARATOR))
|
||||||
|
{
|
||||||
|
/* Move the buffer by one */
|
||||||
|
NodeName.Buffer++;
|
||||||
|
NodeName.Length -= sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we didn't get just a slash or something */
|
||||||
|
ASSERT(NodeName.Length > 0);
|
||||||
|
|
||||||
|
/* Now setup the hash */
|
||||||
|
p = NodeName.Buffer;
|
||||||
|
for (i = 0; i < NodeName.Length; i += sizeof(WCHAR))
|
||||||
|
{
|
||||||
|
/* Make sure it's a valid character */
|
||||||
|
if (*p != OBJ_NAME_PATH_SEPARATOR)
|
||||||
|
{
|
||||||
|
/* Add this key to the hash */
|
||||||
|
ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move on */
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate the KCB */
|
||||||
|
Kcb = CmpAllocateKeyControlBlock();
|
||||||
|
if (!Kcb) return NULL;
|
||||||
|
|
||||||
|
/* Initailize the key list */
|
||||||
|
InitializeKCBKeyBodyList(Kcb);
|
||||||
|
|
||||||
|
/* Set it up */
|
||||||
|
Kcb->Delete = FALSE;
|
||||||
|
Kcb->RefCount = 1;
|
||||||
|
Kcb->KeyHive = Hive;
|
||||||
|
Kcb->KeyCell = Index;
|
||||||
|
Kcb->ConvKey = ConvKey;
|
||||||
|
Kcb->DelayedCloseIndex = CmpDelayedCloseSize;
|
||||||
|
Kcb->InDelayClose = 0;
|
||||||
|
|
||||||
|
/* Check if we have two hash entires */
|
||||||
|
HashLock = Flags & CMP_LOCK_HASHES_FOR_KCB ? TRUE : FALSE;
|
||||||
|
if (HashLock)
|
||||||
|
{
|
||||||
|
/* Not yet implemented */
|
||||||
|
KeBugCheck(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we already have a KCB */
|
||||||
|
FoundKcb = CmpInsertKeyHash(&Kcb->KeyHash, IsFake);
|
||||||
|
if (FoundKcb)
|
||||||
|
{
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT(!FoundKcb->Delete);
|
||||||
|
|
||||||
|
/* Free the one we allocated and reference this one */
|
||||||
|
CmpFreeKeyControlBlock(Kcb);
|
||||||
|
Kcb = FoundKcb;
|
||||||
|
if (!CmpReferenceKeyControlBlock(Kcb))
|
||||||
|
{
|
||||||
|
/* We got too many handles */
|
||||||
|
ASSERT(Kcb->RefCount + 1 != 0);
|
||||||
|
Kcb = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check if we're not creating a fake one, but it used to be fake */
|
||||||
|
if ((Kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) && !(IsFake))
|
||||||
|
{
|
||||||
|
/* Set the hive and cell */
|
||||||
|
Kcb->KeyHive = Hive;
|
||||||
|
Kcb->KeyCell = Index;
|
||||||
|
|
||||||
|
/* This means that our current information is invalid */
|
||||||
|
Kcb->ExtFlags = CM_KCB_INVALID_CACHED_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we didn't have any valid data */
|
||||||
|
if (!(Kcb->ExtFlags & (CM_KCB_NO_SUBKEY |
|
||||||
|
CM_KCB_SUBKEY_ONE |
|
||||||
|
CM_KCB_SUBKEY_HINT)))
|
||||||
|
{
|
||||||
|
/* Calculate the index hint */
|
||||||
|
Kcb->SubKeyCount = Node->SubKeyCounts[Stable] +
|
||||||
|
Node->SubKeyCounts[Volatile];
|
||||||
|
|
||||||
|
/* Cached information is now valid */
|
||||||
|
Kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the other data */
|
||||||
|
Kcb->KcbLastWriteTime = Node->LastWriteTime;
|
||||||
|
Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
|
||||||
|
Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
|
||||||
|
Kcb->KcbMaxValueDataLen = Node->MaxValueDataLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No KCB, do we have a parent? */
|
||||||
|
if (Parent)
|
||||||
|
{
|
||||||
|
/* Reference the parent */
|
||||||
|
if (((Parent->TotalLevels + 1) < 512) &&
|
||||||
|
(CmpReferenceKeyControlBlock(Parent)))
|
||||||
|
{
|
||||||
|
/* Link it */
|
||||||
|
Kcb->ParentKcb = Parent;
|
||||||
|
Kcb->TotalLevels = Parent->TotalLevels + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Remove the KCB and free it */
|
||||||
|
CmpRemoveKeyControlBlock(Kcb);
|
||||||
|
CmpFreeKeyControlBlock(Kcb);
|
||||||
|
Kcb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No parent, this is the root node */
|
||||||
|
Kcb->ParentKcb = NULL;
|
||||||
|
Kcb->TotalLevels = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we have a KCB */
|
||||||
|
if (Kcb)
|
||||||
|
{
|
||||||
|
/* Get the NCB */
|
||||||
|
Kcb->NameBlock = CmpGetNameControlBlock(&NodeName);
|
||||||
|
if (Kcb->NameBlock)
|
||||||
|
{
|
||||||
|
/* Fill it out */
|
||||||
|
Kcb->ValueCache.Count = Node->ValueList.Count;
|
||||||
|
Kcb->ValueCache.ValueList = Node->ValueList.List;
|
||||||
|
Kcb->Flags = Node->Flags;
|
||||||
|
Kcb->ExtFlags = 0;
|
||||||
|
Kcb->DelayedCloseIndex = CmpDelayedCloseSize;
|
||||||
|
|
||||||
|
/* Remember if this is a fake key */
|
||||||
|
if (IsFake) Kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST;
|
||||||
|
|
||||||
|
/* Setup the other data */
|
||||||
|
Kcb->SubKeyCount = Node->SubKeyCounts[Stable] +
|
||||||
|
Node->SubKeyCounts[Volatile];
|
||||||
|
Kcb->KcbLastWriteTime = Node->LastWriteTime;
|
||||||
|
Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
|
||||||
|
Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
|
||||||
|
Kcb->KcbMaxValueDataLen = (USHORT)Node->MaxValueDataLen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Dereference the KCB */
|
||||||
|
CmpDereferenceKeyControlBlockWithLock(Parent, FALSE);
|
||||||
|
|
||||||
|
/* Remove the KCB and free it */
|
||||||
|
CmpRemoveKeyControlBlock(Kcb);
|
||||||
|
CmpFreeKeyControlBlock(Kcb);
|
||||||
|
Kcb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT((!Kcb) || (Kcb->Delete == FALSE));
|
||||||
|
|
||||||
|
/* Check if we had locked the hashes */
|
||||||
|
if (HashLock)
|
||||||
|
{
|
||||||
|
/* Not yet implemented: Unlock hashes */
|
||||||
|
KeBugCheck(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the KCB */
|
||||||
|
return Kcb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
EnlistKeyBodyWithKCB(IN PCM_KEY_BODY KeyBody,
|
||||||
|
IN ULONG Flags)
|
||||||
|
{
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,12 @@ KGUARDED_MUTEX CmpSelfHealQueueLock;
|
||||||
LIST_ENTRY CmpSelfHealQueueListHead;
|
LIST_ENTRY CmpSelfHealQueueListHead;
|
||||||
PEPROCESS CmpSystemProcess;
|
PEPROCESS CmpSystemProcess;
|
||||||
BOOLEAN HvShutdownComplete;
|
BOOLEAN HvShutdownComplete;
|
||||||
|
PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller;
|
||||||
|
BOOLEAN CmpFlushStarveWriters;
|
||||||
|
BOOLEAN CmpFlushOnLockRelease;
|
||||||
|
BOOLEAN CmpSpecialBootCondition;
|
||||||
|
BOOLEAN CmpNoWrite;
|
||||||
|
BOOLEAN CmpForceForceFlush;
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
@ -704,7 +710,7 @@ CmpCreateRegistryRoot(VOID)
|
||||||
|
|
||||||
/* Initialize the object */
|
/* Initialize the object */
|
||||||
#if 0
|
#if 0
|
||||||
RootKey->Type = TAG('k', 'v', '0', '2';
|
RootKey->Type = TAG('k', 'v', '0', '2');
|
||||||
RootKey->KeyControlBlock = Kcb;
|
RootKey->KeyControlBlock = Kcb;
|
||||||
RootKey->NotifyBlock = NULL;
|
RootKey->NotifyBlock = NULL;
|
||||||
RootKey->ProcessID = PsGetCurrentProcessId();
|
RootKey->ProcessID = PsGetCurrentProcessId();
|
||||||
|
@ -721,7 +727,7 @@ CmpCreateRegistryRoot(VOID)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Insert it into the object list head */
|
/* Insert it into the object list head */
|
||||||
EnlistKeyBodyWithKCB(RootKey, 0);
|
EnlistKeyBodyWithKeyObject(RootKey, 0);
|
||||||
|
|
||||||
/* Insert the key into the namespace */
|
/* Insert the key into the namespace */
|
||||||
Status = ObInsertObject(RootKey,
|
Status = ObInsertObject(RootKey,
|
||||||
|
@ -978,3 +984,80 @@ CmInitSystem1(VOID)
|
||||||
/* If we got here, all went well */
|
/* If we got here, all went well */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpLockRegistryExclusive(VOID)
|
||||||
|
{
|
||||||
|
/* Enter a critical region and lock the registry */
|
||||||
|
KeEnterCriticalRegion();
|
||||||
|
ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT(CmpFlushStarveWriters == 0);
|
||||||
|
RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
CmpTestRegistryLock(VOID)
|
||||||
|
{
|
||||||
|
/* Test the lock */
|
||||||
|
return (BOOLEAN)ExIsResourceAcquiredSharedLite(&CmpRegistryLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
CmpTestRegistryLockExclusive(VOID)
|
||||||
|
{
|
||||||
|
/* Test the lock */
|
||||||
|
return ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CmpUnlockRegistry(VOID)
|
||||||
|
{
|
||||||
|
/* Sanity check */
|
||||||
|
CMP_ASSERT_REGISTRY_LOCK();
|
||||||
|
|
||||||
|
/* Check if we should flush the registry */
|
||||||
|
if (CmpFlushOnLockRelease)
|
||||||
|
{
|
||||||
|
/* The registry should be exclusively locked for this */
|
||||||
|
CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
|
||||||
|
|
||||||
|
/* Flush the registry */
|
||||||
|
CmpFlushEntireRegistry(TRUE);
|
||||||
|
CmpFlushOnLockRelease = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the lock and leave the critical region */
|
||||||
|
ExReleaseResourceLite(&CmpRegistryLock);
|
||||||
|
KeLeaveCriticalRegion();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
CmpFlushEntireRegistry(IN BOOLEAN ForceFlush)
|
||||||
|
{
|
||||||
|
BOOLEAN Flushed = TRUE;
|
||||||
|
|
||||||
|
/* Make sure that the registry isn't read-only now */
|
||||||
|
if (CmpNoWrite) return TRUE;
|
||||||
|
|
||||||
|
/* Otherwise, acquire the hive list lock and disable force flush */
|
||||||
|
CmpForceForceFlush = FALSE;
|
||||||
|
ExAcquirePushLockShared(&CmpHiveListHeadLock);
|
||||||
|
|
||||||
|
/* Check if the hive list isn't empty */
|
||||||
|
if (!IsListEmpty(&CmpHiveListHead))
|
||||||
|
{
|
||||||
|
/* FIXME: TODO */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the lock and return the flush state */
|
||||||
|
ExReleasePushLock(&CmpHiveListHeadLock);
|
||||||
|
return Flushed;
|
||||||
|
}
|
||||||
|
|
|
@ -110,12 +110,14 @@
|
||||||
<file>cmhardwr.c</file>
|
<file>cmhardwr.c</file>
|
||||||
</directory>
|
</directory>
|
||||||
</if>
|
</if>
|
||||||
|
<file>cmalloc.c</file>
|
||||||
<file>cmapi.c</file>
|
<file>cmapi.c</file>
|
||||||
<file>cmboot.c</file>
|
<file>cmboot.c</file>
|
||||||
<file>cmcheck.c</file>
|
<file>cmcheck.c</file>
|
||||||
<file>cmcontrl.c</file>
|
<file>cmcontrl.c</file>
|
||||||
<file>cmconfig.c</file>
|
<file>cmconfig.c</file>
|
||||||
<file>cmdata.c</file>
|
<file>cmdata.c</file>
|
||||||
|
<file>cmdelay.c</file>
|
||||||
<file>cmindex.c</file>
|
<file>cmindex.c</file>
|
||||||
<file>cminit.c</file>
|
<file>cminit.c</file>
|
||||||
<file>cmhook.c</file>
|
<file>cmhook.c</file>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue