Author: fireball
Date: Mon Oct 29 17:44:26 2007
New Revision: 29954
URL:
http://svn.reactos.org/svn/reactos?rev=29954&view=rev
Log:
- 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.
Added:
trunk/reactos/ntoskrnl/config/cmalloc.c (with props)
trunk/reactos/ntoskrnl/config/cmdelay.c (with props)
Modified:
trunk/reactos/ntoskrnl/cm/registry.c
trunk/reactos/ntoskrnl/config/cm.h
trunk/reactos/ntoskrnl/config/cm_x.h
trunk/reactos/ntoskrnl/config/cmkcbncb.c
trunk/reactos/ntoskrnl/config/cmsysini.c
trunk/reactos/ntoskrnl/ntoskrnl.rbuild
Modified: trunk/reactos/ntoskrnl/cm/registry.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/cm/registry.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/cm/registry.c (original)
+++ trunk/reactos/ntoskrnl/cm/registry.c Mon Oct 29 17:44:26 2007
@@ -226,8 +226,8 @@
/* Precondition: Must not hold the hive lock CmpRegistryLock */
VOID
NTAPI
-EnlistKeyBodyWithKCB(IN PKEY_OBJECT KeyObject,
- IN ULONG Flags)
+EnlistKeyBodyWithKeyObject(IN PKEY_OBJECT KeyObject,
+ IN ULONG Flags)
{
/* Acquire hive lock */
KeEnterCriticalRegion();
Modified: trunk/reactos/ntoskrnl/config/cm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cm.h?rev=2…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cm.h (original)
+++ trunk/reactos/ntoskrnl/config/cm.h Mon Oct 29 17:44:26 2007
@@ -307,6 +307,15 @@
ULONG Reserved;
PVOID AllocPage;
} 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
@@ -788,6 +797,9 @@
VOID
);
+//
+// Delay Functions
+//
PVOID
NTAPI
CmpAllocateDelayItem(
@@ -798,6 +810,29 @@
NTAPI
CmpFreeDelayItem(
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
);
//
@@ -814,22 +849,44 @@
IN PUNICODE_STRING KeyName
);
-VOID
-NTAPI
-CmpDereferenceKcbWithLock(
+PCM_KEY_CONTROL_BLOCK
+NTAPI
+CmpAllocateKeyControlBlock(
+ VOID
+);
+
+VOID
+NTAPI
+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 BOOLEAN LockHeldExclusively
+);
+
+VOID
+NTAPI
EnlistKeyBodyWithKCB(
-#if 0
IN PCM_KEY_BODY KeyObject,
-#else
- IN PKEY_OBJECT KeyObject,
-#endif
IN ULONG Flags
+);
+
+VOID
+NTAPI
+EnlistKeyBodyWithKeyObject(
+ IN PKEY_OBJECT KeyObject,
+ IN ULONG Flags
);
NTSTATUS
@@ -1276,6 +1333,7 @@
extern BOOLEAN ExpInTextModeSetup;
extern BOOLEAN InitIsWinPEMode;
extern ULONG CmpHashTableSize;
+extern ULONG CmpDelayedCloseSize, CmpDelayedCloseIndex;
//
// Inlined functions
Modified: trunk/reactos/ntoskrnl/config/cm_x.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cm_x.h?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cm_x.h (original)
+++ trunk/reactos/ntoskrnl/config/cm_x.h Mon Oct 29 17:44:26 2007
@@ -200,6 +200,18 @@
}
//
+// 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
//
#define CmpAcquireNcbLockExclusive(n) \
@@ -209,6 +221,15 @@
}
//
+// Exclusively acquires an NCB by key
+//
+#define CmpAcquireNcbLockExclusiveByKey(k) \
+{ \
+ ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \
+ (k)).Lock); \
+}
+
+//
// Releases an exlusively or shared acquired NCB
//
#define CmpReleaseNcbLock(k) \
@@ -216,3 +237,12 @@
ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \
(k)->ConvKey).Lock); \
}
+
+//
+// Releases an exlusively or shared acquired NCB by key
+//
+#define CmpReleaseNcbLockByKey(k) \
+{ \
+ ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \
+ (k)).Lock); \
+}
Added: trunk/reactos/ntoskrnl/config/cmalloc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmalloc.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmalloc.c (added)
+++ trunk/reactos/ntoskrnl/config/cmalloc.c Mon Oct 29 17:44:26 2007
@@ -1,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(a)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);
+}
Propchange: trunk/reactos/ntoskrnl/config/cmalloc.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/ntoskrnl/config/cmdelay.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmdelay.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmdelay.c (added)
+++ trunk/reactos/ntoskrnl/config/cmdelay.c Mon Oct 29 17:44:26 2007
@@ -1,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(a)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;
+}
+
Propchange: trunk/reactos/ntoskrnl/config/cmdelay.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/ntoskrnl/config/cmkcbncb.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmkcbncb.c…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmkcbncb.c (original)
+++ trunk/reactos/ntoskrnl/config/cmkcbncb.c Mon Oct 29 17:44:26 2007
@@ -2,16 +2,16 @@
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* 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(a)reactos.org)
*/
/* INCLUDES ******************************************************************/
-#include "ntoskrnl.h"
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
#include "cm.h"
-#define NDEBUG
-#include "debug.h"
/* GLOBALS *******************************************************************/
@@ -19,159 +19,530 @@
PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable;
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;
/* 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
-NTAPI
CmpInitializeCache(VOID)
{
- ULONG Length;
-
+ ULONG Length, i;
+
/* Calculate length for the table */
- Length = CmpHashTableSize * sizeof(PCM_KEY_HASH);
-
+ Length = CmpHashTableSize * sizeof(CM_KEY_HASH_TABLE_ENTRY);
+
/* Allocate it */
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);
-
+
+ /* Initialize the locks */
+ for (i = 0;i < CmpHashTableSize; i++)
+ {
+ /* Setup the pushlock */
+ ExInitializePushLock((PULONG_PTR)&CmpCacheTable[i].Lock);
+ }
+
/* 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 */
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);
- /* Setup the delayed close lock */
- KeInitializeGuardedMutex(&CmpDelayedCloseTableLock);
-
- /* 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 */
- KeInitializeGuardedMutex(&CmpAllocBucketLock);
- InitializeListHead(&CmpFreeKCBListHead);
- CmpAllocInited = TRUE;
- }
-}
-
-VOID
-NTAPI
-CmpDelayDerefKCBDpcRoutine(IN PKDPC Dpc,
- IN PVOID DeferredContext,
- IN PVOID SystemArgument1,
- IN PVOID SystemArgument2)
-{
+ /* Initialize the locks */
+ for (i = 0;i < CmpHashTableSize; i++)
+ {
+ /* Setup the pushlock */
+ ExInitializePushLock((PULONG_PTR)&CmpNameCacheTable[i].Lock);
+ }
+
+ /* 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(CmpDelayDerefKCBWorkItemActive);
-
- /* Queue the work item */
- ExQueueWorkItem(&CmpDelayDerefKCBWorkItem, DelayedWorkQueue);
-}
-
-VOID
-NTAPI
-CmpDelayDerefKCBWorker(IN PVOID Context)
-{
+ 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
+NTAPI
+CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb,
+ IN BOOLEAN LockHeldExclusively)
+{
+ PCM_KEY_CONTROL_BLOCK Parent;
PAGED_CODE();
+ /* Sanity checks */
+ ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
+ (CmpTestRegistryLockExclusive() == TRUE));
+ ASSERT(Kcb->RefCount == 0);
+
+ /* Cleanup the value cache */
+ 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
+NTAPI
+CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb,
+ IN BOOLEAN LockHeldExclusively)
+{
/* 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);
+ ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
+ (CmpTestRegistryLockExclusive() == TRUE));
+
+ /* Check if this is the last reference */
+ if (InterlockedDecrement((PLONG)&Kcb->RefCount) == 0)
+ {
+ /* 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);
+ }
+ }
+}
+
+VOID
+NTAPI
+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
@@ -183,6 +554,213 @@
IN ULONG Flags,
IN PUNICODE_STRING KeyName)
{
- /* Temporary hack */
- return (PVOID)1;
-}
+ PCM_KEY_CONTROL_BLOCK Kcb, FoundKcb = NULL;
+ 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);
+}
+
Modified: trunk/reactos/ntoskrnl/config/cmsysini.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmsysini.c…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmsysini.c (original)
+++ trunk/reactos/ntoskrnl/config/cmsysini.c Mon Oct 29 17:44:26 2007
@@ -17,6 +17,12 @@
LIST_ENTRY CmpSelfHealQueueListHead;
PEPROCESS CmpSystemProcess;
BOOLEAN HvShutdownComplete;
+PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller;
+BOOLEAN CmpFlushStarveWriters;
+BOOLEAN CmpFlushOnLockRelease;
+BOOLEAN CmpSpecialBootCondition;
+BOOLEAN CmpNoWrite;
+BOOLEAN CmpForceForceFlush;
/* FUNCTIONS *****************************************************************/
@@ -704,7 +710,7 @@
/* Initialize the object */
#if 0
- RootKey->Type = TAG('k', 'v', '0', '2';
+ RootKey->Type = TAG('k', 'v', '0', '2');
RootKey->KeyControlBlock = Kcb;
RootKey->NotifyBlock = NULL;
RootKey->ProcessID = PsGetCurrentProcessId();
@@ -721,7 +727,7 @@
#endif
/* Insert it into the object list head */
- EnlistKeyBodyWithKCB(RootKey, 0);
+ EnlistKeyBodyWithKeyObject(RootKey, 0);
/* Insert the key into the namespace */
Status = ObInsertObject(RootKey,
@@ -978,3 +984,80 @@
/* If we got here, all went well */
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;
+}
Modified: trunk/reactos/ntoskrnl/ntoskrnl.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ntoskrnl.rbuild?r…
==============================================================================
--- trunk/reactos/ntoskrnl/ntoskrnl.rbuild (original)
+++ trunk/reactos/ntoskrnl/ntoskrnl.rbuild Mon Oct 29 17:44:26 2007
@@ -110,12 +110,14 @@
<file>cmhardwr.c</file>
</directory>
</if>
+ <file>cmalloc.c</file>
<file>cmapi.c</file>
<file>cmboot.c</file>
<file>cmcheck.c</file>
<file>cmcontrl.c</file>
<file>cmconfig.c</file>
<file>cmdata.c</file>
+ <file>cmdelay.c</file>
<file>cmindex.c</file>
<file>cminit.c</file>
<file>cmhook.c</file>