https://git.reactos.org/?p=reactos.git;a=commitdiff;h=08fcf0c58bd24395b1769be5f57cf3332aa4aaa5

commit 08fcf0c58bd24395b1769be5f57cf3332aa4aaa5
Author:     George Bișoc <george.bi...@reactos.org>
AuthorDate: Thu Feb 16 21:21:31 2023 +0100
Commit:     George Bișoc <george.bi...@reactos.org>
CommitDate: Sun Oct 1 20:06:01 2023 +0200

    [NTOS:CM] Implement locking/unlocking of KCBs in an array
    
    The CmpUnLockKcbArray, CmpLockKcbArray and CmpBuildAndLockKcbArray routines
    help us to lock KCBs within array so that information remains consistent 
when
    we are doing a cache lookup during a parse procedure of the registry 
database.
---
 ntoskrnl/config/cmkcbncb.c     | 148 +++++++++++++++++++++++++++++++++++++++++
 ntoskrnl/include/internal/cm.h |   1 -
 2 files changed, 148 insertions(+), 1 deletion(-)

diff --git a/ntoskrnl/config/cmkcbncb.c b/ntoskrnl/config/cmkcbncb.c
index 2241d530ae8..659aeea4ddb 100644
--- a/ntoskrnl/config/cmkcbncb.c
+++ b/ntoskrnl/config/cmkcbncb.c
@@ -1134,6 +1134,154 @@ DelistKeyBodyFromKCB(IN PCM_KEY_BODY KeyBody,
     if (!LockHeld) CmpReleaseKcbLock(KeyBody->KeyControlBlock);
 }
 
+VOID
+CmpUnLockKcbArray(
+    _In_ PULONG KcbArray)
+{
+    ULONG i;
+
+    /* Release the locked KCBs in reverse order */
+    for (i = KcbArray[0]; i > 0; i--)
+    {
+        CmpReleaseKcbLockByIndex(KcbArray[i]);
+    }
+}
+
+static
+VOID
+CmpLockKcbArray(
+    _In_ PULONG KcbArray,
+    _In_ ULONG KcbLockFlags)
+{
+    ULONG i;
+
+    /* Lock the KCBs */
+    for (i = 1; i <= KcbArray[0]; i++)
+    {
+        if (KcbLockFlags & CMP_LOCK_KCB_ARRAY_EXCLUSIVE)
+        {
+            CmpAcquireKcbLockExclusiveByIndex(KcbArray[i]);
+        }
+        else // CMP_LOCK_KCB_ARRAY_SHARED
+        {
+            CmpAcquireKcbLockSharedByIndex(KcbArray[i]);
+        }
+    }
+}
+
+static
+VOID
+CmpSortKcbArray(
+    _Inout_ PULONG KcbArray)
+{
+    ULONG i, j, k, KcbCount;
+
+    /* Ensure we don't go above the limit of KCBs we can hold */
+    KcbCount = KcbArray[0];
+    ASSERT(KcbCount < CMP_KCBS_IN_ARRAY_LIMIT);
+
+    /* Exchange-Sort the array in ascending order. Complexity: O[n^2] */
+    for (i = 1; i <= KcbCount; i++)
+    {
+        for (j = i + 1; j <= KcbCount; j++)
+        {
+            if (KcbArray[i] > KcbArray[j])
+            {
+                ULONG Temp = KcbArray[i];
+                KcbArray[i] = KcbArray[j];
+                KcbArray[j] = Temp;
+            }
+        }
+    }
+
+    /* Now remove any duplicated indices on the sorted array if any */
+    for (i = 1; i <= KcbCount; i++)
+    {
+        for (j = i + 1; j <= KcbCount; j++)
+        {
+            if (KcbArray[i] == KcbArray[j])
+            {
+                for (k = j; k <= KcbCount; k++)
+                {
+                    KcbArray[k - 1] = KcbArray[k];
+                }
+
+                j--;
+                KcbCount--;
+            }
+        }
+    }
+
+    /* Update the KCB count */
+    KcbArray[0] = KcbCount;
+}
+
+PULONG
+NTAPI
+CmpBuildAndLockKcbArray(
+    _In_ PCM_HASH_CACHE_STACK HashCacheStack,
+    _In_ ULONG KcbLockFlags,
+    _In_ PCM_KEY_CONTROL_BLOCK Kcb,
+    _Inout_ PULONG OuterStackArray,
+    _In_ ULONG TotalRemainingSubkeys,
+    _In_ ULONG MatchRemainSubkeyLevel)
+{
+    ULONG KcbIndex = 1, HashStackIndex, TotalRemaining;
+    PULONG LockedKcbs = NULL;
+    PCM_KEY_CONTROL_BLOCK ParentKcb = Kcb->ParentKcb;;
+
+    /* These parameters are expected */
+    ASSERT(HashCacheStack != NULL);
+    ASSERT(Kcb != NULL);
+    ASSERT(OuterStackArray != NULL);
+
+    /*
+     * Ensure when we build an array of KCBs to lock, that
+     * we don't go beyond the boundary the limit allows us
+     * to. 1 is the current KCB we would want to lock
+     * alongside with the remaining key levels in the formula.
+     */
+    TotalRemaining = (1 + TotalRemainingSubkeys) - MatchRemainSubkeyLevel;
+    ASSERT(TotalRemaining <= CMP_KCBS_IN_ARRAY_LIMIT);
+
+    /* Count the parent if we have one */
+    if (ParentKcb)
+    {
+        /* Ensure we are still below the limit and add the parent to KCBs to 
lock */
+        if (TotalRemainingSubkeys == MatchRemainSubkeyLevel)
+        {
+            TotalRemaining++;
+            ASSERT(TotalRemaining <= CMP_KCBS_IN_ARRAY_LIMIT);
+            OuterStackArray[KcbIndex++] = GET_HASH_INDEX(ParentKcb->ConvKey);
+        }
+    }
+
+    /* Add the current KCB */
+    OuterStackArray[KcbIndex++] = GET_HASH_INDEX(Kcb->ConvKey);
+
+    /* Loop over the hash stack and grab the hashes for locking (they will be 
converted to indices) */
+    for (HashStackIndex = 0;
+         HashStackIndex < TotalRemainingSubkeys;
+         HashStackIndex++)
+    {
+        OuterStackArray[KcbIndex++] = 
GET_HASH_INDEX(HashCacheStack[HashStackIndex].ConvKey);
+    }
+
+    /*
+     * Store how many KCBs we need to lock and sort the array.
+     * Remove any duplicated indices from the array if any.
+     */
+    OuterStackArray[0] = KcbIndex - 1;
+    CmpSortKcbArray(OuterStackArray);
+
+    /* Lock them */
+    CmpLockKcbArray(OuterStackArray, KcbLockFlags);
+
+    /* Give the locked KCBs to caller now */
+    LockedKcbs = OuterStackArray;
+    return LockedKcbs;
+}
+
 VOID
 NTAPI
 CmpFlushNotifiesOnKeyBodyList(IN PCM_KEY_CONTROL_BLOCK Kcb,
diff --git a/ntoskrnl/include/internal/cm.h b/ntoskrnl/include/internal/cm.h
index da8bad2dbd0..36b640f2034 100644
--- a/ntoskrnl/include/internal/cm.h
+++ b/ntoskrnl/include/internal/cm.h
@@ -1015,7 +1015,6 @@ DelistKeyBodyFromKCB(
 );
 
 VOID
-NTAPI
 CmpUnLockKcbArray(
     _In_ PULONG LockedKcbs
 );

Reply via email to