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.

1113 lines
29 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. hivehint.c
  5. Abstract:
  6. This module contains free space display support.
  7. Author:
  8. Dragos C. Sambotin (dragoss) 15-Jul-1999
  9. Revision History:
  10. --*/
  11. #include "cmp.h"
  12. NTSTATUS
  13. HvpAdjustBitmap(
  14. IN PHHIVE Hive,
  15. IN ULONG HiveLength,
  16. IN OUT PRTL_BITMAP Bitmap
  17. );
  18. HCELL_INDEX
  19. HvpFindFreeCellInBin(
  20. PHHIVE Hive,
  21. ULONG Index,
  22. ULONG NewSize,
  23. HSTORAGE_TYPE Type,
  24. PHBIN Bin
  25. );
  26. HCELL_INDEX
  27. HvpFindFreeCellInThisViewWindow(
  28. PHHIVE Hive,
  29. ULONG Index,
  30. ULONG NewSize,
  31. HSTORAGE_TYPE Type,
  32. HCELL_INDEX Vicinity
  33. );
  34. HCELL_INDEX
  35. HvpScanForFreeCellInViewWindow(
  36. PHHIVE Hive,
  37. ULONG Index,
  38. ULONG NewSize,
  39. HSTORAGE_TYPE Type,
  40. HCELL_INDEX FileOffsetStart
  41. );
  42. #ifdef ALLOC_PRAGMA
  43. #pragma alloc_text(PAGE,HvpAdjustHiveFreeDisplay)
  44. #pragma alloc_text(PAGE,HvpFreeHiveFreeDisplay)
  45. #pragma alloc_text(PAGE,HvpAdjustBitmap)
  46. #pragma alloc_text(PAGE,HvpAddFreeCellHint)
  47. #pragma alloc_text(PAGE,HvpRemoveFreeCellHint)
  48. #pragma alloc_text(PAGE,HvpFindFreeCellInBin)
  49. #pragma alloc_text(PAGE,HvpFindFreeCellInThisViewWindow)
  50. #pragma alloc_text(PAGE,HvpScanForFreeCellInViewWindow)
  51. #pragma alloc_text(PAGE,HvpCheckViewBoundary)
  52. #pragma alloc_text(PAGE,HvpFindFreeCell)
  53. #endif
  54. NTSTATUS
  55. HvpAdjustHiveFreeDisplay(
  56. IN PHHIVE Hive,
  57. IN ULONG HiveLength,
  58. IN HSTORAGE_TYPE Type
  59. )
  60. /*++
  61. Routine Description:
  62. calls HvpAdjustBitmap for all bitmap sizes
  63. !!! - to be called when the size of the hive changes (shrink or grow case).
  64. Arguments:
  65. Hive - used for quota tracking.
  66. HiveLength - the new length of the hive.
  67. Type - Stable or Volatile.
  68. Return Value:
  69. NTSTATUS code.
  70. --*/
  71. {
  72. ULONG i;
  73. NTSTATUS Status;
  74. PAGED_CODE();
  75. for (i = 0; i < HHIVE_FREE_DISPLAY_SIZE; i++) {
  76. Status = HvpAdjustBitmap(Hive,HiveLength,&(Hive->Storage[Type].FreeDisplay[i]) );
  77. if( !NT_SUCCESS(Status) ){
  78. return Status;
  79. }
  80. }
  81. return STATUS_SUCCESS;
  82. }
  83. #define ROUND_UP_NOZERO(a, b) (a)?ROUND_UP(a,b):(b)
  84. #define ROUND_INCREMENTS 0x100
  85. VOID
  86. HvpFreeHiveFreeDisplay(
  87. IN PHHIVE Hive
  88. )
  89. /*++
  90. Routine Description:
  91. Frees the storage allocated for the free display bitmaps
  92. Arguments:
  93. Hive - used for quota tracking.
  94. Return Value:
  95. NTSTATUS code.
  96. --*/
  97. {
  98. ULONG i,j;
  99. NTSTATUS Status;
  100. ULONG BufferSize;
  101. PAGED_CODE();
  102. for( i=Stable;i<=Volatile;i++) {
  103. //
  104. // we may loose some quota here; due to rounding
  105. // we can prevent that by keeping the real size of
  106. // the bitmaps as a member of the hive struct
  107. //
  108. BufferSize = ROUND_UP_NOZERO(Hive->Storage[i].FreeDisplay[0].SizeOfBitMap / 8,ROUND_INCREMENTS);
  109. for (j = 0; j < HHIVE_FREE_DISPLAY_SIZE; j++) {
  110. if( Hive->Storage[i].FreeDisplay[j].Buffer != NULL ) {
  111. (Hive->Free)(Hive->Storage[i].FreeDisplay[j].Buffer, BufferSize);
  112. }
  113. }
  114. }
  115. return;
  116. }
  117. NTSTATUS
  118. HvpAdjustBitmap(
  119. IN PHHIVE Hive,
  120. IN ULONG HiveLength,
  121. IN OUT PRTL_BITMAP Bitmap
  122. )
  123. /*++
  124. Routine Description:
  125. When the length of the hive grows/shrinks, adjust the bitmap accordingly.
  126. - allocates a bitmap buffer large enough.
  127. - copies the relevant information from the old bitmap.
  128. Arguments:
  129. Hive - used for quota tracking.
  130. HiveLength - the new length of the hive.
  131. Bitmap - bitmap to operate on.
  132. Return Value:
  133. NTSTATUS code.
  134. --*/
  135. {
  136. ULONG VectorSize;
  137. ULONG NewBufferSize;
  138. ULONG OldBufferSize;
  139. PULONG Vector;
  140. PULONG OldVector;
  141. ULONG OldVectorSize;
  142. PAGED_CODE();
  143. VectorSize = HiveLength / HBLOCK_SIZE; // Vector size == bits
  144. NewBufferSize = ROUND_UP_NOZERO( (VectorSize + 7) / 8,ROUND_INCREMENTS); // BufferSize == Bytes
  145. if( Bitmap->SizeOfBitMap == 0 ) {
  146. OldBufferSize = 0;
  147. } else {
  148. OldBufferSize = ROUND_UP_NOZERO( (Bitmap->SizeOfBitMap + 7) / 8, ROUND_INCREMENTS);
  149. }
  150. if( NewBufferSize <= OldBufferSize ) {
  151. //
  152. // We don't shrink the vector; next time we grow, we'll perform
  153. // the adjustments
  154. //
  155. //
  156. // Clear all the unused bits and return;
  157. //
  158. // we don't really need to do this as nobody will write in here
  159. // we'll drop it in the final implementation
  160. //
  161. OldVectorSize = Bitmap->SizeOfBitMap;
  162. //
  163. // set the new size
  164. //
  165. RtlInitializeBitMap(Bitmap,Bitmap->Buffer,VectorSize);
  166. if( OldVectorSize < VectorSize ) {
  167. RtlClearBits (Bitmap,OldVectorSize,VectorSize - OldVectorSize);
  168. }
  169. return STATUS_SUCCESS;
  170. }
  171. //
  172. // else, the bitmap has enlarged. Allocate a new buffer and copy the bits already set.
  173. //
  174. Vector = (PULONG)((Hive->Allocate)(NewBufferSize, TRUE,CM_FIND_LEAK_TAG39));
  175. if (Vector == NULL) {
  176. return STATUS_INSUFFICIENT_RESOURCES;
  177. }
  178. OldVector = Bitmap->Buffer;
  179. //CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"HvpAdjustBitmap: Old %lu :: %lu (%lx) New %lu :: %lu (%lx)\n",OldBufferSize,Bitmap->SizeOfBitMap,OldVector,NewBufferSize,VectorSize,Vector));
  180. RtlZeroMemory(Vector,NewBufferSize);
  181. RtlInitializeBitMap(Bitmap, Vector, VectorSize);
  182. if( OldVector != NULL ) {
  183. //
  184. // copy the already set bits
  185. //
  186. RtlCopyMemory (Vector,OldVector,OldBufferSize);
  187. //
  188. // Free the old vector
  189. //
  190. (Hive->Free)(OldVector, OldBufferSize);
  191. }
  192. return STATUS_SUCCESS;
  193. }
  194. VOID
  195. HvpAddFreeCellHint(
  196. PHHIVE Hive,
  197. HCELL_INDEX Cell,
  198. ULONG Index,
  199. HSTORAGE_TYPE Type
  200. )
  201. /*++
  202. Routine Description:
  203. Sets the corresponding bit in the bitmap
  204. Arguments:
  205. Hive - hive operating on
  206. Cell - free cell
  207. Index - index in FreeDisplay (based on the free cell size)
  208. Type - storage type (Stable or Volatile)
  209. Return Value:
  210. VOID
  211. --*/
  212. {
  213. ULONG BinIndex;
  214. PHMAP_ENTRY Me;
  215. PHBIN Bin;
  216. PAGED_CODE();
  217. Me = HvpGetCellMap(Hive, Cell);
  218. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  219. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  220. //
  221. // compute the bin index and for the begining of the bin
  222. //
  223. BinIndex = Bin->FileOffset / HBLOCK_SIZE;
  224. RtlSetBits (&(Hive->Storage[Type].FreeDisplay[Index]), BinIndex, Bin->Size / HBLOCK_SIZE);
  225. Hive->Storage[Type].FreeSummary |= (1 << Index);
  226. }
  227. VOID
  228. HvpRemoveFreeCellHint(
  229. PHHIVE Hive,
  230. HCELL_INDEX Cell,
  231. ULONG Index,
  232. HSTORAGE_TYPE Type
  233. )
  234. /*++
  235. Routine Description:
  236. Clears the corresponding bit in the bitmap
  237. Arguments:
  238. Hive - hive operating on
  239. Cell - free cell
  240. Index - index in FreeDisplay (based on the free cell size)
  241. Type - storage type (Stable or Volatile)
  242. Return Value:
  243. VOID
  244. --*/
  245. {
  246. ULONG BinIndex;
  247. ULONG TempIndex;
  248. PHMAP_ENTRY Me;
  249. PHBIN Bin;
  250. ULONG CellOffset;
  251. ULONG Size;
  252. PHCELL p;
  253. BOOLEAN CellFound = FALSE;
  254. PAGED_CODE();
  255. Me = HvpGetCellMap(Hive, Cell);
  256. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  257. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  258. CellOffset = Bin->FileOffset + sizeof(HBIN);
  259. #ifdef CM_MAP_NO_READ
  260. //
  261. // we ned to be protected against exception raised by the FS while faulting in data
  262. //
  263. try {
  264. #endif //CM_MAP_NO_READ
  265. //
  266. // There is a chance we can find a suitable free cell
  267. //
  268. p = (PHCELL)((PUCHAR)Bin + sizeof(HBIN));
  269. while (p < (PHCELL)((PUCHAR)Bin + Bin->Size)) {
  270. //
  271. // if free cell, check it out, add it to free list for hive
  272. //
  273. if (p->Size >= 0) {
  274. Size = (ULONG)p->Size;
  275. HvpComputeIndex(TempIndex, Size);
  276. if ((Index == TempIndex) && (CellOffset != (Cell&(~HCELL_TYPE_MASK)) )) {
  277. //
  278. // there is at least one free cell of this size (this one)
  279. // different than the one being delisted
  280. //
  281. CellFound = TRUE;
  282. break;
  283. }
  284. } else {
  285. //
  286. // used cell
  287. //
  288. Size = (ULONG)(p->Size * -1);
  289. }
  290. ASSERT( ((LONG)Size) >= 0);
  291. p = (PHCELL)((PUCHAR)p + Size);
  292. CellOffset += Size;
  293. }
  294. #ifdef CM_MAP_NO_READ
  295. } except (EXCEPTION_EXECUTE_HANDLER) {
  296. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpRemoveFreeCellHint: exception thrown ehile faulting in data, code:%08lx\n", GetExceptionCode()));
  297. //
  298. // better not use cells inthis range rather than leaving false hints
  299. //
  300. CellFound = FALSE;
  301. }
  302. #endif //CM_MAP_NO_READ
  303. if( CellFound == FALSE ) {
  304. //
  305. // no cell with this index was found
  306. // compute the bin index and for the begining of the bin
  307. //
  308. BinIndex = Bin->FileOffset / HBLOCK_SIZE;
  309. RtlClearBits (&(Hive->Storage[Type].FreeDisplay[Index]), BinIndex, Bin->Size / HBLOCK_SIZE);
  310. }
  311. if( RtlNumberOfSetBits(&(Hive->Storage[Type].FreeDisplay[Index]) ) != 0 ) {
  312. //
  313. // there are still some other free cells of this size
  314. //
  315. Hive->Storage[Type].FreeSummary |= (1 << Index);
  316. } else {
  317. //
  318. // entire bitmap is 0 (i.e. no other free cells of this size)
  319. //
  320. Hive->Storage[Type].FreeSummary &= (~(1 << Index));
  321. }
  322. }
  323. HCELL_INDEX
  324. HvpFindFreeCellInBin(
  325. PHHIVE Hive,
  326. ULONG Index,
  327. ULONG NewSize,
  328. HSTORAGE_TYPE Type,
  329. PHBIN Bin
  330. )
  331. /*++
  332. Routine Description:
  333. Lookup for a free cell with the size NewSize in this particular bin
  334. Arguments:
  335. Hive - target hive.
  336. Index - index in FreeDisplay (based on the free cell size)
  337. NewSize - desired size
  338. Type - storage type (Stable or Volatile)
  339. Bin - Bin in question
  340. Return Value:
  341. A free cellindex with a size bigger than NewSize, or HCELL_NIL
  342. --*/
  343. {
  344. ULONG BinIndex;
  345. ULONG CellOffset;
  346. PHCELL p;
  347. ULONG BinOffset;
  348. ULONG Size;
  349. HCELL_INDEX cellindex;
  350. ULONG FoundCellIndex;
  351. PAGED_CODE();
  352. BinOffset = Bin->FileOffset;
  353. BinIndex = BinOffset/HBLOCK_SIZE;
  354. if( RtlCheckBit(&(Hive->Storage[Type].FreeDisplay[Index]), BinIndex) == 0 ) {
  355. //
  356. // no hint for this bin
  357. //
  358. return HCELL_NIL;
  359. }
  360. CellOffset = sizeof(HBIN);
  361. #ifdef CM_MAP_NO_READ
  362. //
  363. // we ned to be protected against exception raised by the FS while faulting in data
  364. //
  365. try {
  366. #endif //CM_MAP_NO_READ
  367. //
  368. // There is a chance we can find a suitable free cell
  369. //
  370. p = (PHCELL)((PUCHAR)Bin + sizeof(HBIN));
  371. while (p < (PHCELL)((PUCHAR)Bin + Bin->Size)) {
  372. //
  373. // if free cell, check it out, add it to free list for hive
  374. //
  375. if (p->Size >= 0) {
  376. Size = (ULONG)p->Size;
  377. //
  378. // cell is free, and is not obviously corrupt, add to free list
  379. //
  380. CellOffset = (ULONG)((PUCHAR)p - (PUCHAR)Bin);
  381. cellindex = BinOffset + CellOffset + (Type*HCELL_TYPE_MASK);
  382. if (NewSize <= (ULONG)Size) {
  383. //
  384. // Found a big enough cell.
  385. //
  386. HvpComputeIndex(FoundCellIndex, Size);
  387. if( Index == FoundCellIndex ) {
  388. //
  389. // and enlisted at the same index (we want to avoid fragmentation if possible!)
  390. //
  391. if (! HvMarkCellDirty(Hive, cellindex)) {
  392. return HCELL_NIL;
  393. }
  394. HvpDelistFreeCell(Hive, cellindex, Type);
  395. ASSERT(p->Size > 0);
  396. ASSERT(NewSize <= (ULONG)p->Size);
  397. return cellindex;
  398. }
  399. }
  400. } else {
  401. //
  402. // used cell
  403. //
  404. Size = (ULONG)(p->Size * -1);
  405. }
  406. ASSERT( ((LONG)Size) >= 0);
  407. p = (PHCELL)((PUCHAR)p + Size);
  408. }
  409. #ifdef CM_MAP_NO_READ
  410. } except (EXCEPTION_EXECUTE_HANDLER) {
  411. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpFindFreeCellInBin: exception thrown ehile faulting in data, code:%08lx\n", GetExceptionCode()));
  412. return HCELL_NIL;
  413. }
  414. #endif //CM_MAP_NO_READ
  415. //
  416. // no free cell matching this size on this bin ; We did all this work for nothing!
  417. //
  418. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"[HvpFindFreeCellInBin] (Offset,Size) = (%lx,%lx) ==> No Match\n",BinOffset,Bin->Size));
  419. return HCELL_NIL;
  420. }
  421. HCELL_INDEX
  422. HvpScanForFreeCellInViewWindow(
  423. PHHIVE Hive,
  424. ULONG Index,
  425. ULONG NewSize,
  426. HSTORAGE_TYPE Type,
  427. HCELL_INDEX FileOffsetStart
  428. )
  429. /*++
  430. Routine Description:
  431. Lookup for a free cell with the size NewSize in the CM_VIEW_SIZE window defined by
  432. Vicinity.
  433. If it doesn't find a free cell for the specifed index, tries with the
  434. Arguments:
  435. Hive - target hive.
  436. Index - index in FreeDisplay (based on the free cell size)
  437. NewSize - desired size
  438. Type - storage type (Stable or Volatile)
  439. Vicinity - defines the window; it is never HCELL_NIL !!!
  440. Return Value:
  441. A free cellindex with a size bigger than NewSize, or HCELL_NIL
  442. Note:
  443. Vicinity is a physical file offset at this point. we need to
  444. convert it to a logical one prior to accessing the map
  445. --*/
  446. {
  447. ULONG FileOffsetEnd;
  448. HCELL_INDEX Cell;
  449. PHMAP_ENTRY Me;
  450. PHBIN Bin;
  451. PFREE_HBIN FreeBin;
  452. ULONG BinFileOffset;
  453. ULONG BinSize;
  454. PAGED_CODE();
  455. FileOffsetEnd = FileOffsetStart + CM_VIEW_SIZE;
  456. FileOffsetEnd -= HBLOCK_SIZE;
  457. if( FileOffsetStart != 0 ) {
  458. FileOffsetStart -= HBLOCK_SIZE;
  459. }
  460. if( FileOffsetEnd > Hive->Storage[Type].Length ) {
  461. FileOffsetEnd = Hive->Storage[Type].Length;
  462. }
  463. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"\t[HvpScanForFreeCellInViewWindow] (Start,End) = (%lx,%lx) Size = %lx\n",FileOffsetStart,FileOffsetEnd,Hive->Storage[Type].Length));
  464. //
  465. // sanity ASSERT
  466. //
  467. ASSERT( FileOffsetStart < FileOffsetEnd );
  468. //
  469. // the caller already checked for this; remember, hints are for real!
  470. //
  471. ASSERT( !RtlAreBitsClear( &(Hive->Storage[Type].FreeDisplay[Index]),FileOffsetStart/HBLOCK_SIZE,(FileOffsetEnd - FileOffsetStart) / HBLOCK_SIZE) );
  472. while( FileOffsetStart < FileOffsetEnd ) {
  473. Cell = FileOffsetStart + (Type*HCELL_TYPE_MASK);
  474. Me = HvpGetCellMap(Hive, Cell);
  475. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  476. //
  477. // skip discarded bins
  478. //
  479. if(Me->BinAddress & HMAP_DISCARDABLE) {
  480. FreeBin = (PFREE_HBIN)Me->BlockAddress;
  481. if( FreeBin->FileOffset == FileOffsetStart ) {
  482. FileOffsetStart += FreeBin->Size;
  483. } else {
  484. //
  485. // the bin does not start in this window;
  486. // skip to the next bin in this window
  487. //
  488. FileOffsetStart = FreeBin->FileOffset + FreeBin->Size;
  489. }
  490. continue;
  491. }
  492. if((Me->BinAddress & (HMAP_INVIEW|HMAP_INPAGEDPOOL)) == 0) {
  493. //
  494. // bin is not mapped, map it now!!!
  495. // do not touch the view as we may iterate through
  496. // the hole hive; this will keep the view for this window
  497. // mapped, as we hold the registry lock exclusive
  498. //
  499. if( !NT_SUCCESS(CmpMapThisBin((PCMHIVE)Hive,Cell,FALSE)) ) {
  500. //
  501. // cannot map bin due to insufficient resources
  502. //
  503. return HCELL_NIL;
  504. }
  505. ASSERT( Me->BinAddress & HMAP_INVIEW );
  506. }
  507. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  508. #ifdef CM_MAP_NO_READ
  509. //
  510. // we need to protect against in-page-errors thrown by mm while faulting in data
  511. //
  512. try {
  513. #endif //CM_MAP_NO_READ
  514. BinFileOffset = Bin->FileOffset;
  515. BinSize = Bin->Size;
  516. #ifdef CM_MAP_NO_READ
  517. } except (EXCEPTION_EXECUTE_HANDLER) {
  518. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpScanForFreeCellInViewWindow: exception thrown while faulting in data, code:%08lx\n", GetExceptionCode()));
  519. return HCELL_NIL;
  520. }
  521. #endif //CM_MAP_NO_READ
  522. if( BinFileOffset == FileOffsetStart ) {
  523. Cell = HvpFindFreeCellInBin(Hive,Index,NewSize,Type,Bin);
  524. if( Cell != HCELL_NIL ) {
  525. //found it!
  526. return Cell;
  527. }
  528. FileOffsetStart += BinSize;
  529. } else {
  530. //
  531. // bin does not start in this CM_VIEW_SIZE window; skip to the next bin in this window
  532. //
  533. FileOffsetStart = BinFileOffset + BinSize;
  534. }
  535. }
  536. //
  537. // no free cell matching this size on the CM_VIEW_SIZE window ; We did all this work for nothing!
  538. //
  539. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"[HvpScanForFreeCellInViewWindow] (Start,End) = (%lx,%lx) ==> No Match\n",FileOffsetStart,FileOffsetEnd));
  540. return HCELL_NIL;
  541. }
  542. HCELL_INDEX
  543. HvpFindFreeCellInThisViewWindow(
  544. PHHIVE Hive,
  545. ULONG Index,
  546. ULONG NewSize,
  547. HSTORAGE_TYPE Type,
  548. HCELL_INDEX Vicinity
  549. )
  550. /*++
  551. Routine Description:
  552. Lookup for a free cell with the size NewSize in the window defined by
  553. Vicinity.
  554. If it doesn't find a free cell for the specifed index, tries with the
  555. Arguments:
  556. Hive - target hive.
  557. Index - index in FreeDisplay (based on the free cell size)
  558. NewSize - desired size
  559. Type - storage type (Stable or Volatile)
  560. Vicinity - defines the window; it is never HCELL_NIL !!!
  561. Return Value:
  562. A free cellindex with a size bigger than NewSize, or HCELL_NIL
  563. Note:
  564. Vicinity is a logical file offset at this point. This function
  565. converts it to a physical one, and HvpScanForFindFreeCellInViewWindow
  566. converts it back to logical prior to getting the cell map.
  567. --*/
  568. {
  569. HCELL_INDEX Cell;
  570. ULONG FileOffsetStart;
  571. ULONG FileOffsetEnd;
  572. ULONG VicinityViewOffset;
  573. ULONG Summary;
  574. ULONG Offset;
  575. ULONG RunLength;
  576. PAGED_CODE();
  577. ASSERT( Vicinity != HCELL_NIL );
  578. VicinityViewOffset = ((Vicinity&(~HCELL_TYPE_MASK)) + HBLOCK_SIZE) & (~(CM_VIEW_SIZE - 1));
  579. FileOffsetStart = VicinityViewOffset & (~(CM_VIEW_SIZE - 1));
  580. FileOffsetEnd = FileOffsetStart + CM_VIEW_SIZE;
  581. if( FileOffsetEnd > (Hive->Storage[Type].Length + HBLOCK_SIZE) ) {
  582. FileOffsetEnd = Hive->Storage[Type].Length + HBLOCK_SIZE;
  583. }
  584. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"[HvpFindFreeCellInThisViewWindow] Vicinity = %lx (Start,End) = (%lx,%lx) Size = %lx\n",Vicinity,FileOffsetStart,FileOffsetEnd,Hive->Storage[Type].Length));
  585. //
  586. // sanity assert
  587. //
  588. ASSERT( FileOffsetStart < FileOffsetEnd );
  589. //
  590. // at this point the offset is physical (file-oriented, i.e. it is
  591. // translated with HBLOCK_SIZE; HvpScanForFreeCellInViewWindow will do the
  592. // reverse computation to adjust the offset)
  593. //
  594. //
  595. // Compute Summary vector of Display entries that are non null
  596. //
  597. Summary = Hive->Storage[Type].FreeSummary;
  598. Summary = Summary & ~((1 << Index) - 1);
  599. //
  600. // We now have a summary of lists that are non-null and may
  601. // contain entries large enough to satisfy the request.
  602. // Iterate through the list and pull the first cell that is
  603. // big enough. If no cells are big enough, advance to the
  604. // next non-null list.
  605. //
  606. ASSERT(HHIVE_FREE_DISPLAY_SIZE == 24);
  607. Offset = FileOffsetStart?(FileOffsetStart-HBLOCK_SIZE):0;
  608. RunLength = FileOffsetEnd - FileOffsetStart;
  609. if( FileOffsetStart == 0 ) {
  610. //
  611. // first run is one block shorter !
  612. //
  613. RunLength -= HBLOCK_SIZE;
  614. }
  615. Offset /= HBLOCK_SIZE;
  616. RunLength /= HBLOCK_SIZE;
  617. while (Summary != 0) {
  618. if (Summary & 0xff) {
  619. Index = CmpFindFirstSetRight[Summary & 0xff];
  620. } else if (Summary & 0xff00) {
  621. Index = CmpFindFirstSetRight[(Summary & 0xff00) >> 8] + 8;
  622. } else {
  623. ASSERT(Summary & 0xff0000);
  624. Index = CmpFindFirstSetRight[(Summary & 0xff0000) >> 16] + 16;
  625. }
  626. //
  627. // we go down this path only if we have any hints
  628. //
  629. if( !RtlAreBitsClear( &(Hive->Storage[Type].FreeDisplay[Index]),Offset,RunLength) ) {
  630. //
  631. // we have a reason to scan this view
  632. //
  633. Cell = HvpScanForFreeCellInViewWindow(Hive,Index,NewSize,Type,VicinityViewOffset);
  634. if( Cell != HCELL_NIL ) {
  635. // found it
  636. return Cell;
  637. }
  638. //
  639. // if we got here, the hints are invalid
  640. //
  641. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"[HvpFindFreeCellInThisViewWindow] (Start,End) = (%lx,%lx) Offset = %lx RunLength = %lx\n",FileOffsetStart,FileOffsetEnd,Offset,RunLength));
  642. }
  643. //
  644. // No suitable cell was found of this size.
  645. // Clear the bit in the summary and try the
  646. // next biggest size
  647. //
  648. ASSERT(Summary & (1 << Index));
  649. Summary = Summary & ~(1 << Index);
  650. }
  651. return HCELL_NIL;
  652. }
  653. HCELL_INDEX
  654. HvpFindFreeCell(
  655. PHHIVE Hive,
  656. ULONG Index,
  657. ULONG NewSize,
  658. HSTORAGE_TYPE Type,
  659. HCELL_INDEX Vicinity
  660. )
  661. /*++
  662. Routine Description:
  663. Lookup for a free cell. First try is in the CM_VIEW_SIZE window defined
  664. by Vicinity. If no free cell is found in this window (or vicinity
  665. if NIL), entire hive is searched (window by window).
  666. Arguments:
  667. Hive - target hive.
  668. Index - index in FreeDisplay (based on the free cell size)
  669. NewSize - desired size
  670. Type - storage type (Stable or Volatile)
  671. Vicinity - defines the window.
  672. Return Value:
  673. A free cellindex with a size bigger than NewSize, or HCELL_NIL
  674. Optimization:
  675. When Vicinity is HCELL_NIL or if a cell is not found in the same window
  676. as the vicinity, we don't really care where the cell gets allocated.
  677. So, rather than iterating the whole hive, is a good ideea to search first
  678. in the pinned view list, then in the mapped view list, and at the end
  679. in the rest of unmapped views.
  680. DRAGOS: This is not finished: need to determine whether we need it or not
  681. --*/
  682. {
  683. HCELL_INDEX Cell = HCELL_NIL;
  684. ULONG FileOffset = 0;
  685. PCMHIVE CmHive;
  686. /*
  687. PCMHIVE CmHive;
  688. PCM_VIEW_OF_FILE CmView;
  689. USHORT NrViews;
  690. */
  691. PAGED_CODE();
  692. CmHive = (PCMHIVE)CONTAINING_RECORD(Hive, CMHIVE, Hive);
  693. #if DBG
  694. {
  695. UNICODE_STRING HiveName;
  696. RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName);
  697. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"[HvpFindFreeCell] CellSize = %lu Vicinity = %lx :: Hive (%p) (%.*S) ...",NewSize,Vicinity,Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer));
  698. }
  699. #endif
  700. //
  701. // Vicinity should have the same storage as the new cell !
  702. //
  703. ASSERT( (Vicinity == HCELL_NIL) || (HvGetCellType(Vicinity) == (ULONG)Type) );
  704. //
  705. // we have the lock exclusive or nobody is operating inside this hive
  706. //
  707. //ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  708. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  709. if( (Vicinity != HCELL_NIL) && (CmHive->GrowOnlyMode == FALSE) ) {
  710. //
  711. // try first in this window
  712. //
  713. Cell = HvpFindFreeCellInThisViewWindow(Hive,Index,NewSize,Type,Vicinity);
  714. }
  715. if( Cell != HCELL_NIL ) {
  716. //
  717. // found it!!!
  718. //
  719. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"found cell %lx \n",Cell));
  720. return Cell;
  721. }
  722. /*
  723. //
  724. // Optimization:
  725. // Step 1 : Search first in the pinned views
  726. //
  727. CmHive = (PCMHIVE)CONTAINING_RECORD(Hive, CMHIVE, Hive);
  728. //
  729. // iterate through the pinned views
  730. //
  731. CmView = (PCM_VIEW_OF_FILE)CmHive->PinViewListHead.Flink;
  732. for(NrViews = CmHive->PinnedViews;NrViews;NrViews--) {
  733. CmView = CONTAINING_RECORD( CmView,
  734. CM_VIEW_OF_FILE,
  735. PinViewList);
  736. ASSERT( (CmView->FileOffset + CmView->Size) != 0 && (CmView->ViewAddress != 0));
  737. FileOffset = CmView->FileOffset;
  738. // adjust the offset
  739. if( FileOffset > 0 ) {
  740. FileOffset -= HBLOCK_SIZE;
  741. }
  742. //
  743. // search in this window
  744. //
  745. Cell = FileOffset + (Type*HCELL_TYPE_MASK);
  746. Cell = HvpFindFreeCellIn256kWindow(Hive,Index,NewSize,Type,Cell);
  747. if( Cell != HCELL_NIL ) {
  748. //
  749. // found it!
  750. //
  751. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"found cell %lx \n",Cell));
  752. return Cell;
  753. }
  754. CmView = (PCM_VIEW_OF_FILE)CmView->PinViewList.Flink;
  755. }
  756. //
  757. // Step 2: Search in the mapped views
  758. //
  759. CmView = (PCM_VIEW_OF_FILE)CmHive->LRUViewListHead.Flink;
  760. for(NrViews = CmHive->MappedViews;NrViews;NrViews--) {
  761. CmView = CONTAINING_RECORD( CmView,
  762. CM_VIEW_OF_FILE,
  763. LRUViewList);
  764. ASSERT( (CmView->FileOffset + CmView->Size) != 0 && (CmView->ViewAddress != 0));
  765. FileOffset = CmView->FileOffset;
  766. // adjust the offset
  767. if( FileOffset > 0 ) {
  768. FileOffset -= HBLOCK_SIZE;
  769. }
  770. //
  771. // search in this window
  772. //
  773. Cell = FileOffset + (Type*HCELL_TYPE_MASK);
  774. Cell = HvpFindFreeCellIn256kWindow(Hive,Index,NewSize,Type,Cell);
  775. if( Cell != HCELL_NIL ) {
  776. //
  777. // found it!
  778. //
  779. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"found cell %lx \n",Cell));
  780. return Cell;
  781. }
  782. CmView = (PCM_VIEW_OF_FILE)CmView->LRUViewList.Flink;
  783. }
  784. FileOffset = 0;
  785. */
  786. //
  787. // bad luck!; we did not found it in this window.
  788. // We have to search the entire hive
  789. //
  790. while( FileOffset < Hive->Storage[Type].Length ) {
  791. //
  792. // don't search again in the vicinity window
  793. // we already did it once
  794. //
  795. if( ( ((CmHive->GrowOnlyMode == FALSE) || (Type == Volatile)) &&
  796. ((Vicinity == HCELL_NIL) || (HvpCheckViewBoundary(FileOffset,Vicinity&(~HCELL_TYPE_MASK)) == FALSE)) ) ||
  797. ( (CmHive->GrowOnlyMode == TRUE) && (FileOffset >= CmHive->GrowOffset) )
  798. ) {
  799. //
  800. // search in this window
  801. //
  802. Cell = FileOffset + (Type*HCELL_TYPE_MASK);
  803. Cell = HvpFindFreeCellInThisViewWindow(Hive,Index,NewSize,Type,Cell);
  804. if( Cell != HCELL_NIL ) {
  805. //
  806. // found it!
  807. //
  808. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"found cell %lx \n",Cell));
  809. return Cell;
  810. }
  811. }
  812. //
  813. // advance to the new window
  814. //
  815. if( FileOffset == 0) {
  816. // account for the base block
  817. FileOffset += (CM_VIEW_SIZE - HBLOCK_SIZE);
  818. } else {
  819. FileOffset += CM_VIEW_SIZE;
  820. }
  821. }
  822. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"No cell found.\n"));
  823. return HCELL_NIL;
  824. }
  825. BOOLEAN
  826. HvpCheckViewBoundary(
  827. IN ULONG Start,
  828. IN ULONG End
  829. )
  830. /*++
  831. Routine Description:
  832. Checks if addresses are in the same CM_VIEW_SIZE boundary.
  833. We may convert this function to a macro for performance
  834. reasons
  835. Arguments:
  836. Start - starting address
  837. End - ending address
  838. Return Value:
  839. TRUE - yes, addresses are in the same view
  840. FALSE - no, addresses are NOT in the same view
  841. --*/
  842. {
  843. PAGED_CODE();
  844. //
  845. // account for the header
  846. //
  847. Start += HBLOCK_SIZE;
  848. End += HBLOCK_SIZE;
  849. //
  850. // truncate to the CM_VIEW_SIZE segment
  851. //
  852. Start &= (~(CM_VIEW_SIZE - 1));
  853. End &= (~(CM_VIEW_SIZE - 1));
  854. if( Start != End ){
  855. return FALSE;
  856. }
  857. return TRUE;
  858. }