1384 lines
35 KiB
C
1384 lines
35 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
hivecell.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements hive cell procedures.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Bryan M. Willman (bryanwi) 27-Mar-92
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "cmp.h"
|
|||
|
|
|||
|
//
|
|||
|
// Private procedures
|
|||
|
//
|
|||
|
HCELL_INDEX
|
|||
|
HvpDoAllocateCell(
|
|||
|
PHHIVE Hive,
|
|||
|
ULONG NewSize,
|
|||
|
HSTORAGE_TYPE Type
|
|||
|
);
|
|||
|
|
|||
|
ULONG
|
|||
|
HvpAllocateInBin(
|
|||
|
PHHIVE Hive,
|
|||
|
PHBIN Bin,
|
|||
|
ULONG Size,
|
|||
|
ULONG Type
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HvpMakeBinPresent(
|
|||
|
IN PHHIVE Hive,
|
|||
|
IN HCELL_INDEX Cell,
|
|||
|
IN PHMAP_ENTRY Map
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HvpIsFreeNeighbor(
|
|||
|
PHHIVE Hive,
|
|||
|
PHBIN Bin,
|
|||
|
PHCELL FreeCell,
|
|||
|
PHCELL *FreeNeighbor,
|
|||
|
HSTORAGE_TYPE Type
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
#define CmpFindFirstSetRight KiFindFirstSetRight
|
|||
|
extern CCHAR KiFindFirstSetRight[256];
|
|||
|
#define CmpFindFirstSetLeft KiFindFirstSetLeft
|
|||
|
extern CCHAR KiFindFirstSetLeft[256];
|
|||
|
|
|||
|
#define HvpComputeIndex(Index, Size) \
|
|||
|
{ \
|
|||
|
Index = (Size >> HHIVE_FREE_DISPLAY_SHIFT) - 1; \
|
|||
|
if (Index >= HHIVE_LINEAR_INDEX ) { \
|
|||
|
\
|
|||
|
/* \
|
|||
|
** Too big for the linear lists, compute the exponential \
|
|||
|
** list. \
|
|||
|
*/ \
|
|||
|
\
|
|||
|
if (Index > 255) { \
|
|||
|
/* \
|
|||
|
** Too big for all the lists, use the last index. \
|
|||
|
*/ \
|
|||
|
Index = HHIVE_FREE_DISPLAY_SIZE-1; \
|
|||
|
} else { \
|
|||
|
Index = CmpFindFirstSetLeft[Index] + \
|
|||
|
HHIVE_FREE_DISPLAY_BIAS; \
|
|||
|
} \
|
|||
|
} \
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE,HvpGetCellPaged)
|
|||
|
#pragma alloc_text(PAGE,HvpGetCellFlat)
|
|||
|
#pragma alloc_text(PAGE,HvpGetCellMap)
|
|||
|
#pragma alloc_text(PAGE,HvGetCellSize)
|
|||
|
#pragma alloc_text(PAGE,HvAllocateCell)
|
|||
|
#pragma alloc_text(PAGE,HvpDoAllocateCell)
|
|||
|
#pragma alloc_text(PAGE,HvFreeCell)
|
|||
|
#pragma alloc_text(PAGE,HvpIsFreeNeighbor)
|
|||
|
#pragma alloc_text(PAGE,HvpEnlistFreeCell)
|
|||
|
#pragma alloc_text(PAGE,HvpDelistFreeCell)
|
|||
|
#pragma alloc_text(PAGE,HvReallocateCell)
|
|||
|
#pragma alloc_text(PAGE,HvIsCellAllocated)
|
|||
|
#pragma alloc_text(PAGE,HvpAllocateInBin)
|
|||
|
#pragma alloc_text(PAGE,HvpMakeBinPresent)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Cell Procedures
|
|||
|
//
|
|||
|
struct _CELL_DATA *
|
|||
|
HvpGetCellPaged(
|
|||
|
PHHIVE Hive,
|
|||
|
HCELL_INDEX Cell
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the memory address for the specified Cell. Will never
|
|||
|
return failure, but may assert. Use HvIsCellAllocated to check
|
|||
|
validity of Cell.
|
|||
|
|
|||
|
This routine should never be called directly, always call it
|
|||
|
via the HvGetCell() macro.
|
|||
|
|
|||
|
This routine provides GetCell support for hives with full maps.
|
|||
|
It is the normal version of the routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - supplies a pointer to the hive control structure for the
|
|||
|
hive of interest
|
|||
|
|
|||
|
Cell - supplies HCELL_INDEX of cell to return address for
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Address of Cell in memory. Assert or BugCheck if error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG Type;
|
|||
|
ULONG Table;
|
|||
|
ULONG Block;
|
|||
|
ULONG Offset;
|
|||
|
PHCELL pcell;
|
|||
|
PHMAP_ENTRY Map;
|
|||
|
|
|||
|
CMLOG(CML_FLOW, CMS_MAP) {
|
|||
|
KdPrint(("HvGetCellPaged:\n"));
|
|||
|
KdPrint(("\tHive=%08lx Cell=%08lx\n",Hive,Cell));
|
|||
|
}
|
|||
|
ASSERT(Hive->Signature == HHIVE_SIGNATURE);
|
|||
|
ASSERT(Cell != HCELL_NIL);
|
|||
|
ASSERT(Hive->Flat == FALSE);
|
|||
|
ASSERT((Cell & (HCELL_PAD(Hive)-1))==0);
|
|||
|
ASSERT_CM_LOCK_OWNED();
|
|||
|
#if DBG
|
|||
|
if (HvGetCellType(Cell) == Stable) {
|
|||
|
ASSERT(Cell >= sizeof(HBIN));
|
|||
|
} else {
|
|||
|
ASSERT(Cell >= (HCELL_TYPE_MASK + sizeof(HBIN)));
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
Type = HvGetCellType(Cell);
|
|||
|
Table = (Cell & HCELL_TABLE_MASK) >> HCELL_TABLE_SHIFT;
|
|||
|
Block = (Cell & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
|
|||
|
Offset = (Cell & HCELL_OFFSET_MASK);
|
|||
|
|
|||
|
ASSERT((Cell - (Type * HCELL_TYPE_MASK)) < Hive->Storage[Type].Length);
|
|||
|
|
|||
|
Map = &((Hive->Storage[Type].Map)->Directory[Table]->Table[Block]);
|
|||
|
ASSERT((Map->BinAddress & HMAP_BASE) != 0);
|
|||
|
ASSERT((Map->BinAddress & HMAP_DISCARDABLE) == 0);
|
|||
|
pcell = (PHCELL)((ULONG)(Map->BlockAddress) + Offset);
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
return (struct _CELL_DATA *)&(pcell->u.OldCell.u.UserData);
|
|||
|
} else {
|
|||
|
return (struct _CELL_DATA *)&(pcell->u.NewCell.u.UserData);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
struct _CELL_DATA *
|
|||
|
HvpGetCellFlat(
|
|||
|
PHHIVE Hive,
|
|||
|
HCELL_INDEX Cell
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the memory address for the specified Cell. Will never
|
|||
|
return failure, but may assert. Use HvIsCellAllocated to check
|
|||
|
validity of Cell.
|
|||
|
|
|||
|
This routine should never be called directly, always call it
|
|||
|
via the HvGetCell() macro.
|
|||
|
|
|||
|
This routine provides GetCell support for read only hives with
|
|||
|
single allocation flat images. Such hives do not have cell
|
|||
|
maps ("page tables"), instead, we compute addresses by
|
|||
|
arithmetic against the base image address.
|
|||
|
|
|||
|
Such hives cannot have volatile cells.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - supplies a pointer to the hive control structure for the
|
|||
|
hive of interest
|
|||
|
|
|||
|
Cell - supplies HCELL_INDEX of cell to return address for
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Address of Cell in memory. Assert or BugCheck if error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PUCHAR base;
|
|||
|
PHCELL pcell;
|
|||
|
|
|||
|
CMLOG(CML_FLOW, CMS_MAP) {
|
|||
|
KdPrint(("HvGetCellFlat:\n"));
|
|||
|
KdPrint(("\tHive=%08lx Cell=%08lx\n",Hive,Cell));
|
|||
|
}
|
|||
|
ASSERT(Hive->Signature == HHIVE_SIGNATURE);
|
|||
|
ASSERT(Cell != HCELL_NIL);
|
|||
|
ASSERT(Hive->Flat == TRUE);
|
|||
|
ASSERT(HvGetCellType(Cell) == Stable);
|
|||
|
ASSERT(Cell >= sizeof(HBIN));
|
|||
|
ASSERT(Cell < Hive->BaseBlock->Length);
|
|||
|
ASSERT((Cell & 0x7)==0);
|
|||
|
|
|||
|
//
|
|||
|
// Address is base of Hive image + Cell
|
|||
|
//
|
|||
|
base = (PUCHAR)(Hive->BaseBlock) + HBLOCK_SIZE;
|
|||
|
pcell = (PHCELL)(base + Cell);
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
return (struct _CELL_DATA *)&(pcell->u.OldCell.u.UserData);
|
|||
|
} else {
|
|||
|
return (struct _CELL_DATA *)&(pcell->u.NewCell.u.UserData);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PHMAP_ENTRY
|
|||
|
HvpGetCellMap(
|
|||
|
PHHIVE Hive,
|
|||
|
HCELL_INDEX Cell
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the address of the HMAP_ENTRY for the cell.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - supplies a pointer to the hive control structure for the
|
|||
|
hive of interest
|
|||
|
|
|||
|
Cell - supplies HCELL_INDEX of cell to return map entry address for
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Address of MAP_ENTRY in memory. NULL if no such cell or other error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG Type;
|
|||
|
ULONG Table;
|
|||
|
ULONG Block;
|
|||
|
PHMAP_TABLE ptab;
|
|||
|
|
|||
|
CMLOG(CML_FLOW, CMS_MAP) {
|
|||
|
KdPrint(("HvpGetCellMapPaged:\n"));
|
|||
|
KdPrint(("\tHive=%08lx Cell=%08lx\n",Hive,Cell));
|
|||
|
}
|
|||
|
ASSERT(Hive->Signature == HHIVE_SIGNATURE);
|
|||
|
ASSERT(Hive->Flat == FALSE);
|
|||
|
ASSERT((Cell & (HCELL_PAD(Hive)-1))==0);
|
|||
|
|
|||
|
Type = HvGetCellType(Cell);
|
|||
|
Table = (Cell & HCELL_TABLE_MASK) >> HCELL_TABLE_SHIFT;
|
|||
|
Block = (Cell & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
|
|||
|
|
|||
|
if ((Cell - (Type * HCELL_TYPE_MASK)) >= Hive->Storage[Type].Length) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
ptab = (Hive->Storage[Type].Map)->Directory[Table];
|
|||
|
return &(ptab->Table[Block]);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LONG
|
|||
|
HvGetCellSize(
|
|||
|
IN PHHIVE Hive,
|
|||
|
IN PVOID Address
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the size of the specified Cell, based on its MEMORY
|
|||
|
ADDRESS. Must always call HvGetCell first to get that
|
|||
|
address.
|
|||
|
|
|||
|
NOTE: This should be a macro if speed is issue.
|
|||
|
|
|||
|
NOTE: If you pass in some random pointer, you will get some
|
|||
|
random answer. Only pass in valid Cell addresses.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - supplies hive control structure for the given cell
|
|||
|
|
|||
|
Address - address in memory of the cell, returned by HvGetCell()
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Allocated size in bytes of the cell.
|
|||
|
|
|||
|
If Negative, Cell is free, or Address is bogus.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LONG size;
|
|||
|
|
|||
|
CMLOG(CML_FLOW, CMS_MAP) {
|
|||
|
KdPrint(("HvGetCellSize:\n"));
|
|||
|
KdPrint(("\tAddress=%08lx\n", Address));
|
|||
|
}
|
|||
|
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
size = ( (CONTAINING_RECORD(Address, HCELL, u.OldCell.u.UserData))->Size ) * -1;
|
|||
|
size -= FIELD_OFFSET(HCELL, u.OldCell.u.UserData);
|
|||
|
} else {
|
|||
|
size = ( (CONTAINING_RECORD(Address, HCELL, u.NewCell.u.UserData))->Size ) * -1;
|
|||
|
size -= FIELD_OFFSET(HCELL, u.NewCell.u.UserData);
|
|||
|
}
|
|||
|
return size;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
HCELL_INDEX
|
|||
|
HvAllocateCell(
|
|||
|
PHHIVE Hive,
|
|||
|
ULONG NewSize,
|
|||
|
HSTORAGE_TYPE Type
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Allocates the space and the cell index for a new cell.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - supplies a pointer to the hive control structure for the
|
|||
|
hive of interest
|
|||
|
|
|||
|
NewSize - size in bytes of the cell to allocate
|
|||
|
|
|||
|
Type - indicates whether Stable or Volatile storage is desired.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
New HCELL_INDEX if success, HCELL_NIL if failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HCELL_INDEX NewCell;
|
|||
|
|
|||
|
CMLOG(CML_MAJOR, CMS_HIVE) {
|
|||
|
KdPrint(("HvAllocateCell:\n"));
|
|||
|
KdPrint(("\tHive=%08lx NewSize=%08lx\n",Hive,NewSize));
|
|||
|
}
|
|||
|
ASSERT(Hive->Signature == HHIVE_SIGNATURE);
|
|||
|
ASSERT(Hive->ReadOnly == FALSE);
|
|||
|
ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
|||
|
|
|||
|
//
|
|||
|
// Make room for overhead fields and round up to HCELL_PAD boundary
|
|||
|
//
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
NewSize += FIELD_OFFSET(HCELL, u.OldCell.u.UserData);
|
|||
|
} else {
|
|||
|
NewSize += FIELD_OFFSET(HCELL, u.NewCell.u.UserData);
|
|||
|
}
|
|||
|
NewSize = ROUND_UP(NewSize, HCELL_PAD(Hive));
|
|||
|
|
|||
|
//
|
|||
|
// reject impossible/unreasonable values
|
|||
|
//
|
|||
|
if (NewSize >= HSANE_CELL_MAX) {
|
|||
|
return HCELL_NIL;
|
|||
|
}
|
|||
|
|
|||
|
if (NewSize > HCELL_BIG_ROUND) {
|
|||
|
NewSize = ROUND_UP(NewSize, HBLOCK_SIZE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Do the actual storage allocation
|
|||
|
//
|
|||
|
NewCell = HvpDoAllocateCell(Hive, NewSize, Type);
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (NewCell != HCELL_NIL) {
|
|||
|
ASSERT(HvIsCellAllocated(Hive, NewCell));
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
CMLOG(CML_FLOW, CMS_HIVE) {
|
|||
|
KdPrint(("\tNewCell=%08lx\n", NewCell));
|
|||
|
}
|
|||
|
return NewCell;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HCELL_INDEX
|
|||
|
HvpDoAllocateCell(
|
|||
|
PHHIVE Hive,
|
|||
|
ULONG NewSize,
|
|||
|
HSTORAGE_TYPE Type
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Allocates space in the hive. Does not affect cell map in any way.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - supplies a pointer to the hive control structure for the
|
|||
|
hive of interest
|
|||
|
|
|||
|
NewSize - size in bytes of the cell to allocate
|
|||
|
|
|||
|
Type - indicates whether Stable or Volatile storage is desired.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
HCELL_INDEX of new cell, HCELL_NIL if failure
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG Index;
|
|||
|
ULONG Summary;
|
|||
|
HCELL_INDEX cell;
|
|||
|
PHCELL pcell;
|
|||
|
HCELL_INDEX tcell;
|
|||
|
PHCELL ptcell;
|
|||
|
PHBIN Bin;
|
|||
|
PHMAP_ENTRY Me;
|
|||
|
ULONG offset;
|
|||
|
PHCELL next;
|
|||
|
ULONG MinFreeSize;
|
|||
|
|
|||
|
|
|||
|
CMLOG(CML_MINOR, CMS_HIVE) {
|
|||
|
KdPrint(("HvDoAllocateCell:\n"));
|
|||
|
KdPrint(("\tHive=%08lx NewSize=%08lx Type=%08lx\n",Hive,NewSize,Type));
|
|||
|
}
|
|||
|
ASSERT(Hive->ReadOnly == FALSE);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Compute Index into Display
|
|||
|
//
|
|||
|
HvpComputeIndex(Index, NewSize);
|
|||
|
|
|||
|
//
|
|||
|
// Compute Summary vector of Display entries that are non null
|
|||
|
//
|
|||
|
Summary = Hive->Storage[Type].FreeSummary;
|
|||
|
Summary = Summary & ~((1 << Index) - 1);
|
|||
|
|
|||
|
//
|
|||
|
// We now have a summary of lists that are non-null and may
|
|||
|
// contain entries large enough to satisfy the request.
|
|||
|
// Iterate through the list and pull the first cell that is
|
|||
|
// big enough. If no cells are big enough, advance to the
|
|||
|
// next non-null list.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(HHIVE_FREE_DISPLAY_SIZE == 24);
|
|||
|
while (Summary != 0) {
|
|||
|
if (Summary & 0xff) {
|
|||
|
Index = CmpFindFirstSetRight[Summary & 0xff];
|
|||
|
} else if (Summary & 0xff00) {
|
|||
|
Index = CmpFindFirstSetRight[(Summary & 0xff00) >> 8] + 8;
|
|||
|
} else {
|
|||
|
ASSERT(Summary & 0xff0000);
|
|||
|
Index = CmpFindFirstSetRight[(Summary & 0xff0000) >> 16] + 16;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Walk through the list until we find a cell large enough
|
|||
|
// to satisfy the allocation. If we find one, pull it from
|
|||
|
// the list and use it. If we don't find one, clear this
|
|||
|
// list's bit in the Summary and try the next larger list.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// look for a large enough cell in the list
|
|||
|
//
|
|||
|
cell = Hive->Storage[Type].FreeDisplay[Index];
|
|||
|
while (cell != HCELL_NIL) {
|
|||
|
|
|||
|
pcell = HvpGetHCell(Hive, cell);
|
|||
|
|
|||
|
if (NewSize <= (ULONG)pcell->Size) {
|
|||
|
|
|||
|
//
|
|||
|
// Found a big enough cell.
|
|||
|
//
|
|||
|
if (! HvMarkCellDirty(Hive, cell)) {
|
|||
|
return HCELL_NIL;
|
|||
|
}
|
|||
|
|
|||
|
HvpDelistFreeCell(Hive, pcell, Type);
|
|||
|
|
|||
|
ASSERT(pcell->Size > 0);
|
|||
|
ASSERT(NewSize <= (ULONG)pcell->Size);
|
|||
|
goto UseIt;
|
|||
|
}
|
|||
|
// DbgPrint("cell %08lx (%lx) too small (%d < %d), trying next at",cell,pcell,pcell->Size,NewSize);
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
cell = pcell->u.OldCell.u.Next;
|
|||
|
} else {
|
|||
|
cell = pcell->u.NewCell.u.Next;
|
|||
|
}
|
|||
|
// DbgPrint(" %08lx\n",cell);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// No suitable cell was found on that list.
|
|||
|
// Clear the bit in the summary and try the
|
|||
|
// next biggest list.
|
|||
|
//
|
|||
|
// DbgPrint("No suitable cell, Index %d, Summary %08lx -> ",Index, Summary);
|
|||
|
ASSERT(Summary & (1 << Index));
|
|||
|
Summary = Summary & ~(1 << Index);
|
|||
|
// DbgPrint("%08lx\n",Summary);
|
|||
|
}
|
|||
|
|
|||
|
if (Summary == 0) {
|
|||
|
//
|
|||
|
// No suitable cells were found on any free list.
|
|||
|
//
|
|||
|
// Either there is no large enough cell, or we
|
|||
|
// have no free cells left at all. In either case, allocate a
|
|||
|
// new bin, with a new free cell certain to be large enough in
|
|||
|
// it, and use that cell.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to create a new bin
|
|||
|
//
|
|||
|
if ((Bin = HvpAddBin(Hive, NewSize, Type)) != NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// It worked. Use single large cell in Bin.
|
|||
|
//
|
|||
|
DHvCheckBin(Hive,Bin);
|
|||
|
cell = (Bin->FileOffset) + sizeof(HBIN) + (Type*HCELL_TYPE_MASK);
|
|||
|
pcell = HvpGetHCell(Hive, cell);
|
|||
|
} else {
|
|||
|
return HCELL_NIL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
UseIt:
|
|||
|
|
|||
|
//
|
|||
|
// cell refers to a free cell we have pulled from its list
|
|||
|
// if it is too big, give the residue back
|
|||
|
// ("too big" means there is at least one HCELL of extra space)
|
|||
|
// always mark it allocated
|
|||
|
// return it as our function value
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(pcell->Size > 0);
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
MinFreeSize = FIELD_OFFSET(HCELL, u.OldCell.u.Next) + sizeof(HCELL_INDEX);
|
|||
|
} else {
|
|||
|
MinFreeSize = FIELD_OFFSET(HCELL, u.NewCell.u.Next) + sizeof(HCELL_INDEX);
|
|||
|
}
|
|||
|
if ((NewSize + MinFreeSize) < (ULONG)pcell->Size) {
|
|||
|
|
|||
|
//
|
|||
|
// Crack the cell, use part we need, put rest on
|
|||
|
// free list.
|
|||
|
//
|
|||
|
Me = HvpGetCellMap(Hive, cell);
|
|||
|
ASSERT(Me != NULL);
|
|||
|
Bin = (PHBIN)((ULONG)(Me->BinAddress) & HMAP_BASE);
|
|||
|
offset = (ULONG)pcell - (ULONG)Bin;
|
|||
|
|
|||
|
ptcell = (PHCELL)((PUCHAR)pcell + NewSize);
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
ptcell->u.OldCell.Last = offset;
|
|||
|
}
|
|||
|
ptcell->Size = pcell->Size - NewSize;
|
|||
|
|
|||
|
if ((offset + pcell->Size) < Bin->Size) {
|
|||
|
next = (PHCELL)((PUCHAR)pcell + pcell->Size);
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
next->u.OldCell.Last = offset + NewSize;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
pcell->Size = NewSize;
|
|||
|
tcell = (HCELL_INDEX)((ULONG)cell + NewSize);
|
|||
|
|
|||
|
HvpEnlistFreeCell(Hive, tcell, ptcell->Size, Type);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// return the cell we found.
|
|||
|
//
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
RtlFillMemory(
|
|||
|
&(pcell->u.OldCell.u.UserData),
|
|||
|
(pcell->Size - FIELD_OFFSET(HCELL, u.OldCell.u.UserData)),
|
|||
|
HCELL_ALLOCATE_FILL
|
|||
|
);
|
|||
|
} else {
|
|||
|
RtlFillMemory(
|
|||
|
&(pcell->u.NewCell.u.UserData),
|
|||
|
(pcell->Size - FIELD_OFFSET(HCELL, u.NewCell.u.UserData)),
|
|||
|
HCELL_ALLOCATE_FILL
|
|||
|
);
|
|||
|
}
|
|||
|
pcell->Size *= -1;
|
|||
|
|
|||
|
return cell;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HvFreeCell(
|
|||
|
PHHIVE Hive,
|
|||
|
HCELL_INDEX Cell
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Frees the storage for a cell.
|
|||
|
|
|||
|
NOTE: CALLER is expected to mark relevent data dirty, so as to
|
|||
|
allow this call to always succeed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - supplies a pointer to the hive control structure for the
|
|||
|
hive of interest
|
|||
|
|
|||
|
Cell - HCELL_INDEX of Cell to free.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE - failed, presumably for want of log space.
|
|||
|
|
|||
|
TRUE - it worked
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PHBIN Bin;
|
|||
|
PHCELL tmp;
|
|||
|
HCELL_INDEX newfreecell;
|
|||
|
PHCELL freebase;
|
|||
|
ULONG savesize;
|
|||
|
PHCELL neighbor;
|
|||
|
ULONG Type;
|
|||
|
PHMAP_ENTRY Me;
|
|||
|
|
|||
|
|
|||
|
CMLOG(CML_MINOR, CMS_HIVE) {
|
|||
|
KdPrint(("HvFreeCell:\n"));
|
|||
|
KdPrint(("\tHive=%08lx Cell=%08lx\n",Hive,Cell));
|
|||
|
}
|
|||
|
ASSERT(Hive->ReadOnly == FALSE);
|
|||
|
ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
|||
|
|
|||
|
//
|
|||
|
// Get sizes and addresses
|
|||
|
//
|
|||
|
Me = HvpGetCellMap(Hive, Cell);
|
|||
|
ASSERT(Me != NULL);
|
|||
|
Type = HvGetCellType(Cell);
|
|||
|
|
|||
|
Bin = (PHBIN)((ULONG)(Me->BinAddress) & HMAP_BASE);
|
|||
|
DHvCheckBin(Hive,Bin);
|
|||
|
|
|||
|
freebase = HvpGetHCell(Hive, Cell);
|
|||
|
|
|||
|
//
|
|||
|
// go do actual frees, cannot fail from this point on
|
|||
|
//
|
|||
|
ASSERT(freebase->Size < 0);
|
|||
|
freebase->Size *= -1;
|
|||
|
|
|||
|
savesize = freebase->Size;
|
|||
|
|
|||
|
//
|
|||
|
// Look for free neighbors and coalesce them. We will never travel
|
|||
|
// around this loop more than twice.
|
|||
|
//
|
|||
|
while (
|
|||
|
HvpIsFreeNeighbor(
|
|||
|
Hive,
|
|||
|
Bin,
|
|||
|
freebase,
|
|||
|
&neighbor,
|
|||
|
Type
|
|||
|
) == TRUE
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
if (neighbor > freebase) {
|
|||
|
|
|||
|
//
|
|||
|
// Neighboring free cell is immediately above us in memory.
|
|||
|
//
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
tmp = (PHCELL)((PUCHAR)neighbor + neighbor->Size);
|
|||
|
if ( ((ULONG)tmp - (ULONG)Bin) < Bin->Size) {
|
|||
|
tmp->u.OldCell.Last = (ULONG)freebase - (ULONG)Bin;
|
|||
|
}
|
|||
|
}
|
|||
|
freebase->Size += neighbor->Size;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Neighboring free cell is immediately below us in memory.
|
|||
|
//
|
|||
|
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
tmp = (PHCELL)((PUCHAR)freebase + freebase->Size);
|
|||
|
if ( ((ULONG)tmp - (ULONG)Bin) < Bin->Size ) {
|
|||
|
tmp->u.OldCell.Last = (ULONG)neighbor - (ULONG)Bin;
|
|||
|
}
|
|||
|
}
|
|||
|
neighbor->Size += freebase->Size;
|
|||
|
freebase = neighbor;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// freebase now points to the biggest free cell we could make, none
|
|||
|
// of which is on the free list. So put it on the list.
|
|||
|
//
|
|||
|
newfreecell = (Bin->FileOffset) +
|
|||
|
((ULONG)freebase - (ULONG)Bin) +
|
|||
|
(Type*HCELL_TYPE_MASK);
|
|||
|
|
|||
|
ASSERT(HvpGetHCell(Hive, newfreecell) == freebase);
|
|||
|
|
|||
|
HvpEnlistFreeCell(Hive, newfreecell, freebase->Size, Type);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HvpIsFreeNeighbor(
|
|||
|
PHHIVE Hive,
|
|||
|
PHBIN Bin,
|
|||
|
PHCELL FreeCell,
|
|||
|
PHCELL *FreeNeighbor,
|
|||
|
HSTORAGE_TYPE Type
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Reports on whether FreeCell has at least one free neighbor and
|
|||
|
if so where. Free neighbor will be cut out of the free list.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - hive we're working on
|
|||
|
|
|||
|
Bin - pointer to the storage bin
|
|||
|
|
|||
|
FreeCell - supplies a pointer to a cell that has been freed, or
|
|||
|
the result of a coalesce.
|
|||
|
|
|||
|
FreeNeighbor - supplies a pointer to a variable to receive the address
|
|||
|
of a free neigbhor of FreeCell, if such exists
|
|||
|
|
|||
|
Type - storage type of the cell
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if a free neighbor was found, else false.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PHCELL ptcell;
|
|||
|
|
|||
|
CMLOG(CML_MINOR, CMS_HIVE) {
|
|||
|
KdPrint(("HvpIsFreeNeighbor:\n\tBin=%08lx",Bin));
|
|||
|
KdPrint(("FreeCell=%08lx\n", FreeCell));
|
|||
|
}
|
|||
|
ASSERT(Hive->ReadOnly == FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Neighbor above us?
|
|||
|
//
|
|||
|
*FreeNeighbor = NULL;
|
|||
|
ptcell = (PHCELL)((PUCHAR)FreeCell + FreeCell->Size);
|
|||
|
ASSERT( ((ULONG)ptcell - (ULONG)Bin) <= Bin->Size);
|
|||
|
if (((ULONG)ptcell - (ULONG)Bin) < Bin->Size) {
|
|||
|
if (ptcell->Size > 0) {
|
|||
|
*FreeNeighbor = ptcell;
|
|||
|
goto FoundNeighbor;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Neighbor below us?
|
|||
|
//
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
if (FreeCell->u.OldCell.Last != HBIN_NIL) {
|
|||
|
ptcell = (PHCELL)((PUCHAR)Bin + FreeCell->u.OldCell.Last);
|
|||
|
if (ptcell->Size > 0) {
|
|||
|
*FreeNeighbor = ptcell;
|
|||
|
goto FoundNeighbor;
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
ptcell = (PHCELL)(Bin+1);
|
|||
|
while (ptcell < FreeCell) {
|
|||
|
|
|||
|
//
|
|||
|
// scan through the cells from the start of the bin looking for neighbor.
|
|||
|
//
|
|||
|
if (ptcell->Size > 0) {
|
|||
|
|
|||
|
if ((PHCELL)((PUCHAR)ptcell + ptcell->Size) == FreeCell) {
|
|||
|
*FreeNeighbor = ptcell;
|
|||
|
//
|
|||
|
// Try and mark it dirty, since we will be changing
|
|||
|
// the size field. If this fails, ignore
|
|||
|
// the free neighbor, we will not fail the free
|
|||
|
// just because we couldn't mark the cell dirty
|
|||
|
// so it could be coalesced.
|
|||
|
//
|
|||
|
// Note we only bother doing this for new hives,
|
|||
|
// for old format hives we always mark the whole
|
|||
|
// bin dirty.
|
|||
|
//
|
|||
|
if ((Type == Volatile) ||
|
|||
|
(HvMarkCellDirty(Hive, (ULONG)ptcell-(ULONG)Bin + Bin->FileOffset))) {
|
|||
|
goto FoundNeighbor;
|
|||
|
} else {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
ptcell = (PHCELL)((PUCHAR)ptcell + ptcell->Size);
|
|||
|
}
|
|||
|
} else {
|
|||
|
ptcell = (PHCELL)((PUCHAR)ptcell - ptcell->Size);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(FALSE);
|
|||
|
|
|||
|
FoundNeighbor:
|
|||
|
|
|||
|
HvpDelistFreeCell(Hive, *FreeNeighbor, Type);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HvpEnlistFreeCell(
|
|||
|
PHHIVE Hive,
|
|||
|
HCELL_INDEX Cell,
|
|||
|
ULONG Size,
|
|||
|
HSTORAGE_TYPE Type
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Puts the newly freed cell on the appropriate list.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - supplies a pointer to the hive control structure for the
|
|||
|
hive of interest
|
|||
|
|
|||
|
Cell - supplies index of cell to enlist
|
|||
|
|
|||
|
Size - size of cell
|
|||
|
|
|||
|
Type - indicates whether Stable or Volatile storage is desired.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NONE.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PHCELL_INDEX Next;
|
|||
|
PHMAP_ENTRY Map;
|
|||
|
PHCELL pcell;
|
|||
|
PHCELL FirstCell;
|
|||
|
ULONG Index;
|
|||
|
PHBIN Bin;
|
|||
|
HCELL_INDEX FreeCell;
|
|||
|
PFREE_HBIN FreeBin;
|
|||
|
PHBIN FirstBin;
|
|||
|
PHBIN LastBin;
|
|||
|
|
|||
|
HvpComputeIndex(Index, Size);
|
|||
|
|
|||
|
Next = &(Hive->Storage[Type].FreeDisplay[Index]);
|
|||
|
pcell = HvpGetHCell(Hive, Cell);
|
|||
|
ASSERT(pcell->Size > 0);
|
|||
|
ASSERT(Size == (ULONG)pcell->Size);
|
|||
|
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
pcell->u.OldCell.u.Next = *Next;
|
|||
|
} else {
|
|||
|
pcell->u.NewCell.u.Next = *Next;
|
|||
|
}
|
|||
|
*Next = Cell;
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if this is the first cell in the bin and if the entire
|
|||
|
// bin consists just of this cell.
|
|||
|
//
|
|||
|
Map = HvpGetCellMap(Hive, Cell);
|
|||
|
Bin = (PHBIN)(Map->BinAddress & ~HMAP_NEWALLOC);
|
|||
|
if ((pcell == (PHCELL)(Bin + 1)) &&
|
|||
|
(Size == Bin->Size-sizeof(HBIN))) {
|
|||
|
|
|||
|
//
|
|||
|
// We have a bin that is entirely free. But we cannot do anything with it
|
|||
|
// unless the memalloc that contains the bin is entirely free. Walk the
|
|||
|
// bins backwards until we find the first one in the alloc, then walk forwards
|
|||
|
// until we find the last one. If any of the other bins in the memalloc
|
|||
|
// are not free, bail out.
|
|||
|
//
|
|||
|
FirstBin = Bin;
|
|||
|
while (FirstBin->MemAlloc == 0) {
|
|||
|
Map=HvpGetCellMap(Hive,(FirstBin->FileOffset - HBLOCK_SIZE) +
|
|||
|
(Type * HCELL_TYPE_MASK));
|
|||
|
FirstBin = (PHBIN)(Map->BinAddress & HMAP_BASE);
|
|||
|
FirstCell = (PHCELL)(FirstBin+1);
|
|||
|
if ((ULONG)(FirstCell->Size) != FirstBin->Size-sizeof(HBIN)) {
|
|||
|
//
|
|||
|
// The first cell in the bin is either allocated, or not the only
|
|||
|
// cell in the HBIN. We cannot free any HBINs.
|
|||
|
//
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LastBin = Bin;
|
|||
|
while (LastBin->FileOffset+LastBin->Size < FirstBin->FileOffset+FirstBin->MemAlloc) {
|
|||
|
Map = HvpGetCellMap(Hive, (LastBin->FileOffset+LastBin->Size) +
|
|||
|
(Type * HCELL_TYPE_MASK));
|
|||
|
if (Map->BinAddress==0) {
|
|||
|
//
|
|||
|
// Map is still being built up and we are at the end of what's
|
|||
|
// been built up. Just return and this will get freed up
|
|||
|
// when the next HBIN is added.
|
|||
|
//
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
LastBin = (PHBIN)(Map->BinAddress & HMAP_BASE);
|
|||
|
FirstCell = (PHCELL)(LastBin + 1);
|
|||
|
if ((ULONG)(FirstCell->Size) != LastBin->Size-sizeof(HBIN)) {
|
|||
|
//
|
|||
|
// The first cell in the bin is either allocated, or not the only
|
|||
|
// cell in the HBIN. We cannot free any HBINs.
|
|||
|
//
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// All the bins in this alloc are freed. Coalesce all the bins into
|
|||
|
// one alloc-sized bin, then either discard the bin or mark it as
|
|||
|
// discardable.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Mark the first HBLOCK of the first HBIN dirty, since
|
|||
|
// we may need to update the on disk field for the bin size
|
|||
|
//
|
|||
|
if (!HvMarkDirty(Hive,
|
|||
|
FirstBin->FileOffset + (Type * HCELL_TYPE_MASK),
|
|||
|
sizeof(HBIN) + sizeof(HCELL))) {
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
|
|||
|
FreeBin = (Hive->Allocate)(sizeof(FREE_HBIN), FALSE);
|
|||
|
if (FreeBin == NULL) {
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Walk through the bins and delist each free cell
|
|||
|
//
|
|||
|
Bin = FirstBin;
|
|||
|
do {
|
|||
|
FirstCell = (PHCELL)(Bin+1);
|
|||
|
HvpDelistFreeCell(Hive, FirstCell, Type);
|
|||
|
if (Bin==LastBin) {
|
|||
|
break;
|
|||
|
}
|
|||
|
Map = HvpGetCellMap(Hive, (Bin->FileOffset+Bin->Size)+
|
|||
|
(Type * HCELL_TYPE_MASK));
|
|||
|
Bin = (PHBIN)(Map->BinAddress & HMAP_BASE);
|
|||
|
|
|||
|
} while ( TRUE );
|
|||
|
|
|||
|
//
|
|||
|
// Coalesce them all into one bin.
|
|||
|
//
|
|||
|
FirstBin->Size = FirstBin->MemAlloc;
|
|||
|
|
|||
|
FreeBin->Size = FirstBin->Size;
|
|||
|
FreeBin->FileOffset = FirstBin->FileOffset;
|
|||
|
FirstCell = (PHCELL)(FirstBin+1);
|
|||
|
FirstCell->Size = FirstBin->Size - sizeof(HBIN);
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
FirstCell->u.OldCell.Last = (ULONG)HBIN_NIL;
|
|||
|
}
|
|||
|
|
|||
|
InsertHeadList(&Hive->Storage[Type].FreeBins, &FreeBin->ListEntry);
|
|||
|
ASSERT_LISTENTRY(&FreeBin->ListEntry);
|
|||
|
ASSERT_LISTENTRY(FreeBin->ListEntry.Flink);
|
|||
|
|
|||
|
FreeCell = FirstBin->FileOffset+(Type*HCELL_TYPE_MASK);
|
|||
|
FreeBin->Flags = FREE_HBIN_DISCARDABLE;
|
|||
|
while (FreeCell-FirstBin->FileOffset < FirstBin->Size) {
|
|||
|
Map = HvpGetCellMap(Hive, FreeCell);
|
|||
|
if (Map->BinAddress | HMAP_NEWALLOC) {
|
|||
|
Map->BinAddress = (ULONG)FirstBin | HMAP_DISCARDABLE | HMAP_NEWALLOC;
|
|||
|
} else {
|
|||
|
Map->BinAddress = (ULONG)FirstBin | HMAP_DISCARDABLE;
|
|||
|
}
|
|||
|
Map->BlockAddress = (ULONG)FreeBin;
|
|||
|
FreeCell += HBLOCK_SIZE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Done:
|
|||
|
Hive->Storage[Type].FreeSummary |= (1 << Index);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HvpDelistFreeCell(
|
|||
|
PHHIVE Hive,
|
|||
|
PHCELL Pcell,
|
|||
|
HSTORAGE_TYPE Type
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Removes a free cell from its list, and clears the Summary
|
|||
|
bit for it if need be.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - supplies a pointer to the hive control structure for the
|
|||
|
hive of interest
|
|||
|
|
|||
|
Pcell - supplies a pointer to the HCELL structure of interest
|
|||
|
|
|||
|
Type - Stable vs. Volatile
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NONE.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PHCELL_INDEX List;
|
|||
|
ULONG Index;
|
|||
|
|
|||
|
HvpComputeIndex(Index, Pcell->Size);
|
|||
|
List = &(Hive->Storage[Type].FreeDisplay[Index]);
|
|||
|
|
|||
|
//
|
|||
|
// Find previous cell on list
|
|||
|
//
|
|||
|
ASSERT(*List != HCELL_NIL);
|
|||
|
while (HvpGetHCell(Hive,*List) != Pcell) {
|
|||
|
List = (PHCELL_INDEX)HvGetCell(Hive,*List);
|
|||
|
ASSERT(*List != HCELL_NIL);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove Pcell from list.
|
|||
|
//
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
*List = Pcell->u.OldCell.u.Next;
|
|||
|
} else {
|
|||
|
*List = Pcell->u.NewCell.u.Next;
|
|||
|
}
|
|||
|
|
|||
|
if (Hive->Storage[Type].FreeDisplay[Index] == HCELL_NIL) {
|
|||
|
Hive->Storage[Type].FreeSummary &= ~(1 << Index);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HCELL_INDEX
|
|||
|
HvReallocateCell(
|
|||
|
PHHIVE Hive,
|
|||
|
HCELL_INDEX Cell,
|
|||
|
ULONG NewSize
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Grows or shrinks a cell.
|
|||
|
|
|||
|
NOTE:
|
|||
|
|
|||
|
MUST NOT FAIL if the cell is being made smaller. Can be
|
|||
|
a noop, but must work.
|
|||
|
|
|||
|
WARNING:
|
|||
|
|
|||
|
If the cell is grown, it will get a NEW and DIFFERENT HCELL_INDEX!!!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - supplies a pointer to the hive control structure for the
|
|||
|
hive of interest
|
|||
|
|
|||
|
Cell - supplies index of cell to grow or shrink
|
|||
|
|
|||
|
NewSize - desired size of cell (this is an absolute size, not an
|
|||
|
increment or decrement.)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
New HCELL_INDEX for cell, or HCELL_NIL if failure.
|
|||
|
|
|||
|
If return is HCELL_NIL, either old cell did not exist, or it did exist
|
|||
|
and we could not make a new one. In either case, nothing has changed.
|
|||
|
|
|||
|
If return is NOT HCELL_NIL, then it is the HCELL_INDEX for the Cell,
|
|||
|
which very probably moved.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PHMAP_ENTRY me;
|
|||
|
PUCHAR oldaddress;
|
|||
|
LONG oldsize;
|
|||
|
ULONG oldalloc;
|
|||
|
HCELL_INDEX NewCell; // return value
|
|||
|
PUCHAR newaddress;
|
|||
|
ULONG Type;
|
|||
|
|
|||
|
CMLOG(CML_MAJOR, CMS_HIVE) {
|
|||
|
KdPrint(("HvReallocateCell:\n"));
|
|||
|
KdPrint(("\tHive=%08lx Cell=%08lx NewSize=%08lx\n",Hive,Cell,NewSize));
|
|||
|
}
|
|||
|
ASSERT(Hive->Signature == HHIVE_SIGNATURE);
|
|||
|
ASSERT(Hive->ReadOnly == FALSE);
|
|||
|
ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
|||
|
|
|||
|
//
|
|||
|
// Make room for overhead fields and round up to HCELL_PAD boundary
|
|||
|
//
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
NewSize += FIELD_OFFSET(HCELL, u.OldCell.u.UserData);
|
|||
|
} else {
|
|||
|
NewSize += FIELD_OFFSET(HCELL, u.NewCell.u.UserData);
|
|||
|
}
|
|||
|
NewSize = ROUND_UP(NewSize, HCELL_PAD(Hive));
|
|||
|
|
|||
|
//
|
|||
|
// reject impossible/unreasonable values
|
|||
|
//
|
|||
|
if (NewSize >= HSANE_CELL_MAX) {
|
|||
|
CMLOG(CML_FLOW, CMS_HIVE) {
|
|||
|
KdPrint(("\tNewSize=%08lx\n", NewSize));
|
|||
|
}
|
|||
|
return HCELL_NIL;
|
|||
|
}
|
|||
|
|
|||
|
if (NewSize > HCELL_BIG_ROUND) {
|
|||
|
NewSize = ROUND_UP(NewSize, HBLOCK_SIZE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get sizes and addresses
|
|||
|
//
|
|||
|
me = HvpGetCellMap(Hive, Cell);
|
|||
|
ASSERT(me != NULL);
|
|||
|
|
|||
|
oldaddress = (PUCHAR)HvGetCell(Hive, Cell);
|
|||
|
oldsize = HvGetCellSize(Hive, oldaddress);
|
|||
|
ASSERT(oldsize > 0);
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
oldalloc = (ULONG)(oldsize + FIELD_OFFSET(HCELL, u.OldCell.u.UserData));
|
|||
|
} else {
|
|||
|
oldalloc = (ULONG)(oldsize + FIELD_OFFSET(HCELL, u.NewCell.u.UserData));
|
|||
|
}
|
|||
|
Type = HvGetCellType(Cell);
|
|||
|
|
|||
|
DHvCheckHive(Hive);
|
|||
|
|
|||
|
if (NewSize == oldalloc) {
|
|||
|
|
|||
|
//
|
|||
|
// This is a noop, return the same cell
|
|||
|
//
|
|||
|
NewCell = Cell;
|
|||
|
|
|||
|
} else if (NewSize < oldalloc) {
|
|||
|
|
|||
|
//
|
|||
|
// This is a shrink.
|
|||
|
//
|
|||
|
// PERFNOTE - IMPLEMENT THIS. Do nothing for now.
|
|||
|
//
|
|||
|
NewCell = Cell;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This is a grow.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// PERFNOTE - Someday we want to detect that there is a free neighbor
|
|||
|
// above us and grow into that neighbor if possible.
|
|||
|
// For now, always do the allocate, copy, free gig.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a new block of memory to hold the cell
|
|||
|
//
|
|||
|
|
|||
|
if ((NewCell = HvpDoAllocateCell(Hive, NewSize, Type)) == HCELL_NIL) {
|
|||
|
return HCELL_NIL;
|
|||
|
}
|
|||
|
ASSERT(HvIsCellAllocated(Hive, NewCell));
|
|||
|
newaddress = (PUCHAR)HvGetCell(Hive, NewCell);
|
|||
|
|
|||
|
//
|
|||
|
// oldaddress points to the old data block for the cell,
|
|||
|
// newaddress points to the new data block, copy the data
|
|||
|
//
|
|||
|
RtlMoveMemory(newaddress, oldaddress, oldsize);
|
|||
|
|
|||
|
//
|
|||
|
// Free the old block of memory
|
|||
|
//
|
|||
|
HvFreeCell(Hive, Cell);
|
|||
|
}
|
|||
|
|
|||
|
DHvCheckHive(Hive);
|
|||
|
return NewCell;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Procedure used for checking only (used in production systems, so
|
|||
|
// must always be here.)
|
|||
|
//
|
|||
|
BOOLEAN
|
|||
|
HvIsCellAllocated(
|
|||
|
PHHIVE Hive,
|
|||
|
HCELL_INDEX Cell
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Report whether the requested cell is allocated or not.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - containing Hive.
|
|||
|
|
|||
|
Cell - cel of interest
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if allocated, FALSE if not.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG Type;
|
|||
|
PHCELL Address;
|
|||
|
PHCELL Below;
|
|||
|
PHMAP_ENTRY Me;
|
|||
|
PHBIN Bin;
|
|||
|
ULONG Offset;
|
|||
|
LONG Size;
|
|||
|
|
|||
|
|
|||
|
ASSERT(Hive->Signature == HHIVE_SIGNATURE);
|
|||
|
|
|||
|
if (Hive->Flat == TRUE) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
Type = HvGetCellType(Cell);
|
|||
|
|
|||
|
if ( ((Cell & ~HCELL_TYPE_MASK) > Hive->Storage[Type].Length) || // off end
|
|||
|
(Cell % HCELL_PAD(Hive) != 0) // wrong alignment
|
|||
|
)
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
Address = HvpGetHCell(Hive, Cell);
|
|||
|
Me = HvpGetCellMap(Hive, Cell);
|
|||
|
if (Me == NULL) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
Bin = (PHBIN)((ULONG)(Me->BinAddress) & HMAP_BASE);
|
|||
|
Offset = (ULONG)Address - (ULONG)Bin;
|
|||
|
Size = Address->Size * -1;
|
|||
|
|
|||
|
if ( (Address->Size > 0) || // not allocated
|
|||
|
((Offset + (ULONG)Size) > Bin->Size) || // runs off bin, or too big
|
|||
|
(Offset < sizeof(HBIN)) // pts into bin header
|
|||
|
)
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (USE_OLD_CELL(Hive)) {
|
|||
|
if (Address->u.OldCell.Last != HBIN_NIL) {
|
|||
|
|
|||
|
if (Address->u.OldCell.Last > Bin->Size) { // bogus back pointer
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
Below = (PHCELL)((PUCHAR)Bin + Address->u.OldCell.Last);
|
|||
|
Size = (Below->Size < 0) ?
|
|||
|
Below->Size * -1 :
|
|||
|
Below->Size;
|
|||
|
|
|||
|
if ( ((ULONG)Below + Size) != (ULONG)Address ) { // no pt back
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|