Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2439 lines
65 KiB

  1. //depot/main/Base/ntos/config/hivecell.c#14 - integrate change 19035 (text)
  2. /*++
  3. Copyright (c) 1991 Microsoft Corporation
  4. Module Name:
  5. hivecell.c
  6. Abstract:
  7. This module implements hive cell procedures.
  8. Author:
  9. Bryan M. Willman (bryanwi) 27-Mar-92
  10. Environment:
  11. Revision History:
  12. Dragos C. Sambotin (dragoss) 22-Dec-98
  13. Requests for cells bigger than 1K are doubled. This way
  14. we avoid fragmentation and we make the value-growing
  15. process more flexible.
  16. Dragos C. Sambotin (dragoss) 13-Jan-99
  17. At boot time, order the free cells list ascending.
  18. --*/
  19. #include "cmp.h"
  20. //
  21. // Private procedures
  22. //
  23. HCELL_INDEX
  24. HvpDoAllocateCell(
  25. PHHIVE Hive,
  26. ULONG NewSize,
  27. HSTORAGE_TYPE Type,
  28. HCELL_INDEX Vicinity
  29. );
  30. ULONG
  31. HvpAllocateInBin(
  32. PHHIVE Hive,
  33. PHBIN Bin,
  34. ULONG Size,
  35. ULONG Type
  36. );
  37. BOOLEAN
  38. HvpIsFreeNeighbor(
  39. PHHIVE Hive,
  40. PHBIN Bin,
  41. PHCELL FreeCell,
  42. PHCELL *FreeNeighbor,
  43. HSTORAGE_TYPE Type
  44. );
  45. VOID
  46. HvpDelistBinFreeCells(
  47. PHHIVE Hive,
  48. PHBIN Bin,
  49. HSTORAGE_TYPE Type
  50. );
  51. #define SIXTEEN_K 0x4000
  52. // Double requests bigger than 1KB
  53. // CmpSetValueKeyExisting always allocates a bigger data
  54. // value cell exactly the required size. This creates
  55. // problems when somebody slowly grows a value one DWORD
  56. // at a time to some enormous size. An easy fix for this
  57. // would be to set a certain threshold (like 1K). Once a
  58. // value size crosses that threshold, allocate a new cell
  59. // that is twice the old size. So the actual allocated
  60. // size would grow to 1k, then 2k, 4k, 8k, 16k, 32k,etc.
  61. // This will reduce the fragmentation.
  62. //
  63. // Note:
  64. // For 5.1, this needs to be coherent with CM_KEY_VALUE_BIG
  65. //
  66. //
  67. #define HvpAdjustCellSize(Size) \
  68. { \
  69. ULONG onek = SIXTEEN_K; \
  70. ULONG Limit = 0; \
  71. \
  72. while( Size > onek ) { \
  73. onek<<=1; \
  74. Limit++; \
  75. } \
  76. \
  77. Size = Limit?onek:Size; \
  78. }
  79. extern BOOLEAN HvShutdownComplete; // Set to true after shutdown
  80. // to disable any further I/O
  81. //#define CM_CHECK_FREECELL_LEAKS
  82. #ifdef CM_CHECK_FREECELL_LEAKS
  83. VOID
  84. HvpCheckBinForFreeCell(
  85. PHHIVE Hive,
  86. PHBIN Bin,
  87. ULONG NewSize,
  88. HSTORAGE_TYPE Type
  89. );
  90. VOID
  91. HvpCheckFreeCells( PHHIVE Hive,
  92. ULONG NewSize,
  93. HSTORAGE_TYPE Type
  94. );
  95. #endif //CM_CHECK_FREECELL_LEAKS
  96. #ifdef ALLOC_PRAGMA
  97. #pragma alloc_text(PAGE,HvpGetHCell)
  98. #pragma alloc_text(PAGE,HvpGetCellMapped)
  99. #pragma alloc_text(PAGE,HvpReleaseCellMapped)
  100. #pragma alloc_text(PAGE,HvpGetCellPaged)
  101. #pragma alloc_text(PAGE,HvpGetCellFlat)
  102. #pragma alloc_text(PAGE,HvpGetCellMap)
  103. #pragma alloc_text(PAGE,HvGetCellSize)
  104. #pragma alloc_text(PAGE,HvAllocateCell)
  105. #pragma alloc_text(PAGE,HvpDoAllocateCell)
  106. #pragma alloc_text(PAGE,HvFreeCell)
  107. #pragma alloc_text(PAGE,HvpIsFreeNeighbor)
  108. #pragma alloc_text(PAGE,HvpEnlistFreeCell)
  109. #pragma alloc_text(PAGE,HvpDelistFreeCell)
  110. #pragma alloc_text(PAGE,HvReallocateCell)
  111. #pragma alloc_text(PAGE,HvIsCellAllocated)
  112. #pragma alloc_text(PAGE,HvpAllocateInBin)
  113. #pragma alloc_text(PAGE,HvpDelistBinFreeCells)
  114. #ifdef NT_RENAME_KEY
  115. #pragma alloc_text(PAGE,HvDuplicateCell)
  116. #endif
  117. #ifdef CM_CHECK_FREECELL_LEAKS
  118. #pragma alloc_text(PAGE,HvpCheckBinForFreeCell)
  119. #pragma alloc_text(PAGE,HvpCheckFreeCells)
  120. #endif //CM_CHECK_FREECELL_LEAKS
  121. #pragma alloc_text(PAGE,HvAutoCompressCheck)
  122. #pragma alloc_text(PAGE,HvShiftCell)
  123. #endif
  124. #ifdef CM_CHECK_FREECELL_LEAKS
  125. VOID
  126. HvpCheckBinForFreeCell(
  127. PHHIVE Hive,
  128. PHBIN Bin,
  129. ULONG NewSize,
  130. HSTORAGE_TYPE Type
  131. )
  132. {
  133. PHCELL p;
  134. ULONG celloffset;
  135. ULONG size;
  136. ULONG Index1,Index2;
  137. HCELL_INDEX cellindex;
  138. ULONG BinOffset = Bin->FileOffset;
  139. //
  140. // Scan all the cells in the bin, total free and allocated, check
  141. // for impossible pointers.
  142. //
  143. celloffset = sizeof(HBIN);
  144. p = (PHCELL)((PUCHAR)Bin + sizeof(HBIN));
  145. while (p < (PHCELL)((PUCHAR)Bin + Bin->Size)) {
  146. //
  147. // if free cell, check it out, add it to free list for hive
  148. //
  149. if (p->Size >= 0) {
  150. size = (ULONG)p->Size;
  151. if ( (size > Bin->Size) ||
  152. ( (PHCELL)(size + (PUCHAR)p) >
  153. (PHCELL)((PUCHAR)Bin + Bin->Size) ) ||
  154. ((size % HCELL_PAD(Hive)) != 0) ||
  155. (size == 0) )
  156. {
  157. return;
  158. }
  159. //
  160. // cell is free, and is not obviously corrupt, add to free list
  161. //
  162. celloffset = (ULONG)((PUCHAR)p - (PUCHAR)Bin);
  163. cellindex = BinOffset + celloffset;
  164. if( size >= NewSize ) {
  165. //
  166. // we found a free cell which was not detected by HvpFindFreeCell
  167. //
  168. HvpComputeIndex(Index1, size);
  169. HvpComputeIndex(Index2, NewSize);
  170. DbgPrint("HvpCheckBinForFreeCell: Free cell not found! %lx, Index1 = %lu Index2= %lu\n",cellindex,Index1,Index2);
  171. DbgBreakPoint();
  172. }
  173. } else {
  174. size = (ULONG)(p->Size * -1);
  175. if ( (size > Bin->Size) ||
  176. ( (PHCELL)(size + (PUCHAR)p) >
  177. (PHCELL)((PUCHAR)Bin + Bin->Size) ) ||
  178. ((size % HCELL_PAD(Hive)) != 0) ||
  179. (size == 0) )
  180. {
  181. return;
  182. }
  183. }
  184. ASSERT( ((LONG)size) >= 0);
  185. p = (PHCELL)((PUCHAR)p + size);
  186. }
  187. }
  188. VOID
  189. HvpCheckFreeCells( PHHIVE Hive,
  190. ULONG NewSize,
  191. HSTORAGE_TYPE Type
  192. )
  193. {
  194. HCELL_INDEX p;
  195. ULONG Length;
  196. PHMAP_ENTRY t;
  197. PHBIN Bin;
  198. PFREE_HBIN FreeBin;
  199. p = 0x80000000 * Type;
  200. Length = Hive->Storage[Type].Length;
  201. //
  202. // for each bin in the space
  203. //
  204. while (p < Length) {
  205. t = HvpGetCellMap(Hive, p);
  206. if (t == NULL) {
  207. DbgPrint("HvpCheckFreeCells: Couldn't get map for %lx\n",p);
  208. return;
  209. }
  210. if( (t->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0) {
  211. //
  212. // view is not mapped, neither in paged pool
  213. // try to map it.
  214. //
  215. if( !NT_SUCCESS(CmpMapThisBin((PCMHIVE)Hive,p,FALSE)) ) {
  216. //
  217. // we cannot map this bin due to insufficient resources.
  218. //
  219. DbgPrint("HvpCheckFreeCells: Couldn't map bin for %lx\n",p);
  220. return;
  221. }
  222. }
  223. if ((t->BinAddress & HMAP_DISCARDABLE) == 0) {
  224. Bin = (PHBIN)HBIN_BASE(t->BinAddress);
  225. //
  226. // bin header valid?
  227. //
  228. if ( (Bin->Size > Length) ||
  229. (Bin->Signature != HBIN_SIGNATURE) ||
  230. (Bin->FileOffset != p)
  231. )
  232. {
  233. DbgPrint("HvpCheckFreeCells: Invalid bin header for bin %p\n",Bin);
  234. return;
  235. }
  236. //
  237. // structure inside the bin valid?
  238. //
  239. HvpCheckBinForFreeCell(Hive, Bin, NewSize,Type);
  240. p = (ULONG)p + Bin->Size;
  241. } else {
  242. //
  243. // Bin is not present, skip it and advance to the next one.
  244. //
  245. FreeBin = (PFREE_HBIN)t->BlockAddress;
  246. p+=FreeBin->Size;
  247. }
  248. }
  249. }
  250. #endif //CM_CHECK_FREECELL_LEAKS
  251. PHCELL
  252. HvpGetHCell(PHHIVE Hive,
  253. HCELL_INDEX Cell
  254. )
  255. /*++
  256. Routine Description:
  257. Had to make it a function instead of a macro, because HvGetCell
  258. might fail now.
  259. Arguments:
  260. Return Value:
  261. --*/
  262. {
  263. PCELL_DATA pcell;
  264. pcell = HvGetCell(Hive,Cell);
  265. if( pcell == NULL ) {
  266. //
  267. // we couldn't map view for this cell
  268. //
  269. return NULL;
  270. }
  271. return
  272. ( USE_OLD_CELL(Hive) ?
  273. CONTAINING_RECORD(pcell,
  274. HCELL,
  275. u.OldCell.u.UserData) :
  276. CONTAINING_RECORD(pcell,
  277. HCELL,
  278. u.NewCell.u.UserData));
  279. }
  280. // Dragos: Changed functions!
  281. //
  282. // Cell Procedures
  283. //
  284. #ifndef _CM_LDR_
  285. VOID
  286. HvpReleaseCellMapped(
  287. PHHIVE Hive,
  288. HCELL_INDEX Cell
  289. )
  290. /*++
  291. Routine Description:
  292. This routine should never be called directly, always call it
  293. via the HvReleaseCell() macro.
  294. This routine is intended to work with mapped hives. It is intended
  295. to prevent views that are still in use to get unmapped
  296. Arguments:
  297. Hive - supplies a pointer to the hive control structure for the
  298. hive of interest
  299. Cell - supplies HCELL_INDEX of cell to return address for
  300. Return Value:
  301. none
  302. --*/
  303. {
  304. ULONG Type;
  305. ULONG Table;
  306. ULONG Block;
  307. ULONG Offset;
  308. PHCELL pcell;
  309. PHMAP_ENTRY Map;
  310. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"HvpReleaseCellMapped:\n"));
  311. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"\tHive=%p Cell=%08lx\n",Hive,Cell));
  312. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  313. ASSERT(Cell != HCELL_NIL);
  314. ASSERT(Hive->Flat == FALSE);
  315. ASSERT((Cell & (HCELL_PAD(Hive)-1))==0);
  316. ASSERT_CM_LOCK_OWNED();
  317. #if DBG
  318. if (HvGetCellType(Cell) == Stable) {
  319. ASSERT(Cell >= sizeof(HBIN));
  320. } else {
  321. ASSERT(Cell >= (HCELL_TYPE_MASK + sizeof(HBIN)));
  322. }
  323. #endif
  324. if( HvShutdownComplete == TRUE ) {
  325. //
  326. // at shutdown we need to unmap all views
  327. //
  328. #if DBG
  329. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpReleaseCellMapped called after shutdown for Hive = %p Cell = %lx\n",Hive,(ULONG)Cell));
  330. #endif
  331. return;
  332. }
  333. Type = HvGetCellType(Cell);
  334. Table = (Cell & HCELL_TABLE_MASK) >> HCELL_TABLE_SHIFT;
  335. Block = (Cell & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
  336. Offset = (Cell & HCELL_OFFSET_MASK);
  337. ASSERT((Cell - (Type * HCELL_TYPE_MASK)) < Hive->Storage[Type].Length);
  338. Map = &((Hive->Storage[Type].Map)->Directory[Table]->Table[Block]);
  339. CmLockHiveViews ((PCMHIVE)Hive);
  340. if( Map->BinAddress & HMAP_INVIEW ) {
  341. PCM_VIEW_OF_FILE CmView;
  342. CmView = Map->CmView;
  343. ASSERT( CmView != NULL );
  344. ASSERT( CmView->ViewAddress != NULL );
  345. ASSERT( CmView->UseCount != 0 );
  346. ASSERT( CmView->UseCount != 0 );
  347. CmView->UseCount--;
  348. } else {
  349. //
  350. // Bin is in memory (allocated from paged pool) ==> do nothing
  351. //
  352. ASSERT( Map->BinAddress & HMAP_INPAGEDPOOL );
  353. }
  354. ASSERT( ((PCMHIVE)Hive)->UseCount != 0 );
  355. ((PCMHIVE)Hive)->UseCount--;
  356. CmUnlockHiveViews ((PCMHIVE)Hive);
  357. ASSERT( HBIN_BASE(Map->BinAddress) != 0);
  358. }
  359. struct _CELL_DATA *
  360. HvpGetCellMapped(
  361. PHHIVE Hive,
  362. HCELL_INDEX Cell
  363. )
  364. /*++
  365. Routine Description:
  366. This routine should never be called directly, always call it
  367. via the HvGetCell() macro.
  368. This routine is intended to work with mapped hives.
  369. Arguments:
  370. Hive - supplies a pointer to the hive control structure for the
  371. hive of interest
  372. Cell - supplies HCELL_INDEX of cell to return address for
  373. Return Value:
  374. Address of Cell in memory. Assert or BugCheck if error.
  375. --*/
  376. {
  377. ULONG Type;
  378. ULONG Table;
  379. ULONG Block;
  380. ULONG Offset;
  381. PHCELL pcell;
  382. PHMAP_ENTRY Map;
  383. LONG Size;
  384. PUCHAR FaultAddress;
  385. PUCHAR EndOfCell;
  386. UCHAR TmpChar;
  387. PHBIN Bin;
  388. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"HvGetCellPaged:\n"));
  389. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"\tHive=%p Cell=%08lx\n",Hive,Cell));
  390. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  391. ASSERT(Cell != HCELL_NIL);
  392. ASSERT(Hive->Flat == FALSE);
  393. ASSERT((Cell & (HCELL_PAD(Hive)-1))==0);
  394. ASSERT_CM_LOCK_OWNED();
  395. #if 0
  396. if (HvGetCellType(Cell) == Stable) {
  397. ASSERT(Cell >= sizeof(HBIN));
  398. } else {
  399. ASSERT(Cell >= (HCELL_TYPE_MASK + sizeof(HBIN)));
  400. }
  401. #endif
  402. if( HvShutdownComplete == TRUE ) {
  403. //
  404. // at shutdown we need to unmap all views
  405. //
  406. #if DBG
  407. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpGetCellMapped called after shutdown for Hive = %p Cell = %lx\n",Hive,(ULONG)Cell));
  408. #endif
  409. return NULL;
  410. }
  411. Type = HvGetCellType(Cell);
  412. Table = (Cell & HCELL_TABLE_MASK) >> HCELL_TABLE_SHIFT;
  413. Block = (Cell & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
  414. Offset = (Cell & HCELL_OFFSET_MASK);
  415. ASSERT((Cell - (Type * HCELL_TYPE_MASK)) < Hive->Storage[Type].Length);
  416. Map = &((Hive->Storage[Type].Map)->Directory[Table]->Table[Block]);
  417. CmLockHiveViews ((PCMHIVE)Hive);
  418. if( Map->BinAddress & HMAP_INPAGEDPOOL ) {
  419. //
  420. // Bin is in memory (allocated from paged pool) ==> do nothing
  421. //
  422. } else {
  423. PCM_VIEW_OF_FILE CmView;
  424. //
  425. // bin is either mapped, or invalid
  426. //
  427. ASSERT( Type == Stable );
  428. if( (Map->BinAddress & HMAP_INVIEW) == 0 ) {
  429. //
  430. // map the bin
  431. //
  432. if( !NT_SUCCESS (CmpMapCmView((PCMHIVE)Hive,Cell/*+HBLOCK_SIZE*/,&CmView,TRUE) ) ) {
  433. //
  434. // caller of HvGetCell should raise an STATUS_INSUFFICIENT_RESOURCES
  435. // error as a result of this.!!!!
  436. //
  437. CmUnlockHiveViews ((PCMHIVE)Hive);
  438. return NULL;
  439. }
  440. #if DBG
  441. if(CmView != Map->CmView) {
  442. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmView = %p Map->CmView = %p\n",CmView,Map->CmView));
  443. }
  444. #endif
  445. ASSERT( CmView == Map->CmView );
  446. } else {
  447. CmView = Map->CmView;
  448. }
  449. //
  450. // touch the view
  451. //
  452. CmpTouchView((PCMHIVE)Hive,CmView,(ULONG)Cell);
  453. //
  454. // don't hurt ourselves if not neccessary
  455. //
  456. if(Hive->ReleaseCellRoutine) CmView->UseCount++;
  457. }
  458. //
  459. // don't hurt ourselves if not neccessary
  460. //
  461. if(Hive->ReleaseCellRoutine) ((PCMHIVE)Hive)->UseCount++;
  462. CmUnlockHiveViews ((PCMHIVE)Hive);
  463. ASSERT( HBIN_BASE(Map->BinAddress) != 0);
  464. ASSERT((Map->BinAddress & HMAP_DISCARDABLE) == 0);
  465. #ifdef CM_CHECK_MAP_NO_READ_SCHEME
  466. if( Map->BinAddress & HMAP_INVIEW ) {
  467. PHMAP_ENTRY TempMap;
  468. Bin = (PHBIN)HBIN_BASE(Map->BinAddress);
  469. ASSERT( Bin->Signature == HBIN_SIGNATURE );
  470. TempMap = HvpGetCellMap(Hive, Bin->FileOffset);
  471. VALIDATE_CELL_MAP(__LINE__,TempMap,Hive,Bin->FileOffset);
  472. ASSERT( TempMap->BinAddress & HMAP_NEWALLOC );
  473. }
  474. #endif //CM_CHECK_MAP_NO_READ_SCHEME
  475. pcell = (PHCELL)((ULONG_PTR)(Map->BlockAddress) + Offset);
  476. PERFINFO_HIVECELL_REFERENCE_PAGED(Hive, pcell, Cell, Type, Map);
  477. #ifdef CM_MAP_NO_READ
  478. //
  479. // we need to make sure all the cell's data is faulted in inside a
  480. // try/except block, as the IO to fault the data in can throw exceptions
  481. // STATUS_INSUFFICIENT_RESOURCES, in particular
  482. //
  483. try {
  484. //
  485. // this will fault in the first page containing the data
  486. //
  487. Size = pcell->Size;
  488. if( Size < 0 ) {
  489. Size *= -1;
  490. }
  491. //
  492. // check for bogus size
  493. //
  494. Bin = (PHBIN)HBIN_BASE(Map->BinAddress);
  495. if ( (Offset + (ULONG)Size) > Bin->Size ) {
  496. //
  497. // runs off bin; disallow access to this cell
  498. //
  499. //
  500. // restore the usecounts
  501. //
  502. CmLockHiveViews ((PCMHIVE)Hive);
  503. if( (Map->BinAddress & HMAP_INPAGEDPOOL) == 0 ) {
  504. ASSERT( Map->CmView != NULL );
  505. if(Hive->ReleaseCellRoutine) Map->CmView->UseCount--;
  506. }
  507. if(Hive->ReleaseCellRoutine) ((PCMHIVE)Hive)->UseCount--;
  508. CmUnlockHiveViews ((PCMHIVE)Hive);
  509. return NULL;
  510. }
  511. //
  512. // Now stand here like a man and fault in all pages storing cell's data
  513. //
  514. EndOfCell = (PUCHAR)((PUCHAR)pcell + Size);
  515. FaultAddress = (PUCHAR)((PUCHAR)(Map->BlockAddress) + ROUND_UP(Offset,PAGE_SIZE));
  516. while( FaultAddress < EndOfCell ) {
  517. TmpChar = *FaultAddress;
  518. FaultAddress += PAGE_SIZE;
  519. }
  520. } except (EXCEPTION_EXECUTE_HANDLER) {
  521. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpGetCellMapped: exception thrown while faulting in data, code:%08lx\n", GetExceptionCode()));
  522. //
  523. // restore the usecounts
  524. //
  525. CmLockHiveViews ((PCMHIVE)Hive);
  526. if( (Map->BinAddress & HMAP_INPAGEDPOOL) == 0 ) {
  527. ASSERT( Map->CmView != NULL );
  528. if(Hive->ReleaseCellRoutine) Map->CmView->UseCount--;
  529. }
  530. if(Hive->ReleaseCellRoutine) ((PCMHIVE)Hive)->UseCount--;
  531. CmUnlockHiveViews ((PCMHIVE)Hive);
  532. return NULL;
  533. }
  534. #endif //CM_MAP_NO_READ
  535. if (USE_OLD_CELL(Hive)) {
  536. return (struct _CELL_DATA *)&(pcell->u.OldCell.u.UserData);
  537. } else {
  538. return (struct _CELL_DATA *)&(pcell->u.NewCell.u.UserData);
  539. }
  540. }
  541. #else
  542. //
  543. // these functions are just stubs for the loader
  544. //
  545. VOID
  546. HvpReleaseCellMapped(
  547. PHHIVE Hive,
  548. HCELL_INDEX Cell
  549. )
  550. {
  551. }
  552. struct _CELL_DATA *
  553. HvpGetCellMapped(
  554. PHHIVE Hive,
  555. HCELL_INDEX Cell
  556. )
  557. {
  558. return NULL;
  559. }
  560. #endif //_CM_LDR_
  561. struct _CELL_DATA *
  562. HvpGetCellPaged(
  563. PHHIVE Hive,
  564. HCELL_INDEX Cell
  565. )
  566. /*++
  567. Routine Description:
  568. Returns the memory address for the specified Cell. Will never
  569. return failure, but may assert. Use HvIsCellAllocated to check
  570. validity of Cell.
  571. This routine should never be called directly, always call it
  572. via the HvGetCell() macro.
  573. This routine provides GetCell support for hives with full maps.
  574. It is the normal version of the routine.
  575. Arguments:
  576. Hive - supplies a pointer to the hive control structure for the
  577. hive of interest
  578. Cell - supplies HCELL_INDEX of cell to return address for
  579. Return Value:
  580. Address of Cell in memory. Assert or BugCheck if error.
  581. --*/
  582. {
  583. ULONG Type;
  584. ULONG Table;
  585. ULONG Block;
  586. ULONG Offset;
  587. PHCELL pcell;
  588. PHMAP_ENTRY Map;
  589. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"HvGetCellPaged:\n"));
  590. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"\tHive=%p Cell=%08lx\n",Hive,Cell));
  591. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  592. ASSERT(Cell != HCELL_NIL);
  593. ASSERT(Hive->Flat == FALSE);
  594. ASSERT((Cell & (HCELL_PAD(Hive)-1))==0);
  595. ASSERT_CM_LOCK_OWNED();
  596. #if DBG
  597. if (HvGetCellType(Cell) == Stable) {
  598. ASSERT(Cell >= sizeof(HBIN));
  599. } else {
  600. ASSERT(Cell >= (HCELL_TYPE_MASK + sizeof(HBIN)));
  601. }
  602. #endif
  603. if( HvShutdownComplete == TRUE ) {
  604. //
  605. // at shutdown we need to unmap all views
  606. //
  607. #if DBG
  608. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpGetCellPaged called after shutdown for Hive = %p Cell = %lx\n",Hive,(ULONG)Cell));
  609. #endif
  610. return NULL;
  611. }
  612. Type = HvGetCellType(Cell);
  613. Table = (Cell & HCELL_TABLE_MASK) >> HCELL_TABLE_SHIFT;
  614. Block = (Cell & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
  615. Offset = (Cell & HCELL_OFFSET_MASK);
  616. ASSERT((Cell - (Type * HCELL_TYPE_MASK)) < Hive->Storage[Type].Length);
  617. Map = &((Hive->Storage[Type].Map)->Directory[Table]->Table[Block]);
  618. //
  619. // it is ilegal to call this routine for mapped hives
  620. //
  621. ASSERT( Map->BinAddress & HMAP_INPAGEDPOOL );
  622. ASSERT( HBIN_BASE(Map->BinAddress) != 0);
  623. ASSERT((Map->BinAddress & HMAP_DISCARDABLE) == 0);
  624. pcell = (PHCELL)((ULONG_PTR)(Map->BlockAddress) + Offset);
  625. PERFINFO_HIVECELL_REFERENCE_PAGED(Hive, pcell, Cell, Type, Map);
  626. if (USE_OLD_CELL(Hive)) {
  627. return (struct _CELL_DATA *)&(pcell->u.OldCell.u.UserData);
  628. } else {
  629. return (struct _CELL_DATA *)&(pcell->u.NewCell.u.UserData);
  630. }
  631. }
  632. VOID
  633. HvpEnlistFreeCell(
  634. PHHIVE Hive,
  635. HCELL_INDEX Cell,
  636. ULONG Size,
  637. HSTORAGE_TYPE Type,
  638. BOOLEAN CoalesceForward
  639. )
  640. /*++
  641. Routine Description:
  642. Puts the newly freed cell on the appropriate list.
  643. Arguments:
  644. Hive - supplies a pointer to the hive control structure for the
  645. hive of interest
  646. Cell - supplies index of cell to enlist
  647. Size - size of cell
  648. Type - indicates whether Stable or Volatile storage is desired.
  649. CoalesceForward - indicates whether we can coalesce forward or not.
  650. For the case where we have not finished scanning the hive and
  651. enlisting free cells, we do not want to coalesce forward.
  652. Return Value:
  653. NONE.
  654. --*/
  655. {
  656. PHMAP_ENTRY Map;
  657. PHCELL pcell;
  658. PHCELL pcellLast;
  659. PHCELL FirstCell;
  660. ULONG Index;
  661. PHBIN Bin;
  662. HCELL_INDEX FreeCell;
  663. PFREE_HBIN FreeBin;
  664. PHBIN FirstBin;
  665. PHBIN LastBin;
  666. ULONG FreeOffset;
  667. HvpComputeIndex(Index, Size);
  668. #ifdef HV_TRACK_FREE_SPACE
  669. Hive->Storage[Type].FreeStorage += Size;
  670. ASSERT( Hive->Storage[Type].FreeStorage <= Hive->Storage[Type].Length );
  671. #endif
  672. //
  673. // the HvpGetHCell call bellow touches the view containing the cell,
  674. // and makes sure the CM_VIEW_SIZE window is mapped in the system cache
  675. //
  676. pcell = HvpGetHCell(Hive, Cell);
  677. if( pcell == NULL ) {
  678. //
  679. // we couldn't map view for this cell
  680. // this shouldn't happen as the cell here is already marked dirty
  681. // or it's entire bin is mapped
  682. //
  683. ASSERT( FALSE);
  684. return;
  685. }
  686. //
  687. // if we are here; we were called from HvInitializeHive, or with reglock
  688. // held exclusive; therefore it is safe to release the cell here
  689. //
  690. HvReleaseCell(Hive,Cell);
  691. ASSERT(pcell->Size > 0);
  692. ASSERT(Size == (ULONG)pcell->Size);
  693. //
  694. // Check to see if this is the first cell in the bin and if the entire
  695. // bin consists just of this cell.
  696. //
  697. Map = HvpGetCellMap(Hive, Cell);
  698. VALIDATE_CELL_MAP(__LINE__,Map,Hive,Cell);
  699. ASSERT_BIN_VALID(Map);
  700. Bin = (PHBIN)HBIN_BASE(Map->BinAddress);
  701. if ((pcell == (PHCELL)(Bin + 1)) &&
  702. (Size == Bin->Size-sizeof(HBIN))) {
  703. //
  704. // We have a bin that is entirely free. But we cannot do anything with it
  705. // unless the memalloc that contains the bin is entirely free. Walk the
  706. // bins backwards until we find the first one in the alloc, then walk forwards
  707. // until we find the last one. If any of the other bins in the memalloc
  708. // are not free, bail out.
  709. //
  710. FirstBin = Bin;
  711. while ( HvpGetBinMemAlloc(Hive,FirstBin,Type) == 0) {
  712. Map=HvpGetCellMap(Hive,(FirstBin->FileOffset - HBLOCK_SIZE) +
  713. (Type * HCELL_TYPE_MASK));
  714. VALIDATE_CELL_MAP(__LINE__,Map,Hive,(FirstBin->FileOffset - HBLOCK_SIZE) +(Type * HCELL_TYPE_MASK));
  715. ASSERT_BIN_VALID(Map);
  716. FirstBin = (PHBIN)HBIN_BASE(Map->BinAddress);
  717. FirstCell = (PHCELL)(FirstBin+1);
  718. if ((ULONG)(FirstCell->Size) != FirstBin->Size-sizeof(HBIN)) {
  719. //
  720. // The first cell in the bin is either allocated, or not the only
  721. // cell in the HBIN. We cannot free any HBINs.
  722. //
  723. goto Done;
  724. }
  725. }
  726. //
  727. // We can never discard the first bin of a hive as that always gets marked dirty
  728. // and written out.
  729. //
  730. if (FirstBin->FileOffset == 0) {
  731. goto Done;
  732. }
  733. LastBin = Bin;
  734. while (LastBin->FileOffset+LastBin->Size < FirstBin->FileOffset + HvpGetBinMemAlloc(Hive,FirstBin,Type)) {
  735. if (!CoalesceForward) {
  736. //
  737. // We are at the end of what's been built up. Just return and this
  738. // will get freed up when the next HBIN is added.
  739. //
  740. goto Done;
  741. }
  742. Map = HvpGetCellMap(Hive, (LastBin->FileOffset+LastBin->Size) +
  743. (Type * HCELL_TYPE_MASK));
  744. VALIDATE_CELL_MAP(__LINE__,Map,Hive,(LastBin->FileOffset+LastBin->Size) + (Type * HCELL_TYPE_MASK));
  745. ASSERT(Map->BinAddress != 0);
  746. LastBin = (PHBIN)HBIN_BASE(Map->BinAddress);
  747. FirstCell = (PHCELL)(LastBin + 1);
  748. if ((ULONG)(FirstCell->Size) != LastBin->Size-sizeof(HBIN)) {
  749. //
  750. // The first cell in the bin is either allocated, or not the only
  751. // cell in the HBIN. We cannot free any HBINs.
  752. //
  753. goto Done;
  754. }
  755. }
  756. //
  757. // All the bins in this alloc are freed. Coalesce all the bins into
  758. // one alloc-sized bin, then either discard the bin or mark it as
  759. // discardable.
  760. //
  761. if (FirstBin->Size != HvpGetBinMemAlloc(Hive,FirstBin,Type)) {
  762. //
  763. // Mark the first HBLOCK of the first HBIN dirty, since
  764. // we will need to update the on disk field for the bin size
  765. //
  766. if (!HvMarkDirty(Hive,
  767. FirstBin->FileOffset + (Type * HCELL_TYPE_MASK),
  768. sizeof(HBIN) + sizeof(HCELL),FALSE)) {
  769. goto Done;
  770. }
  771. }
  772. FreeBin = (Hive->Allocate)(sizeof(FREE_HBIN), FALSE,CM_FIND_LEAK_TAG7);
  773. if (FreeBin == NULL) {
  774. goto Done;
  775. }
  776. //
  777. // Walk through the bins and delist each free cell
  778. //
  779. Bin = FirstBin;
  780. do {
  781. FirstCell = (PHCELL)(Bin+1);
  782. HvpDelistFreeCell(Hive, Bin->FileOffset + (ULONG)((PUCHAR)FirstCell - (PUCHAR)Bin) + (Type*HCELL_TYPE_MASK), Type);
  783. if (Bin==LastBin) {
  784. break;
  785. }
  786. Map = HvpGetCellMap(Hive, (Bin->FileOffset+Bin->Size)+
  787. (Type * HCELL_TYPE_MASK));
  788. VALIDATE_CELL_MAP(__LINE__,Map,Hive,(Bin->FileOffset+Bin->Size)+(Type * HCELL_TYPE_MASK));
  789. Bin = (PHBIN)HBIN_BASE(Map->BinAddress);
  790. } while ( TRUE );
  791. //
  792. // Coalesce them all into one bin.
  793. //
  794. FirstBin->Size = HvpGetBinMemAlloc(Hive,FirstBin,Type);
  795. FreeBin->Size = FirstBin->Size;
  796. FreeBin->FileOffset = FirstBin->FileOffset;
  797. FirstCell = (PHCELL)(FirstBin+1);
  798. FirstCell->Size = FirstBin->Size - sizeof(HBIN);
  799. if (USE_OLD_CELL(Hive)) {
  800. FirstCell->u.OldCell.Last = (ULONG)HBIN_NIL;
  801. }
  802. InsertHeadList(&Hive->Storage[Type].FreeBins, &FreeBin->ListEntry);
  803. ASSERT_LISTENTRY(&FreeBin->ListEntry);
  804. ASSERT_LISTENTRY(FreeBin->ListEntry.Flink);
  805. #ifdef HV_TRACK_FREE_SPACE
  806. Hive->Storage[Type].FreeStorage += (FirstBin->Size - sizeof(HBIN));
  807. ASSERT( Hive->Storage[Type].FreeStorage <= Hive->Storage[Type].Length );
  808. #endif
  809. FreeCell = FirstBin->FileOffset+(Type*HCELL_TYPE_MASK);
  810. Map = HvpGetCellMap(Hive, FreeCell);
  811. VALIDATE_CELL_MAP(__LINE__,Map,Hive,FreeCell);
  812. if( Map->BinAddress & HMAP_INPAGEDPOOL ) {
  813. //
  814. // the bin is allocated from paged pool;
  815. // mark the free bin as not discarded; paged pool will be freed when the bin is
  816. // discarded
  817. //
  818. FreeBin->Flags = FREE_HBIN_DISCARDABLE;
  819. } else {
  820. //
  821. // bin is not allocated from paged pool; mark it as already discarded
  822. //
  823. FreeBin->Flags = 0;
  824. }
  825. FreeOffset = 0;
  826. while (FreeOffset < FirstBin->Size) {
  827. Map = HvpGetCellMap(Hive, FreeCell);
  828. VALIDATE_CELL_MAP(__LINE__,Map,Hive,FreeCell);
  829. //
  830. // adjust the bin address, but make sure to preserve the mapping flags
  831. // i.e. : if the view containing this bin is mapped into memory, add the flag
  832. //
  833. if (Map->BinAddress & HMAP_NEWALLOC) {
  834. Map->BinAddress = (ULONG_PTR)FirstBin | HMAP_DISCARDABLE | HMAP_NEWALLOC | BIN_MAP_ALLOCATION_TYPE(Map);
  835. } else {
  836. Map->BinAddress = (ULONG_PTR)FirstBin | HMAP_DISCARDABLE | BIN_MAP_ALLOCATION_TYPE(Map);
  837. }
  838. Map->BlockAddress = (ULONG_PTR)FreeBin;
  839. FreeCell += HBLOCK_SIZE;
  840. FreeOffset += HBLOCK_SIZE;
  841. }
  842. //
  843. // don't change the hints, we haven't added any free cell !!!
  844. //
  845. return;
  846. }
  847. Done:
  848. HvpAddFreeCellHint(Hive,Cell,Index,Type);
  849. return;
  850. }
  851. VOID
  852. HvpDelistFreeCell(
  853. PHHIVE Hive,
  854. HCELL_INDEX Cell,
  855. HSTORAGE_TYPE Type
  856. )
  857. /*++
  858. Routine Description:
  859. Updates the FreeSummary and FreeDisplay at the index corresponding to this cell
  860. Arguments:
  861. Hive - supplies a pointer to the hive control structure for the
  862. hive of interest
  863. Cell - supplies the cell index for the free cell to delist
  864. Type - Stable vs. Volatile
  865. Return Value:
  866. NONE.
  867. --*/
  868. {
  869. PHCELL pcell;
  870. ULONG Index;
  871. pcell = HvpGetHCell(Hive, Cell);
  872. if( pcell == NULL ) {
  873. //
  874. // we couldn't map view for this cell
  875. // this shouldn't happen as the cell here is already marked dirty
  876. // or it's entire bin is mapped
  877. //
  878. ASSERT( FALSE);
  879. return;
  880. }
  881. //
  882. // if we are here; we were called from HvInitializeHive, or with reglock
  883. // held exclusive; therefore it is safe to release the cell here
  884. //
  885. HvReleaseCell(Hive,Cell);
  886. ASSERT(pcell->Size > 0);
  887. HvpComputeIndex(Index, pcell->Size);
  888. #ifdef HV_TRACK_FREE_SPACE
  889. Hive->Storage[Type].FreeStorage -= pcell->Size;
  890. ASSERT( (LONG)(Hive->Storage[Type].FreeStorage) >= 0 );
  891. #endif
  892. HvpRemoveFreeCellHint(Hive,Cell,Index,Type);
  893. return;
  894. }
  895. HCELL_INDEX
  896. HvAllocateCell(
  897. PHHIVE Hive,
  898. ULONG NewSize,
  899. HSTORAGE_TYPE Type,
  900. HCELL_INDEX Vicinity
  901. )
  902. /*++
  903. Routine Description:
  904. Allocates the space and the cell index for a new cell.
  905. Arguments:
  906. Hive - supplies a pointer to the hive control structure for the
  907. hive of interest
  908. NewSize - size in bytes of the cell to allocate
  909. Type - indicates whether Stable or Volatile storage is desired.
  910. Return Value:
  911. New HCELL_INDEX if success, HCELL_NIL if failure.
  912. --*/
  913. {
  914. HCELL_INDEX NewCell;
  915. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvAllocateCell:\n"));
  916. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tHive=%p NewSize=%08lx\n",Hive,NewSize));
  917. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  918. ASSERT(Hive->ReadOnly == FALSE);
  919. //
  920. // we have the lock exclusive or nobody is operating inside this hive
  921. //
  922. //ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  923. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  924. //
  925. // Make room for overhead fields and round up to HCELL_PAD boundary
  926. //
  927. if (USE_OLD_CELL(Hive)) {
  928. NewSize += FIELD_OFFSET(HCELL, u.OldCell.u.UserData);
  929. } else {
  930. NewSize += FIELD_OFFSET(HCELL, u.NewCell.u.UserData);
  931. }
  932. NewSize = ROUND_UP(NewSize, HCELL_PAD(Hive));
  933. //
  934. // Adjust the size (an easy fix for granularity)
  935. //
  936. HvpAdjustCellSize(NewSize);
  937. //
  938. // reject impossible/unreasonable values
  939. //
  940. if (NewSize > HSANE_CELL_MAX) {
  941. return HCELL_NIL;
  942. }
  943. //
  944. // Do the actual storage allocation
  945. //
  946. NewCell = HvpDoAllocateCell(Hive, NewSize, Type, Vicinity);
  947. #if DBG
  948. if (NewCell != HCELL_NIL) {
  949. ASSERT(HvIsCellAllocated(Hive, NewCell));
  950. }
  951. #endif
  952. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tNewCell=%08lx\n", NewCell));
  953. return NewCell;
  954. }
  955. HCELL_INDEX
  956. HvpDoAllocateCell(
  957. PHHIVE Hive,
  958. ULONG NewSize,
  959. HSTORAGE_TYPE Type,
  960. HCELL_INDEX Vicinity
  961. )
  962. /*++
  963. Routine Description:
  964. Allocates space in the hive. Does not affect cell map in any way.
  965. If Vicinity is not NIL, it defines the "window" where the new cell
  966. to be allocated (if one free is found). The window is ensured by
  967. looking for a free cell of the desired size:
  968. 1st - in the same CM_VIEW_SIZE window with the Vicinity cell.
  969. Abstract:
  970. This first version allocates a new bin if a cell free cell big enough
  971. cannot be found in the specified window.
  972. Arguments:
  973. Hive - supplies a pointer to the hive control structure for the
  974. hive of interest
  975. NewSize - size in bytes of the cell to allocate
  976. Type - indicates whether Stable or Volatile storage is desired.
  977. Vicinity - the starting cell which defines the vicinity of the new
  978. allocated cell.
  979. Return Value:
  980. HCELL_INDEX of new cell, HCELL_NIL if failure
  981. --*/
  982. {
  983. ULONG Index;
  984. HCELL_INDEX cell;
  985. PHCELL pcell;
  986. HCELL_INDEX tcell;
  987. PHCELL ptcell;
  988. PHBIN Bin;
  989. PHMAP_ENTRY Me;
  990. ULONG offset;
  991. PHCELL next;
  992. ULONG MinFreeSize;
  993. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvDoAllocateCell:\n"));
  994. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tHive=%p NewSize=%08lx Type=%08lx\n",Hive,NewSize,Type));
  995. ASSERT(Hive->ReadOnly == FALSE);
  996. //
  997. // we have the lock exclusive or nobody is operating inside this hive
  998. //
  999. //ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1000. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  1001. //
  1002. // Compute Index into Display
  1003. //
  1004. HvpComputeIndex(Index, NewSize);
  1005. #if DBG
  1006. {
  1007. UNICODE_STRING HiveName;
  1008. RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName);
  1009. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"[HvpDoAllocateCell] CellSize = %lu Vicinity = %lx :: Hive (%p) (%.*S) ...\n",
  1010. NewSize,Vicinity,Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer));
  1011. }
  1012. #endif
  1013. cell = HvpFindFreeCell(Hive,Index,NewSize,Type,Vicinity);
  1014. if( cell != HCELL_NIL ) {
  1015. //
  1016. // found it !
  1017. //
  1018. pcell = HvpGetHCell(Hive, cell);
  1019. if( pcell == NULL ) {
  1020. //
  1021. // we couldn't map view for this cell
  1022. // this shouldn't happen as the cell here is already marked dirty
  1023. // or it's entire bin is mapped
  1024. //
  1025. ASSERT( FALSE);
  1026. return HCELL_NIL;
  1027. }
  1028. // we are safe to release the cell here as the reglock is held exclusive
  1029. HvReleaseCell(Hive,cell);
  1030. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL," found cell at index = %lx size = %lu \n",cell,pcell->Size));
  1031. goto UseIt;
  1032. } else {
  1033. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL," not found\n"));
  1034. //
  1035. // No suitable cells were found on any free list.
  1036. //
  1037. // Either there is no large enough cell, or we
  1038. // have no free cells left at all. In either case, allocate a
  1039. // new bin, with a new free cell certain to be large enough in
  1040. // it, and use that cell.
  1041. //
  1042. #ifdef CM_CHECK_FREECELL_LEAKS
  1043. HvpCheckFreeCells(Hive,NewSize,Type);
  1044. #endif //CM_CHECK_FREECELL_LEAKS
  1045. //
  1046. // Attempt to create a new bin
  1047. //
  1048. if ((Bin = HvpAddBin(Hive, NewSize, Type)) != NULL) {
  1049. //
  1050. // It worked. Use single large cell in Bin.
  1051. //
  1052. DHvCheckBin(Hive,Bin);
  1053. cell = (Bin->FileOffset) + sizeof(HBIN) + (Type*HCELL_TYPE_MASK);
  1054. pcell = HvpGetHCell(Hive, cell);
  1055. if( pcell == NULL ) {
  1056. //
  1057. // we couldn't map view for this cell
  1058. // this shouldn't happen as the entire bin is mapped
  1059. //
  1060. ASSERT( FALSE);
  1061. return HCELL_NIL;
  1062. }
  1063. // we are safe to release the cell here as the reglock is held exclusive
  1064. HvReleaseCell(Hive,cell);
  1065. } else {
  1066. return HCELL_NIL;
  1067. }
  1068. }
  1069. UseIt:
  1070. //
  1071. // cell refers to a free cell we have pulled from its list
  1072. // if it is too big, give the residue back
  1073. // ("too big" means there is at least one HCELL of extra space)
  1074. // always mark it allocated
  1075. // return it as our function value
  1076. //
  1077. ASSERT(pcell->Size > 0);
  1078. if (USE_OLD_CELL(Hive)) {
  1079. MinFreeSize = FIELD_OFFSET(HCELL, u.OldCell.u.Next) + sizeof(HCELL_INDEX);
  1080. } else {
  1081. MinFreeSize = FIELD_OFFSET(HCELL, u.NewCell.u.Next) + sizeof(HCELL_INDEX);
  1082. }
  1083. if ((NewSize + MinFreeSize) <= (ULONG)pcell->Size) {
  1084. //
  1085. // Crack the cell, use part we need, put rest on
  1086. // free list.
  1087. //
  1088. Me = HvpGetCellMap(Hive, cell);
  1089. VALIDATE_CELL_MAP(__LINE__,Me,Hive,cell);
  1090. //
  1091. // at this point we are sure that the bin is in memory ??????
  1092. //
  1093. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  1094. offset = (ULONG)((ULONG_PTR)pcell - (ULONG_PTR)Bin);
  1095. ptcell = (PHCELL)((PUCHAR)pcell + NewSize);
  1096. if (USE_OLD_CELL(Hive)) {
  1097. ptcell->u.OldCell.Last = offset;
  1098. }
  1099. ptcell->Size = pcell->Size - NewSize;
  1100. if ((offset + pcell->Size) < Bin->Size) {
  1101. next = (PHCELL)((PUCHAR)pcell + pcell->Size);
  1102. if (USE_OLD_CELL(Hive)) {
  1103. next->u.OldCell.Last = offset + NewSize;
  1104. }
  1105. }
  1106. pcell->Size = NewSize;
  1107. tcell = (HCELL_INDEX)((ULONG)cell + NewSize);
  1108. HvpEnlistFreeCell(Hive, tcell, ptcell->Size, Type, TRUE);
  1109. }
  1110. //
  1111. // return the cell we found.
  1112. //
  1113. #if DBG
  1114. if (USE_OLD_CELL(Hive)) {
  1115. RtlFillMemory(
  1116. &(pcell->u.OldCell.u.UserData),
  1117. (pcell->Size - FIELD_OFFSET(HCELL, u.OldCell.u.UserData)),
  1118. HCELL_ALLOCATE_FILL
  1119. );
  1120. } else {
  1121. RtlFillMemory(
  1122. &(pcell->u.NewCell.u.UserData),
  1123. (pcell->Size - FIELD_OFFSET(HCELL, u.NewCell.u.UserData)),
  1124. HCELL_ALLOCATE_FILL
  1125. );
  1126. }
  1127. #endif
  1128. pcell->Size *= -1;
  1129. return cell;
  1130. }
  1131. //
  1132. // Procedure used for checking only (used in production systems, so
  1133. // must always be here.)
  1134. //
  1135. BOOLEAN
  1136. HvIsCellAllocated(
  1137. PHHIVE Hive,
  1138. HCELL_INDEX Cell
  1139. )
  1140. /*++
  1141. Routine Description:
  1142. Report whether the requested cell is allocated or not.
  1143. Arguments:
  1144. Hive - containing Hive.
  1145. Cell - cel of interest
  1146. Return Value:
  1147. TRUE if allocated, FALSE if not.
  1148. --*/
  1149. {
  1150. ULONG Type;
  1151. PHCELL Address;
  1152. PHCELL Below;
  1153. PHMAP_ENTRY Me;
  1154. PHBIN Bin;
  1155. ULONG Offset;
  1156. LONG Size;
  1157. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1158. if (Hive->Flat == TRUE) {
  1159. return TRUE;
  1160. }
  1161. Type = HvGetCellType(Cell);
  1162. if ( ((Cell & ~HCELL_TYPE_MASK) > Hive->Storage[Type].Length) || // off end
  1163. (Cell % HCELL_PAD(Hive) != 0) // wrong alignment
  1164. )
  1165. {
  1166. return FALSE;
  1167. }
  1168. Me = HvpGetCellMap(Hive, Cell);
  1169. if (Me == NULL) {
  1170. return FALSE;
  1171. }
  1172. if( Me->BinAddress & HMAP_DISCARDABLE ) {
  1173. return FALSE;
  1174. }
  1175. //
  1176. // this will bring the CM_VIEW_SIZE window mapping the bin in memory
  1177. //
  1178. Address = HvpGetHCell(Hive, Cell);
  1179. if( Address == NULL ) {
  1180. //
  1181. // we couldn't map view for this cell
  1182. //
  1183. return FALSE;
  1184. }
  1185. #ifndef _CM_LDR_
  1186. try {
  1187. #endif //_CM_LDR_
  1188. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  1189. Offset = (ULONG)((ULONG_PTR)Address - (ULONG_PTR)Bin);
  1190. Size = Address->Size * -1;
  1191. if ( (Address->Size >= 0) || // not allocated
  1192. ((Offset + (ULONG)Size) > Bin->Size) || // runs off bin, or too big
  1193. (Offset < sizeof(HBIN)) // pts into bin header
  1194. )
  1195. {
  1196. return FALSE;
  1197. }
  1198. if (USE_OLD_CELL(Hive)) {
  1199. if (Address->u.OldCell.Last != HBIN_NIL) {
  1200. if (Address->u.OldCell.Last > Bin->Size) { // bogus back pointer
  1201. return FALSE;
  1202. }
  1203. Below = (PHCELL)((PUCHAR)Bin + Address->u.OldCell.Last);
  1204. Size = (Below->Size < 0) ?
  1205. Below->Size * -1 :
  1206. Below->Size;
  1207. if ( ((ULONG_PTR)Below + Size) != (ULONG_PTR)Address ) { // no pt back
  1208. return FALSE;
  1209. }
  1210. }
  1211. }
  1212. #ifndef _CM_LDR_
  1213. } finally {
  1214. HvReleaseCell(Hive,Cell);
  1215. }
  1216. #endif //_CM_LDR_
  1217. return TRUE;
  1218. }
  1219. VOID
  1220. HvpDelistBinFreeCells(
  1221. PHHIVE Hive,
  1222. PHBIN Bin,
  1223. HSTORAGE_TYPE Type
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. If we are here, the hive needs recovery.
  1228. Walks through the entire bin and removes its free cells from the list.
  1229. If the bin is marked as free, it just delist it from the freebins list.
  1230. Arguments:
  1231. Hive - supplies a pointer to the hive control structure for the
  1232. hive of interest
  1233. Bin - supplies a pointer to the HBIN of interest
  1234. Type - Stable vs. Volatile
  1235. Return Value:
  1236. NONE.
  1237. --*/
  1238. {
  1239. PHCELL p;
  1240. ULONG size;
  1241. HCELL_INDEX Cell;
  1242. PHMAP_ENTRY Map;
  1243. PFREE_HBIN FreeBin;
  1244. PLIST_ENTRY Entry;
  1245. ULONG CellOffset;
  1246. HCELL_INDEX cellindex;
  1247. ULONG i;
  1248. ULONG BinIndex;
  1249. Cell = Bin->FileOffset+(Type*HCELL_TYPE_MASK);
  1250. Map = HvpGetCellMap(Hive, Cell);
  1251. VALIDATE_CELL_MAP(__LINE__,Map,Hive,Cell);
  1252. //
  1253. // When loading, bins are always in separate chunks (each bin in it's owns chunk)
  1254. //
  1255. ASSERT( HBIN_BASE(Map->BinAddress) == (ULONG_PTR)Bin );
  1256. ASSERT( Map->BinAddress & HMAP_NEWALLOC );
  1257. if( Map->BinAddress & HMAP_DISCARDABLE ) {
  1258. //
  1259. // The bin has been added to the freebins list
  1260. // we have to take it out. No free cell from this bin is on the
  1261. // freecells list, so we don't have to delist them.
  1262. //
  1263. Entry = Hive->Storage[Type].FreeBins.Flink;
  1264. while (Entry != &Hive->Storage[Type].FreeBins) {
  1265. FreeBin = CONTAINING_RECORD(Entry,
  1266. FREE_HBIN,
  1267. ListEntry);
  1268. if( FreeBin->FileOffset == Bin->FileOffset ){
  1269. //
  1270. // that's the bin we're looking for
  1271. //
  1272. // sanity checks
  1273. ASSERT( FreeBin->Size == Bin->Size );
  1274. ASSERT_LISTENTRY(&FreeBin->ListEntry);
  1275. RemoveEntryList(&FreeBin->ListEntry);
  1276. (Hive->Free)(FreeBin, sizeof(FREE_HBIN));
  1277. //
  1278. // the bin is not discardable anymore
  1279. //
  1280. Map->BinAddress &= (~HMAP_DISCARDABLE);
  1281. return;
  1282. }
  1283. // advance to the new bin
  1284. Entry = Entry->Flink;
  1285. }
  1286. // we shouldn't get here
  1287. CM_BUGCHECK(REGISTRY_ERROR,BAD_FREE_BINS_LIST,1,(ULONG)Cell,(ULONG_PTR)Map);
  1288. return;
  1289. }
  1290. //
  1291. // as for the new way of dealing with free cells, all we have to do
  1292. // is to clear the bits in the FreeDisplay
  1293. //
  1294. BinIndex = Bin->FileOffset / HBLOCK_SIZE;
  1295. for (i = 0; i < HHIVE_FREE_DISPLAY_SIZE; i++) {
  1296. RtlClearBits (&(Hive->Storage[Type].FreeDisplay[i]), BinIndex, Bin->Size / HBLOCK_SIZE);
  1297. if( RtlNumberOfSetBits(&(Hive->Storage[Type].FreeDisplay[i]) ) == 0 ) {
  1298. //
  1299. // entire bitmap is 0 (i.e. no other free cells of this size)
  1300. //
  1301. Hive->Storage[Type].FreeSummary &= (~(1 << i));
  1302. }
  1303. }
  1304. return;
  1305. }
  1306. struct _CELL_DATA *
  1307. HvpGetCellFlat(
  1308. PHHIVE Hive,
  1309. HCELL_INDEX Cell
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. Returns the memory address for the specified Cell. Will never
  1314. return failure, but may assert. Use HvIsCellAllocated to check
  1315. validity of Cell.
  1316. This routine should never be called directly, always call it
  1317. via the HvGetCell() macro.
  1318. This routine provides GetCell support for read only hives with
  1319. single allocation flat images. Such hives do not have cell
  1320. maps ("page tables"), instead, we compute addresses by
  1321. arithmetic against the base image address.
  1322. Such hives cannot have volatile cells.
  1323. Arguments:
  1324. Hive - supplies a pointer to the hive control structure for the
  1325. hive of interest
  1326. Cell - supplies HCELL_INDEX of cell to return address for
  1327. Return Value:
  1328. Address of Cell in memory. Assert or BugCheck if error.
  1329. --*/
  1330. {
  1331. PUCHAR base;
  1332. PHCELL pcell;
  1333. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"HvGetCellFlat:\n"));
  1334. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"\tHive=%p Cell=%08lx\n",Hive,Cell));
  1335. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1336. ASSERT(Cell != HCELL_NIL);
  1337. ASSERT(Hive->Flat == TRUE);
  1338. ASSERT(HvGetCellType(Cell) == Stable);
  1339. ASSERT(Cell >= sizeof(HBIN));
  1340. ASSERT(Cell < Hive->BaseBlock->Length);
  1341. ASSERT((Cell & 0x7)==0);
  1342. //
  1343. // Address is base of Hive image + Cell
  1344. //
  1345. base = (PUCHAR)(Hive->BaseBlock) + HBLOCK_SIZE;
  1346. pcell = (PHCELL)(base + Cell);
  1347. PERFINFO_HIVECELL_REFERENCE_FLAT(Hive, pcell, Cell);
  1348. if (USE_OLD_CELL(Hive)) {
  1349. return (struct _CELL_DATA *)&(pcell->u.OldCell.u.UserData);
  1350. } else {
  1351. return (struct _CELL_DATA *)&(pcell->u.NewCell.u.UserData);
  1352. }
  1353. }
  1354. PHMAP_ENTRY
  1355. HvpGetCellMap(
  1356. PHHIVE Hive,
  1357. HCELL_INDEX Cell
  1358. )
  1359. /*++
  1360. Routine Description:
  1361. Returns the address of the HMAP_ENTRY for the cell.
  1362. Arguments:
  1363. Hive - supplies a pointer to the hive control structure for the
  1364. hive of interest
  1365. Cell - supplies HCELL_INDEX of cell to return map entry address for
  1366. Return Value:
  1367. Address of MAP_ENTRY in memory. NULL if no such cell or other error.
  1368. --*/
  1369. {
  1370. ULONG Type;
  1371. ULONG Table;
  1372. ULONG Block;
  1373. PHMAP_TABLE ptab;
  1374. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"HvpGetCellMapPaged:\n"));
  1375. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"\tHive=%p Cell=%08lx\n",Hive,Cell));
  1376. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1377. ASSERT(Hive->Flat == FALSE);
  1378. ASSERT((Cell & (HCELL_PAD(Hive)-1))==0);
  1379. Type = HvGetCellType(Cell);
  1380. Table = (Cell & HCELL_TABLE_MASK) >> HCELL_TABLE_SHIFT;
  1381. Block = (Cell & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
  1382. if ((Cell - (Type * HCELL_TYPE_MASK)) >= Hive->Storage[Type].Length) {
  1383. return NULL;
  1384. }
  1385. ptab = (Hive->Storage[Type].Map)->Directory[Table];
  1386. return &(ptab->Table[Block]);
  1387. }
  1388. LONG
  1389. HvGetCellSize(
  1390. IN PHHIVE Hive,
  1391. IN PVOID Address
  1392. )
  1393. /*++
  1394. Routine Description:
  1395. Returns the size of the specified Cell, based on its MEMORY
  1396. ADDRESS. Must always call HvGetCell first to get that
  1397. address.
  1398. NOTE: This should be a macro if speed is issue.
  1399. NOTE: If you pass in some random pointer, you will get some
  1400. random answer. Only pass in valid Cell addresses.
  1401. Arguments:
  1402. Hive - supplies hive control structure for the given cell
  1403. Address - address in memory of the cell, returned by HvGetCell()
  1404. Return Value:
  1405. Allocated size in bytes of the cell.
  1406. If Negative, Cell is free, or Address is bogus.
  1407. --*/
  1408. {
  1409. LONG size;
  1410. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"HvGetCellSize:\n"));
  1411. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"\tAddress=%p\n", Address));
  1412. if (USE_OLD_CELL(Hive)) {
  1413. size = ( (CONTAINING_RECORD(Address, HCELL, u.OldCell.u.UserData))->Size ) * -1;
  1414. size -= FIELD_OFFSET(HCELL, u.OldCell.u.UserData);
  1415. } else {
  1416. size = ( (CONTAINING_RECORD(Address, HCELL, u.NewCell.u.UserData))->Size ) * -1;
  1417. size -= FIELD_OFFSET(HCELL, u.NewCell.u.UserData);
  1418. }
  1419. return size;
  1420. }
  1421. VOID
  1422. HvFreeCell(
  1423. PHHIVE Hive,
  1424. HCELL_INDEX Cell
  1425. )
  1426. /*++
  1427. Routine Description:
  1428. Frees the storage for a cell.
  1429. NOTE: CALLER is expected to mark relevent data dirty, so as to
  1430. allow this call to always succeed.
  1431. Arguments:
  1432. Hive - supplies a pointer to the hive control structure for the
  1433. hive of interest
  1434. Cell - HCELL_INDEX of Cell to free.
  1435. Return Value:
  1436. FALSE - failed, presumably for want of log space.
  1437. TRUE - it worked
  1438. --*/
  1439. {
  1440. PHBIN Bin;
  1441. PHCELL tmp;
  1442. HCELL_INDEX newfreecell;
  1443. PHCELL freebase;
  1444. ULONG savesize;
  1445. PHCELL neighbor;
  1446. ULONG Type;
  1447. PHMAP_ENTRY Me;
  1448. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvFreeCell:\n"));
  1449. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tHive=%p Cell=%08lx\n",Hive,Cell));
  1450. ASSERT(Hive->ReadOnly == FALSE);
  1451. //
  1452. // we have the lock exclusive or nobody is operating inside this hive
  1453. //
  1454. //ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1455. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  1456. //
  1457. // Get sizes and addresses
  1458. //
  1459. Me = HvpGetCellMap(Hive, Cell);
  1460. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  1461. Type = HvGetCellType(Cell);
  1462. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  1463. //
  1464. // at this point, bin should be valid (either in memory or in the paged pool)
  1465. //
  1466. ASSERT_BIN_VALID(Me);
  1467. DHvCheckBin(Hive,Bin);
  1468. freebase = HvpGetHCell(Hive, Cell);
  1469. if( freebase == NULL ) {
  1470. //
  1471. // we couldn't map view for this cell
  1472. // this shouldn't happen as the cell here is already marked dirty
  1473. // or it's entire bin is mapped
  1474. //
  1475. ASSERT( FALSE);
  1476. return;
  1477. }
  1478. //
  1479. // We should hit this if there is any bogus code path where data is modified
  1480. // but not marked as dirty; We could run into a lot of problems if this ASSERT
  1481. // ever fires !!!
  1482. //
  1483. ASSERT_CELL_DIRTY(Hive,Cell);
  1484. // release the cell right here as the reglock is held exclusive
  1485. HvReleaseCell(Hive,Cell);
  1486. //
  1487. // go do actual frees, cannot fail from this point on
  1488. //
  1489. ASSERT(freebase->Size < 0);
  1490. freebase->Size *= -1;
  1491. savesize = freebase->Size;
  1492. //
  1493. // Look for free neighbors and coalesce them. We will never travel
  1494. // around this loop more than twice.
  1495. //
  1496. while (
  1497. HvpIsFreeNeighbor(
  1498. Hive,
  1499. Bin,
  1500. freebase,
  1501. &neighbor,
  1502. Type
  1503. ) == TRUE
  1504. )
  1505. {
  1506. if (neighbor > freebase) {
  1507. //
  1508. // Neighboring free cell is immediately above us in memory.
  1509. //
  1510. if (USE_OLD_CELL(Hive)) {
  1511. tmp = (PHCELL)((PUCHAR)neighbor + neighbor->Size);
  1512. if ( ((ULONG)((ULONG_PTR)tmp - (ULONG_PTR)Bin)) < Bin->Size) {
  1513. tmp->u.OldCell.Last = (ULONG)((ULONG_PTR)freebase - (ULONG_PTR)Bin);
  1514. }
  1515. }
  1516. freebase->Size += neighbor->Size;
  1517. } else {
  1518. //
  1519. // Neighboring free cell is immediately below us in memory.
  1520. //
  1521. if (USE_OLD_CELL(Hive)) {
  1522. tmp = (PHCELL)((PUCHAR)freebase + freebase->Size);
  1523. if ( ((ULONG)((ULONG_PTR)tmp - (ULONG_PTR)Bin)) < Bin->Size ) {
  1524. tmp->u.OldCell.Last = (ULONG)((ULONG_PTR)neighbor - (ULONG_PTR)Bin);
  1525. }
  1526. }
  1527. neighbor->Size += freebase->Size;
  1528. freebase = neighbor;
  1529. }
  1530. }
  1531. //
  1532. // freebase now points to the biggest free cell we could make, none
  1533. // of which is on the free list. So put it on the list.
  1534. //
  1535. newfreecell = (Bin->FileOffset) +
  1536. ((ULONG)((ULONG_PTR)freebase - (ULONG_PTR)Bin)) +
  1537. (Type*HCELL_TYPE_MASK);
  1538. #if DBG
  1539. //
  1540. // entire bin is in memory; no problem to call HvpGetHCell
  1541. //
  1542. ASSERT(HvpGetHCell(Hive, newfreecell) == freebase);
  1543. HvReleaseCell(Hive,newfreecell);
  1544. if (USE_OLD_CELL(Hive)) {
  1545. RtlFillMemory(
  1546. &(freebase->u.OldCell.u.UserData),
  1547. (freebase->Size - FIELD_OFFSET(HCELL, u.OldCell.u.UserData)),
  1548. HCELL_FREE_FILL
  1549. );
  1550. } else {
  1551. RtlFillMemory(
  1552. &(freebase->u.NewCell.u.UserData),
  1553. (freebase->Size - FIELD_OFFSET(HCELL, u.NewCell.u.UserData)),
  1554. HCELL_FREE_FILL
  1555. );
  1556. }
  1557. #endif
  1558. HvpEnlistFreeCell(Hive, newfreecell, freebase->Size, Type, TRUE);
  1559. return;
  1560. }
  1561. BOOLEAN
  1562. HvpIsFreeNeighbor(
  1563. PHHIVE Hive,
  1564. PHBIN Bin,
  1565. PHCELL FreeCell,
  1566. PHCELL *FreeNeighbor,
  1567. HSTORAGE_TYPE Type
  1568. )
  1569. /*++
  1570. Routine Description:
  1571. Reports on whether FreeCell has at least one free neighbor and
  1572. if so where. Free neighbor will be cut out of the free list.
  1573. Arguments:
  1574. Hive - hive we're working on
  1575. Bin - pointer to the storage bin
  1576. FreeCell - supplies a pointer to a cell that has been freed, or
  1577. the result of a coalesce.
  1578. FreeNeighbor - supplies a pointer to a variable to receive the address
  1579. of a free neigbhor of FreeCell, if such exists
  1580. Type - storage type of the cell
  1581. Return Value:
  1582. TRUE if a free neighbor was found, else false.
  1583. --*/
  1584. {
  1585. PHCELL ptcell;
  1586. HCELL_INDEX cellindex;
  1587. ULONG CellOffset;
  1588. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvpIsFreeNeighbor:\n\tBin=%p",Bin));
  1589. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"FreeCell=%08lx\n", FreeCell));
  1590. ASSERT(Hive->ReadOnly == FALSE);
  1591. //
  1592. // Neighbor above us?
  1593. //
  1594. *FreeNeighbor = NULL;
  1595. cellindex = HCELL_NIL;
  1596. ptcell = (PHCELL)((PUCHAR)FreeCell + FreeCell->Size);
  1597. ASSERT( ((ULONG)((ULONG_PTR)ptcell - (ULONG_PTR)Bin)) <= Bin->Size);
  1598. if (((ULONG)((ULONG_PTR)ptcell - (ULONG_PTR)Bin)) < Bin->Size) {
  1599. if (ptcell->Size > 0) {
  1600. *FreeNeighbor = ptcell;
  1601. goto FoundNeighbor;
  1602. }
  1603. }
  1604. //
  1605. // Neighbor below us?
  1606. //
  1607. if (USE_OLD_CELL(Hive)) {
  1608. if (FreeCell->u.OldCell.Last != HBIN_NIL) {
  1609. ptcell = (PHCELL)((PUCHAR)Bin + FreeCell->u.OldCell.Last);
  1610. if (ptcell->Size > 0) {
  1611. *FreeNeighbor = ptcell;
  1612. goto FoundNeighbor;
  1613. }
  1614. }
  1615. } else {
  1616. ptcell = (PHCELL)(Bin+1);
  1617. while (ptcell < FreeCell) {
  1618. //
  1619. // scan through the cells from the start of the bin looking for neighbor.
  1620. //
  1621. if (ptcell->Size > 0) {
  1622. if ((PHCELL)((PUCHAR)ptcell + ptcell->Size) == FreeCell) {
  1623. *FreeNeighbor = ptcell;
  1624. //
  1625. // Try and mark it dirty, since we will be changing
  1626. // the size field. If this fails, ignore
  1627. // the free neighbor, we will not fail the free
  1628. // just because we couldn't mark the cell dirty
  1629. // so it could be coalesced.
  1630. //
  1631. // Note we only bother doing this for new hives,
  1632. // for old format hives we always mark the whole
  1633. // bin dirty.
  1634. //
  1635. if ((Type == Volatile) ||
  1636. (HvMarkCellDirty(Hive, (ULONG)((ULONG_PTR)ptcell-(ULONG_PTR)Bin) + Bin->FileOffset))) {
  1637. goto FoundNeighbor;
  1638. } else {
  1639. return(FALSE);
  1640. }
  1641. } else {
  1642. ptcell = (PHCELL)((PUCHAR)ptcell + ptcell->Size);
  1643. }
  1644. } else {
  1645. ptcell = (PHCELL)((PUCHAR)ptcell - ptcell->Size);
  1646. }
  1647. }
  1648. }
  1649. return(FALSE);
  1650. FoundNeighbor:
  1651. CellOffset = (ULONG)((PUCHAR)ptcell - (PUCHAR)Bin);
  1652. cellindex = Bin->FileOffset + CellOffset + (Type*HCELL_TYPE_MASK);
  1653. HvpDelistFreeCell(Hive, cellindex, Type);
  1654. return TRUE;
  1655. }
  1656. HCELL_INDEX
  1657. HvReallocateCell(
  1658. PHHIVE Hive,
  1659. HCELL_INDEX Cell,
  1660. ULONG NewSize
  1661. )
  1662. /*++
  1663. Routine Description:
  1664. Grows or shrinks a cell.
  1665. NOTE:
  1666. MUST NOT FAIL if the cell is being made smaller. Can be
  1667. a noop, but must work.
  1668. WARNING:
  1669. If the cell is grown, it will get a NEW and DIFFERENT HCELL_INDEX!!!
  1670. Arguments:
  1671. Hive - supplies a pointer to the hive control structure for the
  1672. hive of interest
  1673. Cell - supplies index of cell to grow or shrink
  1674. NewSize - desired size of cell (this is an absolute size, not an
  1675. increment or decrement.)
  1676. Return Value:
  1677. New HCELL_INDEX for cell, or HCELL_NIL if failure.
  1678. If return is HCELL_NIL, either old cell did not exist, or it did exist
  1679. and we could not make a new one. In either case, nothing has changed.
  1680. If return is NOT HCELL_NIL, then it is the HCELL_INDEX for the Cell,
  1681. which very probably moved.
  1682. --*/
  1683. {
  1684. PUCHAR oldaddress;
  1685. LONG oldsize;
  1686. ULONG oldalloc;
  1687. HCELL_INDEX NewCell; // return value
  1688. PUCHAR newaddress;
  1689. ULONG Type;
  1690. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvReallocateCell:\n"));
  1691. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tHive=%p Cell=%08lx NewSize=%08lx\n",Hive,Cell,NewSize));
  1692. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1693. ASSERT(Hive->ReadOnly == FALSE);
  1694. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  1695. //
  1696. // Make room for overhead fields and round up to HCELL_PAD boundary
  1697. //
  1698. if (USE_OLD_CELL(Hive)) {
  1699. NewSize += FIELD_OFFSET(HCELL, u.OldCell.u.UserData);
  1700. } else {
  1701. NewSize += FIELD_OFFSET(HCELL, u.NewCell.u.UserData);
  1702. }
  1703. NewSize = ROUND_UP(NewSize, HCELL_PAD(Hive));
  1704. //
  1705. // Adjust the size (an easy fix for granularity)
  1706. //
  1707. HvpAdjustCellSize(NewSize);
  1708. //
  1709. // reject impossible/unreasonable values
  1710. //
  1711. if (NewSize > HSANE_CELL_MAX) {
  1712. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tNewSize=%08lx\n", NewSize));
  1713. return HCELL_NIL;
  1714. }
  1715. //
  1716. // Get sizes and addresses
  1717. //
  1718. oldaddress = (PUCHAR)HvGetCell(Hive, Cell);
  1719. if( oldaddress == NULL ) {
  1720. //
  1721. // we couldn't map a view for this cell
  1722. // caller should handle this as STATUS_INSUFFICIENT_RESOURCES
  1723. //
  1724. return HCELL_NIL;
  1725. }
  1726. // release the cell here as we are holding the reglock exclusive
  1727. HvReleaseCell(Hive,Cell);
  1728. oldsize = HvGetCellSize(Hive, oldaddress);
  1729. ASSERT(oldsize > 0);
  1730. if (USE_OLD_CELL(Hive)) {
  1731. oldalloc = (ULONG)(oldsize + FIELD_OFFSET(HCELL, u.OldCell.u.UserData));
  1732. } else {
  1733. oldalloc = (ULONG)(oldsize + FIELD_OFFSET(HCELL, u.NewCell.u.UserData));
  1734. }
  1735. Type = HvGetCellType(Cell);
  1736. DHvCheckHive(Hive);
  1737. if (NewSize == oldalloc) {
  1738. //
  1739. // This is a noop, return the same cell
  1740. //
  1741. NewCell = Cell;
  1742. } else if (NewSize < oldalloc) {
  1743. //
  1744. // This is a shrink.
  1745. //
  1746. // PERFNOTE - IMPLEMENT THIS. Do nothing for now.
  1747. //
  1748. NewCell = Cell;
  1749. } else {
  1750. //
  1751. // This is a grow.
  1752. //
  1753. //
  1754. // PERFNOTE - Someday we want to detect that there is a free neighbor
  1755. // above us and grow into that neighbor if possible.
  1756. // For now, always do the allocate, copy, free gig.
  1757. //
  1758. //
  1759. // Allocate a new block of memory to hold the cell
  1760. //
  1761. if ((NewCell = HvpDoAllocateCell(Hive, NewSize, Type,HCELL_NIL)) == HCELL_NIL) {
  1762. return HCELL_NIL;
  1763. }
  1764. ASSERT(HvIsCellAllocated(Hive, NewCell));
  1765. newaddress = (PUCHAR)HvGetCell(Hive, NewCell);
  1766. if( newaddress == NULL ) {
  1767. //
  1768. // we couldn't map a view for this cell
  1769. // this shouldn't happen as we just allocated this cell
  1770. // (i.e. it's containing bin should be PINNED into memory)
  1771. //
  1772. ASSERT( FALSE );
  1773. return HCELL_NIL;
  1774. }
  1775. // release the cell here as we are holding the reglock exclusive
  1776. HvReleaseCell(Hive,NewCell);
  1777. //
  1778. // oldaddress points to the old data block for the cell,
  1779. // newaddress points to the new data block, copy the data
  1780. //
  1781. RtlMoveMemory(newaddress, oldaddress, oldsize);
  1782. //
  1783. // Free the old block of memory
  1784. //
  1785. HvFreeCell(Hive, Cell);
  1786. }
  1787. DHvCheckHive(Hive);
  1788. return NewCell;
  1789. }
  1790. #ifdef NT_RENAME_KEY
  1791. HCELL_INDEX
  1792. HvDuplicateCell(
  1793. PHHIVE Hive,
  1794. HCELL_INDEX Cell,
  1795. HSTORAGE_TYPE Type,
  1796. BOOLEAN CopyData
  1797. )
  1798. /*++
  1799. Routine Description:
  1800. Makes an identical copy of the given Cell in the specified storagetype
  1801. Arguments:
  1802. Hive - supplies a pointer to the hive control structure for the
  1803. hive of interest
  1804. Cell - cell to duplicate
  1805. Type - destination storage
  1806. CopyData - if TRUE, data is copied, otherwise UserData is zeroed out
  1807. Return Value:
  1808. New HCELL_INDEX for cell, or HCELL_NIL if failure.
  1809. If return is HCELL_NIL, either old cell did not exist, or it did exist
  1810. and we could not make a new one. In either case, nothing has changed.
  1811. If return is NOT HCELL_NIL, then it is the HCELL_INDEX for the Cell,
  1812. which very probably moved.
  1813. --*/
  1814. {
  1815. PUCHAR CellAddress;
  1816. PUCHAR NewCellAddress;
  1817. LONG Size;
  1818. HCELL_INDEX NewCell;
  1819. PAGED_CODE();
  1820. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1821. ASSERT(Hive->Signature == HHIVE_SIGNATURE);
  1822. ASSERT(Hive->ReadOnly == FALSE);
  1823. ASSERT(HvIsCellAllocated(Hive, Cell));
  1824. //
  1825. // Get sizes and addresses
  1826. //
  1827. CellAddress = (PUCHAR)HvGetCell(Hive, Cell);
  1828. if( CellAddress == NULL ) {
  1829. //
  1830. // we couldn't map a view for this cell
  1831. //
  1832. return HCELL_NIL;
  1833. }
  1834. // release the cell here as we are holding the reglock exclusive
  1835. HvReleaseCell(Hive,Cell);
  1836. Size = HvGetCellSize(Hive, CellAddress);
  1837. NewCell = HvAllocateCell(Hive,Size,Type,((HSTORAGE_TYPE)HvGetCellType(Cell) == Type)?Cell:HCELL_NIL);
  1838. if( NewCell == HCELL_NIL ) {
  1839. return HCELL_NIL;
  1840. }
  1841. NewCellAddress = (PUCHAR)HvGetCell(Hive, NewCell);
  1842. if( NewCellAddress == NULL ) {
  1843. //
  1844. // we couldn't map the bin containing this cell
  1845. // this shouldn't happen as we just allocated this cell
  1846. // (i.e. it should be PINNED into memory at this point)
  1847. //
  1848. ASSERT( FALSE );
  1849. HvFreeCell(Hive, NewCell);
  1850. return HCELL_NIL;
  1851. }
  1852. // release the cell here as we are holding the reglock exclusive
  1853. HvReleaseCell(Hive,NewCell);
  1854. ASSERT( HvGetCellSize(Hive, NewCellAddress) >= Size );
  1855. //
  1856. // copy/initialize user data
  1857. //
  1858. if( CopyData == TRUE ) {
  1859. RtlCopyMemory(NewCellAddress,CellAddress,Size);
  1860. } else {
  1861. RtlZeroMemory(NewCellAddress, Size);
  1862. }
  1863. return NewCell;
  1864. }
  1865. #endif //NT_RENAME_KEY
  1866. BOOLEAN HvAutoCompressCheck(PHHIVE Hive)
  1867. /*++
  1868. Routine Description:
  1869. Checks the hive for the compression
  1870. Arguments:
  1871. Hive - supplies a pointer to the hive control structure for the
  1872. hive of interest
  1873. Return Value:
  1874. TRUE/FALSE
  1875. --*/
  1876. {
  1877. PCMHIVE CmHive;
  1878. ULONG CompressLevel;
  1879. PLIST_ENTRY AnchorAddr;
  1880. PFREE_HBIN FreeBin;
  1881. ULONG FreeSpace;
  1882. #ifndef _CM_LDR_
  1883. PAGED_CODE();
  1884. #endif //_CM_LDR_
  1885. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  1886. CmHive = CONTAINING_RECORD(Hive, CMHIVE, Hive);
  1887. if( CmHive->FileHandles[HFILE_TYPE_PRIMARY] == NULL ) {
  1888. //
  1889. // compress already scheduled or hive doesn't really have stable storage; bail out quickly
  1890. //
  1891. return FALSE;
  1892. }
  1893. if( IsListEmpty(&(Hive->Storage[Stable].FreeBins)) ) {
  1894. //
  1895. // no free bins; no worth bothering
  1896. //
  1897. return FALSE;
  1898. }
  1899. //
  1900. // iterate through the free bins and see how much space is wasted
  1901. //
  1902. FreeSpace = 0;
  1903. AnchorAddr = &(Hive->Storage[Stable].FreeBins);
  1904. FreeBin = (PFREE_HBIN)(Hive->Storage[Stable].FreeBins.Flink);
  1905. while ( FreeBin != (PFREE_HBIN)AnchorAddr ) {
  1906. FreeBin = CONTAINING_RECORD(FreeBin,
  1907. FREE_HBIN,
  1908. ListEntry);
  1909. FreeSpace += FreeBin->Size;
  1910. //
  1911. // skip to the next element
  1912. //
  1913. FreeBin = (PFREE_HBIN)(FreeBin->ListEntry.Flink);
  1914. }
  1915. CompressLevel = CM_HIVE_COMPRESS_LEVEL * (Hive->Storage[Stable].Length / 100);
  1916. if( FreeSpace < CompressLevel ) {
  1917. // disable temporary so we can test the system hive.
  1918. return FALSE;
  1919. }
  1920. return TRUE;
  1921. }
  1922. HCELL_INDEX
  1923. HvShiftCell(PHHIVE Hive,HCELL_INDEX Cell)
  1924. {
  1925. PHMAP_ENTRY t;
  1926. PHBIN Bin;
  1927. ASSERT( HvGetCellType(Cell) == Stable );
  1928. t = HvpGetCellMap(Hive, Cell);
  1929. ASSERT( t->BinAddress & HMAP_INPAGEDPOOL );
  1930. Bin = (PHBIN)HBIN_BASE(t->BinAddress);
  1931. ASSERT( Bin->Signature == HBIN_SIGNATURE );
  1932. return Cell - Bin->Spare;
  1933. }