- DBGKD_WAIT_STATE_CHANGE64 is used in KD protocol 5, not number 6 that we use. Proto...
[reactos.git] / reactos / lib / cmlib / hivecell.c
index 6fcbbb2..994ca98 100644 (file)
@@ -9,14 +9,17 @@
 #define NDEBUG
 #include <debug.h>
 
-static PHCELL __inline CMAPI
+static __inline PHCELL CMAPI
 HvpGetCellHeader(
    PHHIVE RegistryHive,
    HCELL_INDEX CellIndex)
 {
    PVOID Block;
 
-   ASSERT(CellIndex != HCELL_NULL);
+   CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx\n",
+       __FUNCTION__, RegistryHive, CellIndex);
+
+   ASSERT(CellIndex != HCELL_NIL);
    if (!RegistryHive->Flat)
    {
       ULONG CellType;
@@ -27,14 +30,14 @@ HvpGetCellHeader(
       CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
       CellOffset = (CellIndex & HCELL_OFFSET_MASK) >> HCELL_OFFSET_SHIFT;
       ASSERT(CellBlock < RegistryHive->Storage[CellType].Length);
-      Block = (PVOID)RegistryHive->Storage[CellType].BlockList[CellBlock].Block;
+      Block = (PVOID)RegistryHive->Storage[CellType].BlockList[CellBlock].BlockAddress;
       ASSERT(Block != NULL);
       return (PVOID)((ULONG_PTR)Block + CellOffset);
    }
    else
    {
-      ASSERT((CellIndex & HCELL_TYPE_MASK) == HvStable);
-      return (PVOID)((ULONG_PTR)RegistryHive->HiveHeader + HV_BLOCK_SIZE +
+      ASSERT((CellIndex & HCELL_TYPE_MASK) == Stable);
+      return (PVOID)((ULONG_PTR)RegistryHive->BaseBlock + HV_BLOCK_SIZE +
                      CellIndex);
    }
 }
@@ -43,26 +46,24 @@ BOOLEAN CMAPI
 HvIsCellAllocated(IN PHHIVE RegistryHive,
                   IN HCELL_INDEX CellIndex)
 {
-    ULONG Type, Block;
-
-    /* If it's a flat hive, the cell is always allocated */
-    if (RegistryHive->Flat) return TRUE;
-
-    /* Otherwise, get the type and make sure it's valid */
-    Type = HvGetCellType(CellIndex);
-    if (((CellIndex % ~HCELL_TYPE_MASK) > RegistryHive->Storage[Type].Length) ||
-        (CellIndex % (RegistryHive->Version >= 2 ? 8 : 16)))
-    {
-        /* Invalid cell index */
-        return FALSE;
-    }
-
-    /* Try to get the cell block */
-    Block = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
-    if (RegistryHive->Storage[Type].BlockList[Block].Block) return TRUE;
-
-    /* No valid block, fail */
-    return FALSE;
+   ULONG Type, Block;
+
+   /* If it's a flat hive, the cell is always allocated */
+   if (RegistryHive->Flat)
+      return TRUE;
+
+   /* Otherwise, get the type and make sure it's valid */
+   Type = HvGetCellType(CellIndex);
+   Block = HvGetCellBlock(CellIndex);
+   if (Block >= RegistryHive->Storage[Type].Length)
+      return FALSE;
+
+   /* Try to get the cell block */
+   if (RegistryHive->Storage[Type].BlockList[Block].BlockAddress)
+      return TRUE;
+
+   /* No valid block, fail */
+   return FALSE;
 }
 
 PVOID CMAPI
@@ -73,11 +74,12 @@ HvGetCell(
    return (PVOID)(HvpGetCellHeader(RegistryHive, CellIndex) + 1);
 }
 
-static LONG __inline CMAPI
+static __inline LONG CMAPI
 HvpGetCellFullSize(
    PHHIVE RegistryHive,
    PVOID Cell)
 {
+   UNREFERENCED_PARAMETER(RegistryHive);
    return ((PHCELL)Cell - 1)->Size;
 }
 
@@ -85,55 +87,64 @@ LONG CMAPI
 HvGetCellSize(IN PHHIVE Hive,
               IN PVOID Address)
 {
-    PHCELL CellHeader;
-    LONG Size;
+   PHCELL CellHeader;
+   LONG Size;
+
+   UNREFERENCED_PARAMETER(Hive);
 
-    CellHeader = (PHCELL)Address - 1;
-    Size = CellHeader->Size * -1;
-    Size -= sizeof(HCELL);
-    return Size;
+   CellHeader = (PHCELL)Address - 1;
+   Size = CellHeader->Size * -1;
+   Size -= sizeof(HCELL);
+   return Size;
 }
 
-VOID CMAPI
+BOOLEAN CMAPI
 HvMarkCellDirty(
    PHHIVE RegistryHive,
-   HCELL_INDEX CellIndex)
+   HCELL_INDEX CellIndex,
+   BOOLEAN HoldingLock)
 {
-   LONG CellSize;
    ULONG CellBlock;
    ULONG CellLastBlock;
 
    ASSERT(RegistryHive->ReadOnly == FALSE);
 
-   if ((CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT != HvStable)
-      return;
+   CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx, HoldingLock %b\n",
+       __FUNCTION__, RegistryHive, CellIndex, HoldingLock);
+
+   if ((CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT != Stable)
+      return FALSE;
 
    CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
    CellLastBlock = ((CellIndex + HV_BLOCK_SIZE - 1) & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
 
-   CellSize = HvpGetCellFullSize(RegistryHive, HvGetCell(RegistryHive, CellIndex));
-   if (CellSize < 0)
-      CellSize = -CellSize;
-
    RtlSetBits(&RegistryHive->DirtyVector,
               CellBlock, CellLastBlock - CellBlock);
+   return TRUE;
 }
 
 BOOLEAN CMAPI
 HvIsCellDirty(IN PHHIVE Hive,
               IN HCELL_INDEX Cell)
 {
-    /* Sanity checks */
-    ASSERT(Hive->ReadOnly == FALSE);
+   BOOLEAN IsDirty = FALSE;
+
+   /* Sanity checks */
+   ASSERT(Hive->ReadOnly == FALSE);
+
+   /* Volatile cells are always "dirty" */
+   if (HvGetCellType(Cell) == Volatile)
+      return TRUE;
 
-    /* Volatile cells are always "dirty" */
-    if (HvGetCellType(Cell) == HvVolatile) return TRUE;
+   /* Check if the dirty bit is set */
+   if (RtlCheckBit(&Hive->DirtyVector, Cell / HV_BLOCK_SIZE))
+       IsDirty = TRUE;
 
-    /* Check if the dirty bit is set */
-    return RtlCheckBit(&Hive->DirtyVector, Cell / HV_BLOCK_SIZE);
+   /* Return result as boolean*/
+   return IsDirty;
 }
 
-static ULONG __inline CMAPI
+static __inline ULONG CMAPI
 HvpComputeFreeListIndex(
    ULONG Size)
 {
@@ -175,7 +186,7 @@ HvpAddFree(
    HCELL_INDEX FreeIndex)
 {
    PHCELL_INDEX FreeBlockData;
-   HV_STORAGE_TYPE Storage;
+   HSTORAGE_TYPE Storage;
    ULONG Index;
 
    ASSERT(RegistryHive != NULL);
@@ -201,8 +212,8 @@ HvpRemoveFree(
 {
    PHCELL_INDEX FreeCellData;
    PHCELL_INDEX pFreeCellOffset;
-   HV_STORAGE_TYPE Storage;
-   ULONG Index;
+   HSTORAGE_TYPE Storage;
+   ULONG Index, FreeListIndex;
 
    ASSERT(RegistryHive->ReadOnly == FALSE);
 
@@ -210,7 +221,7 @@ HvpRemoveFree(
    Index = HvpComputeFreeListIndex((ULONG)CellBlock->Size);
 
    pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[Index];
-   while (*pFreeCellOffset != HCELL_NULL)
+   while (*pFreeCellOffset != HCELL_NIL)
    {
       FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
       if (*pFreeCellOffset == CellIndex)
@@ -221,14 +232,32 @@ HvpRemoveFree(
       pFreeCellOffset = FreeCellData;
    }
 
-   //ASSERT(FALSE);
+   /* Something bad happened, print a useful trace info and bugcheck */
+   CMLTRACE(CMLIB_HCELL_DEBUG, "-- beginning of HvpRemoveFree trace --\n");
+   CMLTRACE(CMLIB_HCELL_DEBUG, "block we are about to free: %08x\n", CellIndex);
+   CMLTRACE(CMLIB_HCELL_DEBUG, "chosen free list index: %d\n", Index);
+   for (FreeListIndex = 0; FreeListIndex < 24; FreeListIndex++)
+   {
+      CMLTRACE(CMLIB_HCELL_DEBUG, "free list [%d]: ", FreeListIndex);
+      pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[FreeListIndex];
+      while (*pFreeCellOffset != HCELL_NIL)
+      {
+         CMLTRACE(CMLIB_HCELL_DEBUG, "%08x ", *pFreeCellOffset);
+         FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
+         pFreeCellOffset = FreeCellData;
+      }
+      CMLTRACE(CMLIB_HCELL_DEBUG, "\n");
+   }
+   CMLTRACE(CMLIB_HCELL_DEBUG, "-- end of HvpRemoveFree trace --\n");
+
+   ASSERT(FALSE);
 }
 
 static HCELL_INDEX CMAPI
 HvpFindFree(
    PHHIVE RegistryHive,
    ULONG Size,
-   HV_STORAGE_TYPE Storage)
+   HSTORAGE_TYPE Storage)
 {
    PHCELL_INDEX FreeCellData;
    HCELL_INDEX FreeCellOffset;
@@ -238,7 +267,7 @@ HvpFindFree(
    for (Index = HvpComputeFreeListIndex(Size); Index < 24; Index++)
    {
       pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[Index];
-      while (*pFreeCellOffset != HCELL_NULL)
+      while (*pFreeCellOffset != HCELL_NIL)
       {
          FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
          if ((ULONG)HvpGetCellFullSize(RegistryHive, FreeCellData) >= Size)
@@ -251,7 +280,7 @@ HvpFindFree(
       }
    }
 
-   return HCELL_NULL;
+   return HCELL_NIL;
 }
 
 NTSTATUS CMAPI
@@ -269,15 +298,15 @@ HvpCreateHiveFreeCellList(
    /* Initialize the free cell list */
    for (Index = 0; Index < 24; Index++)
    {
-      Hive->Storage[HvStable].FreeDisplay[Index] = HCELL_NULL;
-      Hive->Storage[HvVolatile].FreeDisplay[Index] = HCELL_NULL;
+      Hive->Storage[Stable].FreeDisplay[Index] = HCELL_NIL;
+      Hive->Storage[Volatile].FreeDisplay[Index] = HCELL_NIL;
    }
 
    BlockOffset = 0;
    BlockIndex = 0;
-   while (BlockIndex < Hive->Storage[HvStable].Length)
+   while (BlockIndex < Hive->Storage[Stable].Length)
    {
-      Bin = (PHBIN)Hive->Storage[HvStable].BlockList[BlockIndex].Bin;
+      Bin = (PHBIN)Hive->Storage[Stable].BlockList[BlockIndex].BinAddress;
 
       /* Search free blocks and add to list */
       FreeOffset = sizeof(HBIN);
@@ -309,7 +338,8 @@ HCELL_INDEX CMAPI
 HvAllocateCell(
    PHHIVE RegistryHive,
    SIZE_T Size,
-   HV_STORAGE_TYPE Storage)
+   HSTORAGE_TYPE Storage,
+   HCELL_INDEX Vicinity)
 {
    PHCELL FreeCell;
    HCELL_INDEX FreeCellOffset;
@@ -318,6 +348,9 @@ HvAllocateCell(
 
    ASSERT(RegistryHive->ReadOnly == FALSE);
 
+   CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, Size %x, %s, Vicinity %08lx\n",
+       __FUNCTION__, RegistryHive, Size, (Storage == 0) ? "Stable" : "Volatile", Vicinity);
+
    /* Round to 16 bytes multiple. */
    Size = ROUND_UP(Size + sizeof(HCELL), 16);
 
@@ -325,11 +358,11 @@ HvAllocateCell(
    FreeCellOffset = HvpFindFree(RegistryHive, Size, Storage);
 
    /* If no free cell was found we need to extend the hive file. */
-   if (FreeCellOffset == HCELL_NULL)
+   if (FreeCellOffset == HCELL_NIL)
    {
       Bin = HvpAddBin(RegistryHive, Size, Storage);
       if (Bin == NULL)
-         return HCELL_NULL;
+         return HCELL_NIL;
       FreeCellOffset = Bin->FileOffset + sizeof(HBIN);
       FreeCellOffset |= Storage << HCELL_TYPE_SHIFT;
    }
@@ -337,22 +370,30 @@ HvAllocateCell(
    FreeCell = HvpGetCellHeader(RegistryHive, FreeCellOffset);
 
    /* Split the block in two parts */
-   /* FIXME: There is some minimal cell size that we must respect. */
-   if ((ULONG)FreeCell->Size > Size + sizeof(HCELL_INDEX))
+
+   /* The free block that is created has to be at least
+      sizeof(HCELL) + sizeof(HCELL_INDEX) big, so that free
+      cell list code can work. Moreover we round cell sizes
+      to 16 bytes, so creating a smaller block would result in
+      a cell that would never be allocated. */
+   if ((ULONG)FreeCell->Size > Size + 16)
    {
       NewCell = (PHCELL)((ULONG_PTR)FreeCell + Size);
       NewCell->Size = FreeCell->Size - Size;
       FreeCell->Size = Size;
       HvpAddFree(RegistryHive, NewCell, FreeCellOffset + Size);
-      if (Storage == HvStable)
-         HvMarkCellDirty(RegistryHive, FreeCellOffset + Size);
+      if (Storage == Stable)
+         HvMarkCellDirty(RegistryHive, FreeCellOffset + Size, FALSE);
    }
 
-   if (Storage == HvStable)
-      HvMarkCellDirty(RegistryHive, FreeCellOffset);
+   if (Storage == Stable)
+      HvMarkCellDirty(RegistryHive, FreeCellOffset, FALSE);
    FreeCell->Size = -FreeCell->Size;
    RtlZeroMemory(FreeCell + 1, Size - sizeof(HCELL));
 
+   CMLTRACE(CMLIB_HCELL_DEBUG, "%s - CellIndex %08lx\n",
+       __FUNCTION__, FreeCellOffset);
+
    return FreeCellOffset;
 }
 
@@ -366,9 +407,12 @@ HvReallocateCell(
    PVOID NewCell;
    LONG OldCellSize;
    HCELL_INDEX NewCellIndex;
-   HV_STORAGE_TYPE Storage;
+   HSTORAGE_TYPE Storage;
 
-   ASSERT(CellIndex != HCELL_NULL);
+   ASSERT(CellIndex != HCELL_NIL);
+
+   CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx, Size %x\n",
+       __FUNCTION__, RegistryHive, CellIndex, Size);
 
    Storage = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT;
 
@@ -383,11 +427,11 @@ HvReallocateCell(
     * FIXME: Merge with adjacent free cell if possible.
     * FIXME: Implement shrinking.
     */
-   if (Size > OldCellSize)
+   if (Size > (ULONG)OldCellSize)
    {
-      NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage);
-      if (NewCellIndex == HCELL_NULL)
-         return HCELL_NULL;
+      NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage, HCELL_NIL);
+      if (NewCellIndex == HCELL_NIL)
+         return HCELL_NIL;
 
       NewCell = HvGetCell(RegistryHive, NewCellIndex);
       RtlCopyMemory(NewCell, OldCell, (SIZE_T)OldCellSize);
@@ -413,6 +457,9 @@ HvFreeCell(
 
    ASSERT(RegistryHive->ReadOnly == FALSE);
 
+   CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx\n",
+       __FUNCTION__, RegistryHive, CellIndex);
+
    Free = HvpGetCellHeader(RegistryHive, CellIndex);
 
    ASSERT(Free->Size < 0);
@@ -423,7 +470,7 @@ HvFreeCell(
    CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
 
    /* FIXME: Merge free blocks */
-   Bin = (PHBIN)RegistryHive->Storage[CellType].BlockList[CellBlock].Bin;
+   Bin = (PHBIN)RegistryHive->Storage[CellType].BlockList[CellBlock].BinAddress;
 
    if ((CellIndex & ~HCELL_TYPE_MASK) + Free->Size <
        Bin->FileOffset + Bin->Size)
@@ -445,11 +492,23 @@ HvFreeCell(
       {
          if ((ULONG_PTR)Neighbor + Neighbor->Size == (ULONG_PTR)Free)
          {
-            Neighbor->Size += Free->Size;
-            if (CellType == HvStable)
-               HvMarkCellDirty(RegistryHive,
-                               (HCELL_INDEX)((ULONG_PTR)Neighbor - (ULONG_PTR)Bin +
-                               Bin->FileOffset));
+            HCELL_INDEX NeighborCellIndex =
+               (HCELL_INDEX)((ULONG_PTR)Neighbor - (ULONG_PTR)Bin +
+               Bin->FileOffset) | (CellIndex & HCELL_TYPE_MASK);
+
+            if (HvpComputeFreeListIndex(Neighbor->Size) !=
+                HvpComputeFreeListIndex(Neighbor->Size + Free->Size))
+            {
+               HvpRemoveFree(RegistryHive, Neighbor, NeighborCellIndex);
+               Neighbor->Size += Free->Size;
+               HvpAddFree(RegistryHive, Neighbor, NeighborCellIndex);
+            }
+            else
+               Neighbor->Size += Free->Size;
+
+            if (CellType == Stable)
+               HvMarkCellDirty(RegistryHive, NeighborCellIndex, FALSE);
+
             return;
          }
          Neighbor = (PHCELL)((ULONG_PTR)Neighbor + Neighbor->Size);
@@ -463,6 +522,6 @@ HvFreeCell(
    /* Add block to the list of free blocks */
    HvpAddFree(RegistryHive, Free, CellIndex);
 
-   if (CellType == HvStable)
-      HvMarkCellDirty(RegistryHive, CellIndex);
+   if (CellType == Stable)
+      HvMarkCellDirty(RegistryHive, CellIndex, FALSE);
 }