/*++ Copyright (c) 1991 Microsoft Corporation Module Name: hivebin.c Abstract: This module implements HvpAddBin - used to grow a hive. Author: Bryan M. Willman (bryanwi) 27-Mar-92 Environment: Revision History: --*/ #include "cmp.h" // // Private function prototypes // BOOLEAN HvpCoalesceDiscardedBins( IN PHHIVE Hive, IN ULONG NeededSize, IN HSTORAGE_TYPE Type ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE,HvpAddBin) #pragma alloc_text(PAGE,HvpCoalesceDiscardedBins) #endif PHBIN HvpAddBin( IN PHHIVE Hive, IN ULONG NewSize, IN HSTORAGE_TYPE Type ) /*++ Routine Description: Grows either the Stable or Volatile storage of a hive by adding a new bin. Bin will be allocated space in Stable store (e.g. file) if Type == Stable. Memory image will be allocated and initialized. Map will be grown and filled in to describe the new bin. WARNING: When adding a new bin, if the CM_VIEW_SIZE boundary is crossed: - add a free bin with the remaining space to the first CM_VIEW_SIZE barrier - from the next CM_VIEW_SIZE window, add a new bin of the desired size. Of course, this applies only to stable storage. Arguments: Hive - supplies a pointer to the hive control structure for the hive of interest NewSize - size of the object caller wishes to put in the hive. New bin will be at least large enough to hold this. Type - Stable or Volatile Return Value: Pointer to the new BIN if we succeeded, NULL if we failed. --*/ { BOOLEAN UseForIo; PHBIN NewBin; PHBIN RemainingBin; ULONG OldLength; ULONG NewLength; ULONG CheckLength; ULONG OldMap; ULONG NewMap; ULONG OldTable; ULONG NewTable; PHMAP_DIRECTORY Dir = NULL; PHMAP_TABLE newt = NULL; PHMAP_ENTRY Me; PHCELL t; ULONG i; ULONG j; PULONG NewVector = NULL; PLIST_ENTRY Entry; PFREE_HBIN FreeBin = NULL; ULONG TotalDiscardedSize; PCMHIVE CmHive; PAGED_CODE(); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvpAddBin:\n")); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tHive=%p NewSize=%08lx\n",Hive,NewSize)); CmHive = (PCMHIVE)CONTAINING_RECORD(Hive, CMHIVE, Hive); RemainingBin = NULL; // // Round size up to account for bin overhead. Caller should // have accounted for cell overhead. // NewSize += sizeof(HBIN); if ((NewSize < HCELL_BIG_ROUND) && ((NewSize % HBLOCK_SIZE) > HBIN_THRESHOLD)) { NewSize += HBLOCK_SIZE; } // // Try not to create HBINs smaller than the page size of the machine // (it is not illegal to have bins smaller than the page size, but it // is less efficient) // NewSize = ROUND_UP(NewSize, ((HBLOCK_SIZE >= PAGE_SIZE) ? HBLOCK_SIZE : PAGE_SIZE)); // // see if there's a discarded HBIN of the right size // TotalDiscardedSize = 0; Retry: Entry = Hive->Storage[Type].FreeBins.Flink; while (Entry != &Hive->Storage[Type].FreeBins) { FreeBin = CONTAINING_RECORD(Entry, FREE_HBIN, ListEntry); TotalDiscardedSize += FreeBin->Size; if ((FreeBin->Size >= NewSize) && ((CmHive->GrowOnlyMode == FALSE) || (Type == Volatile)) ) { if (!HvMarkDirty(Hive, FreeBin->FileOffset + (Type * HCELL_TYPE_MASK), FreeBin->Size,TRUE)) { goto ErrorExit1; } NewSize = FreeBin->Size; ASSERT_LISTENTRY(&FreeBin->ListEntry); RemoveEntryList(&FreeBin->ListEntry); #ifdef HV_TRACK_FREE_SPACE Hive->Storage[Type].FreeStorage -= (NewSize - sizeof(HBIN)); ASSERT( (LONG)(Hive->Storage[Type].FreeStorage) >= 0 ); #endif if ( FreeBin->Flags & FREE_HBIN_DISCARDABLE ) { // // HBIN is still in memory, don't need any more allocs, just // fill in the block addresses. // Me = NULL; for (i=0;iFileOffset+i+(Type*HCELL_TYPE_MASK)); VALIDATE_CELL_MAP(__LINE__,Me,Hive,FreeBin->FileOffset+i+(Type*HCELL_TYPE_MASK)); Me->BlockAddress = HBIN_BASE(Me->BinAddress)+i; Me->BinAddress &= ~HMAP_DISCARDABLE; // we cannot have the FREE_BIN_DISCARDABLE flag set // and FREE_HBIN_INVIEW not set on a mapped bin. ASSERT( Me->BinAddress & HMAP_INPAGEDPOOL ); // we don't need to set it to NULL - just for debug purposes ASSERT( (Me->CmView = NULL) == NULL ); } (Hive->Free)(FreeBin, sizeof(FREE_HBIN)); #if DBG { UNICODE_STRING HiveName; RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpAddBin for (%p) (%.*S) reusing FreeBin %p at FileOffset %lx; Type = %lu\n", Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,HBIN_BASE(Me->BinAddress),((PHBIN)HBIN_BASE(Me->BinAddress))->FileOffset,(ULONG)Type)); } #endif return (PHBIN)HBIN_BASE(Me->BinAddress); } break; } Entry = Entry->Flink; } if ((Entry == &Hive->Storage[Type].FreeBins) && (TotalDiscardedSize >= NewSize)) { // // No sufficiently large discarded bin was found, // but the total discarded space is large enough. // Attempt to coalesce adjacent discarded bins into // a larger bin and retry. // if (HvpCoalesceDiscardedBins(Hive, NewSize, Type)) { goto Retry; } } // // we need these sooner to do the computations in case we allocate a new bin // OldLength = Hive->Storage[Type].Length; CheckLength = OldLength; // // Attempt to allocate the bin. // UseForIo = (BOOLEAN)((Type == Stable) ? TRUE : FALSE); if (Entry != &Hive->Storage[Type].FreeBins) { if( Type == Volatile ) { // // old plain method for volatile storage // // // Note we use ExAllocatePool directly here to avoid // charging quota for this bin again. When a bin // is discarded, its quota is not returned. This prevents // sparse hives from requiring more quota after // a reboot than on a running system. // NewBin = ExAllocatePoolWithTag((UseForIo) ? PagedPoolCacheAligned : PagedPool, NewSize, CM_HVBIN_TAG); if (NewBin == NULL) { InsertHeadList(&Hive->Storage[Type].FreeBins, Entry); #ifdef HV_TRACK_FREE_SPACE Hive->Storage[Type].FreeStorage += (NewSize - sizeof(HBIN)); #endif // this call is a nop //HvMarkClean(Hive, FreeBin->FileOffset, FreeBin->Size); goto ErrorExit1; } } else { // // for Stable, map the view containing the bin in memory // and fix the map // Me = HvpGetCellMap(Hive, FreeBin->FileOffset); VALIDATE_CELL_MAP(__LINE__,Me,Hive,FreeBin->FileOffset); if( Me->BinAddress & HMAP_INPAGEDPOOL ) { ASSERT( (Me->BinAddress & HMAP_INVIEW) == 0 ); // // bin is in paged pool; allocate backing store // NewBin = (Hive->Allocate)(NewSize, UseForIo,CM_FIND_LEAK_TAG15); if (NewBin == NULL) { InsertHeadList(&Hive->Storage[Type].FreeBins, Entry); #ifdef HV_TRACK_FREE_SPACE Hive->Storage[Type].FreeStorage += (NewSize - sizeof(HBIN)); #endif goto ErrorExit1; } } else { // // The view containing this bin has been unmapped; map it again // if( (Me->BinAddress & HMAP_INVIEW) == 0 ) { ASSERT( (Me->BinAddress & HMAP_INPAGEDPOOL) == 0 ); // // map the bin // if( !NT_SUCCESS(CmpMapThisBin((PCMHIVE)Hive,FreeBin->FileOffset,TRUE)) ) { InsertHeadList(&Hive->Storage[Type].FreeBins, Entry); #ifdef HV_TRACK_FREE_SPACE Hive->Storage[Type].FreeStorage += (NewSize - sizeof(HBIN)); #endif return NULL; } } ASSERT( Me->BinAddress & HMAP_INVIEW ); NewBin = (PHBIN)HBIN_BASE(Me->BinAddress); } } } else { #if 0 // // this is no longer neccesssary as Mm is faulting one page at a time for MNW streams // ASSERT( (CM_VIEW_SIZE >= PAGE_SIZE) && (CM_VIEW_SIZE >= HBLOCK_SIZE) ); // // Don't do unneccessary work for volatile storage or volatile hives // if( (Type == Stable) && (!(Hive->HiveFlags & HIVE_VOLATILE)) ) { ULONG RealHiveSize = OldLength + HBLOCK_SIZE; if( RealHiveSize != (RealHiveSize & (~(CM_VIEW_SIZE - 1)) ) ) { // // Hive size does not follow the CM_VIEW_SIZE increments pattern // ULONG FillUpSize; FillUpSize = ((OldLength + HBLOCK_SIZE + CM_VIEW_SIZE - 1) & (~(CM_VIEW_SIZE - 1))) - (OldLength + HBLOCK_SIZE); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"HvpAddBin for (%p) NewSize (%lx) ",Hive,NewSize)); if( FillUpSize >= NewSize ) { // // there is plenty of space in the remaining to the CM_VIEW_SIZE boundary to accomodate this bin // adjust the size of the bin // NewSize = FillUpSize; ASSERT( HvpCheckViewBoundary(CheckLength,CheckLength + NewSize - 1) == TRUE ); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Fits in the remaining to boundary, Adjusting size to %lx",NewSize)); } else { // // we don't have space to fit this bin in the remaining to the CM_VIEW_SIZE boundary // FillUpSize will be enlisted as a free bin. round up to CM_VIEW_SIZE // ASSERT( HvpCheckViewBoundary(CheckLength,CheckLength + NewSize - 1) == FALSE ); NewSize = ROUND_UP(NewSize, CM_VIEW_SIZE); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Does not fit in the remaining to boundary, Rounding size to %lx",NewSize)); } } else { // // Hive already follows the CM_VIEW_SIZE boundary pattern; don't break it // NewSize = ROUND_UP(NewSize, CM_VIEW_SIZE); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"hive size already aligned, Rounding size to %lx",NewSize)); } } #endif // // this is a totally new bin. Allocate it from paged pool // NewBin = (Hive->Allocate)(NewSize, UseForIo,CM_FIND_LEAK_TAG16); if (NewBin == NULL) { goto ErrorExit1; } } // // Init the bin // NewBin->Signature = HBIN_SIGNATURE; NewBin->Size = NewSize; NewBin->Spare = 0; t = (PHCELL)((PUCHAR)NewBin + sizeof(HBIN)); t->Size = NewSize - sizeof(HBIN); if (USE_OLD_CELL(Hive)) { t->u.OldCell.Last = (ULONG)HBIN_NIL; } if (Entry != &Hive->Storage[Type].FreeBins) { // // found a discarded HBIN we can use, just fill in the map and we // are done. // for (i=0;iFileOffset+i+(Type*HCELL_TYPE_MASK)); VALIDATE_CELL_MAP(__LINE__,Me,Hive,FreeBin->FileOffset+i+(Type*HCELL_TYPE_MASK)); Me->BlockAddress = (ULONG_PTR)NewBin + i; // // make sure to preserve the following flags: // HMAP_INVIEW|HMAP_INPAGEDPOOL // and to clear the flag // HMAP_DISCARDABLE // Me->BinAddress = (ULONG_PTR)((ULONG_PTR)NewBin | (Me->BinAddress&(HMAP_INVIEW|HMAP_INPAGEDPOOL))); Me->BinAddress &= ~HMAP_DISCARDABLE; if (i==0) { Me->BinAddress |= HMAP_NEWALLOC; Me->MemAlloc = NewSize; } else { Me->MemAlloc = 0; } } NewBin->FileOffset = FreeBin->FileOffset; (Hive->Free)(FreeBin, sizeof(FREE_HBIN)); #if DBG { UNICODE_STRING HiveName; RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpAddBin for (%p) (%.*S) reusing FreeBin %p at FileOffset %lx; Type = %lu\n", Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,NewBin,NewBin->FileOffset,(ULONG)Type)); } #endif return(NewBin); } // // Compute map growth needed, grow the map // if( (HvpCheckViewBoundary(CheckLength,CheckLength + NewSize - 1) == FALSE) && (NewSize < CM_VIEW_SIZE) // don't bother if we attempt to allocate a cell bigger then the view size // it'll cross the boundary anyway. ) { // // the bin to be allocated doesn't fit into the remaining // of this CM_VIEW_SIZE window. Allocate it from the next CM_VIEW_SIZE window // and add the remaining of this to the free bin list // CheckLength += (NewSize+HBLOCK_SIZE); CheckLength &= (~(CM_VIEW_SIZE - 1)); CheckLength -= HBLOCK_SIZE; #if DBG { UNICODE_STRING HiveName; RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpAddBin for (%p) (%.*S) crossing boundary at %lx Size %lx, newoffset= %lx\n",Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,OldLength,NewSize,CheckLength)); } #endif } NewLength = CheckLength + NewSize; NewBin->FileOffset = CheckLength; //CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"OldLength = %lx;NewLength = %lx (Type = %lx)\n",OldLength,NewLength,(ULONG)Type)); if( CmpCanGrowSystemHive(Hive,NewLength) == FALSE ) { // // OOPS! we have reached the hard quota limit on the system hive // goto ErrorExit2; } ASSERT((OldLength % HBLOCK_SIZE) == 0); ASSERT((CheckLength % HBLOCK_SIZE) == 0); ASSERT((NewLength % HBLOCK_SIZE) == 0); if (OldLength == 0) { // // Need to create the first table // newt = (PVOID)((Hive->Allocate)(sizeof(HMAP_TABLE), FALSE,CM_FIND_LEAK_TAG17)); if (newt == NULL) { goto ErrorExit2; } RtlZeroMemory(newt, sizeof(HMAP_TABLE)); Hive->Storage[Type].SmallDir = newt; Hive->Storage[Type].Map = (PHMAP_DIRECTORY)&(Hive->Storage[Type].SmallDir); } if (OldLength > 0) { OldMap = (OldLength-1) / HBLOCK_SIZE; } else { OldMap = 0; } NewMap = (NewLength-1) / HBLOCK_SIZE; OldTable = OldMap / HTABLE_SLOTS; NewTable = NewMap / HTABLE_SLOTS; #if DBG if( Type == Stable ) { UNICODE_STRING HiveName; RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpAddBin for (%p) (%.*S) Adding new bin %p at FileOffset %lx; Type = %lu\n",Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,NewBin,NewBin->FileOffset,(ULONG)Type)); } #endif if (NewTable != OldTable) { // // Need some new Tables // if (OldTable == 0) { // // We can get here even if the real directory has already been created. // This can happen if we create the directory then fail on something // later. So we need to handle the case where a directory already exists. // if (Hive->Storage[Type].Map == (PHMAP_DIRECTORY)&Hive->Storage[Type].SmallDir) { ASSERT(Hive->Storage[Type].SmallDir != NULL); // // Need a real directory // Dir = (Hive->Allocate)(sizeof(HMAP_DIRECTORY), FALSE,CM_FIND_LEAK_TAG18); if (Dir == NULL) { goto ErrorExit2; } RtlZeroMemory(Dir, sizeof(HMAP_DIRECTORY)); Dir->Directory[0] = Hive->Storage[Type].SmallDir; Hive->Storage[Type].SmallDir = NULL; Hive->Storage[Type].Map = Dir; } else { ASSERT(Hive->Storage[Type].SmallDir == NULL); } } Dir = Hive->Storage[Type].Map; // // Fill in directory with new tables // if (HvpAllocateMap(Hive, Dir, OldTable+1, NewTable) == FALSE) { goto ErrorExit3; } } // // If Type == Stable, and the hive is not marked WholeHiveVolatile, // grow the file, the log, and the DirtyVector // if( !NT_SUCCESS(HvpAdjustHiveFreeDisplay(Hive,NewLength,Type)) ) { goto ErrorExit3; } Hive->Storage[Type].Length = NewLength; if ((Type == Stable) && (!(Hive->HiveFlags & HIVE_VOLATILE))) { // // Grow the dirtyvector // NewVector = (PULONG)(Hive->Allocate)(ROUND_UP(NewMap+1,sizeof(ULONG)), TRUE,CM_FIND_LEAK_TAG19); if (NewVector == NULL) { goto ErrorExit3; } RtlZeroMemory(NewVector, NewMap+1); if (Hive->DirtyVector.Buffer != NULL) { RtlCopyMemory( (PVOID)NewVector, (PVOID)Hive->DirtyVector.Buffer, OldMap+1 ); (Hive->Free)(Hive->DirtyVector.Buffer, Hive->DirtyAlloc); } RtlInitializeBitMap( &(Hive->DirtyVector), NewVector, NewLength / HSECTOR_SIZE ); Hive->DirtyAlloc = ROUND_UP(NewMap+1,sizeof(ULONG)); // // Grow the log // if ( ! (HvpGrowLog2(Hive, NewSize))) { goto ErrorExit4; } // // Grow the primary // if ( ! (Hive->FileSetSize)( Hive, HFILE_TYPE_PRIMARY, NewLength+HBLOCK_SIZE, OldLength+HBLOCK_SIZE ) ) { goto ErrorExit4; } // // Mark new bin dirty so all control structures get written at next sync // ASSERT( ((NewLength - OldLength) % HBLOCK_SIZE) == 0 ); if ( ! HvMarkDirty(Hive, OldLength,NewLength - OldLength,FALSE)) { // // we have grown the hive, so the new bins are in paged pool !!! // goto ErrorExit4; } } // // Add the remaining to the free bin list // if( CheckLength != OldLength ) { // // Allocate the bin from pagedpool (first flush will update the file image and free the memory) // RemainingBin = (Hive->Allocate)(CheckLength - OldLength, UseForIo,CM_FIND_LEAK_TAG20); if (RemainingBin == NULL) { goto ErrorExit4; } RemainingBin->Signature = HBIN_SIGNATURE; RemainingBin->Size = CheckLength - OldLength; RemainingBin->FileOffset = OldLength; RemainingBin->Spare = 0; t = (PHCELL)((PUCHAR)RemainingBin + sizeof(HBIN)); t->Size = RemainingBin->Size - sizeof(HBIN); if (USE_OLD_CELL(Hive)) { t->u.OldCell.Last = (ULONG)HBIN_NIL; } // // add the free bin to the free bin list and update the map. // FreeBin = (Hive->Allocate)(sizeof(FREE_HBIN), FALSE,CM_FIND_LEAK_TAG21); if (FreeBin == NULL) { goto ErrorExit5; } FreeBin->Size = CheckLength - OldLength; FreeBin->FileOffset = OldLength; FreeBin->Flags = FREE_HBIN_DISCARDABLE; InsertHeadList(&Hive->Storage[Type].FreeBins, &FreeBin->ListEntry); #ifdef HV_TRACK_FREE_SPACE Hive->Storage[Type].FreeStorage += (FreeBin->Size - sizeof(HBIN)); ASSERT( Hive->Storage[Type].FreeStorage <= Hive->Storage[Type].Length ); #endif ASSERT_LISTENTRY(&FreeBin->ListEntry); ASSERT_LISTENTRY(FreeBin->ListEntry.Flink); for (i = OldLength; i < CheckLength; i += HBLOCK_SIZE) { Me = HvpGetCellMap(Hive, i + (Type*HCELL_TYPE_MASK)); VALIDATE_CELL_MAP(__LINE__,Me,Hive,i + (Type*HCELL_TYPE_MASK)); Me->BinAddress = (ULONG_PTR)RemainingBin | HMAP_DISCARDABLE | HMAP_INPAGEDPOOL; if( i == OldLength ) { Me->BinAddress |= HMAP_NEWALLOC; Me->MemAlloc = CheckLength - OldLength; } else { Me->MemAlloc = 0; } Me->BlockAddress = (ULONG_PTR)FreeBin; // we don't need to set it to NULL - just for debug purposes ASSERT( (Me->CmView = NULL) == NULL ); } #if DBG { if( Type == Stable ) { UNICODE_STRING HiveName; RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpAddBin for (%p) (%.*S) adding bin starting at %lx size %lx to FreeBinList\n",Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,FreeBin->FileOffset,FreeBin->Size)); } } #endif } // // Fill in the map, mark new allocation. // j = 0; for (i = CheckLength; i < NewLength; i += HBLOCK_SIZE) { Me = HvpGetCellMap(Hive, i + (Type*HCELL_TYPE_MASK)); VALIDATE_CELL_MAP(__LINE__,Me,Hive,i + (Type*HCELL_TYPE_MASK)); Me->BlockAddress = (ULONG_PTR)NewBin + j; Me->BinAddress = (ULONG_PTR)NewBin; Me->BinAddress |= HMAP_INPAGEDPOOL; // we don't need to set it to NULL - just for debug purposes ASSERT( (Me->CmView = NULL) == NULL ); if (j == 0) { // // First block of allocation, mark it. // Me->BinAddress |= HMAP_NEWALLOC; Me->MemAlloc = NewSize; } else { Me->MemAlloc = 0; } j += HBLOCK_SIZE; } if( Type == Stable) { CmpUpdateSystemHiveHysteresis(Hive,NewLength,OldLength); } return NewBin; ErrorExit5: if( RemainingBin != NULL ){ (Hive->Free)(RemainingBin, RemainingBin->Size); } ErrorExit4: if((Type == Stable) && (!(Hive->HiveFlags & HIVE_VOLATILE))) { RtlInitializeBitMap(&Hive->DirtyVector, NewVector, OldLength / HSECTOR_SIZE); Hive->DirtyCount = RtlNumberOfSetBits(&Hive->DirtyVector); } ErrorExit3: Hive->Storage[Type].Length = OldLength; HvpFreeMap(Hive, Dir, OldTable+1, NewTable); ErrorExit2: (Hive->Free)(NewBin, NewSize); if( newt != NULL ) { (Hive->Free)(newt,sizeof(HMAP_TABLE)); } ErrorExit1: return NULL; } // Dragos: Modified functions BOOLEAN HvpCoalesceDiscardedBins( IN PHHIVE Hive, IN ULONG NeededSize, IN HSTORAGE_TYPE Type ) /*++ Routine Description: Walks through the list of discarded bins and attempts to coalesce adjacent discarded bins into one larger bin in order to satisfy an allocation request. It doesn't coalesce bins over the CM_VIEW_SIZE boundary. It doesn't coalesce bins from paged pool with bins mapped in system cache views. Arguments: Hive - Supplies pointer to hive control block. NeededSize - Supplies size of allocation needed. Type - Stable or Volatile Return Value: TRUE - A bin of the desired size was created. FALSE - No bin of the desired size could be created. --*/ { PLIST_ENTRY List; PFREE_HBIN FreeBin; PFREE_HBIN PreviousFreeBin; PFREE_HBIN NextFreeBin; PHMAP_ENTRY Map; PHMAP_ENTRY PreviousMap; PHMAP_ENTRY NextMap; ULONG MapBlock; List = Hive->Storage[Type].FreeBins.Flink; while (List != &Hive->Storage[Type].FreeBins) { FreeBin = CONTAINING_RECORD(List, FREE_HBIN, ListEntry); if ((FreeBin->Flags & FREE_HBIN_DISCARDABLE)==0) { Map = HvpGetCellMap(Hive, FreeBin->FileOffset); VALIDATE_CELL_MAP(__LINE__,Map,Hive,FreeBin->FileOffset); // // Scan backwards, coalescing previous discarded bins // while (FreeBin->FileOffset > 0) { PreviousMap = HvpGetCellMap(Hive, FreeBin->FileOffset - HBLOCK_SIZE); VALIDATE_CELL_MAP(__LINE__,PreviousMap,Hive,FreeBin->FileOffset - HBLOCK_SIZE); if( (BIN_MAP_ALLOCATION_TYPE(Map) != BIN_MAP_ALLOCATION_TYPE(PreviousMap)) || // different allocation type ((PreviousMap->BinAddress & HMAP_DISCARDABLE) == 0) // previous bin is not discardable ){ break; } PreviousFreeBin = (PFREE_HBIN)PreviousMap->BlockAddress; if (PreviousFreeBin->Flags & FREE_HBIN_DISCARDABLE) { // // this bin has not yet been discarded; can't coalesce with it. // break; } if( HvpCheckViewBoundary(PreviousFreeBin->FileOffset,FreeBin->Size + PreviousFreeBin->Size - 1) == FALSE ) { // // don't coalesce bins over the CM_VIEW_SIZE boundary // // substract 1 because addresses are from 0 to size - 1 !!! // break; } RemoveEntryList(&PreviousFreeBin->ListEntry); // // Fill in all the old map entries with the new one. // for (MapBlock = 0; MapBlock < PreviousFreeBin->Size; MapBlock += HBLOCK_SIZE) { PreviousMap = HvpGetCellMap(Hive, PreviousFreeBin->FileOffset + MapBlock); VALIDATE_CELL_MAP(__LINE__,PreviousMap,Hive,PreviousFreeBin->FileOffset + MapBlock); PreviousMap->BlockAddress = (ULONG_PTR)FreeBin; } FreeBin->FileOffset = PreviousFreeBin->FileOffset; FreeBin->Size += PreviousFreeBin->Size; (Hive->Free)(PreviousFreeBin, sizeof(FREE_HBIN)); } // // Scan forwards, coalescing subsequent discarded bins // while ((FreeBin->FileOffset + FreeBin->Size) < Hive->Storage[Type].Length) { NextMap = HvpGetCellMap(Hive, FreeBin->FileOffset + FreeBin->Size); VALIDATE_CELL_MAP(__LINE__,NextMap,Hive,FreeBin->FileOffset + FreeBin->Size); if( (BIN_MAP_ALLOCATION_TYPE(Map) != BIN_MAP_ALLOCATION_TYPE(NextMap)) || // different allocation type ((NextMap->BinAddress & HMAP_DISCARDABLE) == 0) // previous bin is not discardable ){ break; } NextFreeBin = (PFREE_HBIN)NextMap->BlockAddress; if (NextFreeBin->Flags & FREE_HBIN_DISCARDABLE) { // // this bin has not yet been discarded; can't coalesce with it. // break; } if( HvpCheckViewBoundary(FreeBin->FileOffset,FreeBin->Size + NextFreeBin->Size - 1) == FALSE ) { // // don't coalesce bins over the CM_VIEW_SIZE boundary // // substract 1 because addresses are from 0 to size - 1 !!! // break; } RemoveEntryList(&NextFreeBin->ListEntry); // // Fill in all the old map entries with the new one. // for (MapBlock = 0; MapBlock < NextFreeBin->Size; MapBlock += HBLOCK_SIZE) { NextMap = HvpGetCellMap(Hive, NextFreeBin->FileOffset + MapBlock); VALIDATE_CELL_MAP(__LINE__,NextMap,Hive,NextFreeBin->FileOffset + MapBlock); NextMap->BlockAddress = (ULONG_PTR)FreeBin; } FreeBin->Size += NextFreeBin->Size; (Hive->Free)(NextFreeBin, sizeof(FREE_HBIN)); } if (FreeBin->Size >= NeededSize) { return(TRUE); } } List=List->Flink; } return(FALSE); }