Leaked source code of windows server 2003
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
30 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 PFREE_DISPLAY FreeDisplay
  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. PAGED_CODE();
  100. for( i=Stable;i<=Volatile;i++) {
  101. for (j = 0; j < HHIVE_FREE_DISPLAY_SIZE; j++) {
  102. if( Hive->Storage[i].FreeDisplay[j].Display.Buffer != NULL ) {
  103. ASSERT( Hive->Storage[i].FreeDisplay[j].RealVectorSize );
  104. (Hive->Free)(Hive->Storage[i].FreeDisplay[j].Display.Buffer,
  105. Hive->Storage[i].FreeDisplay[j].RealVectorSize);
  106. RtlInitializeBitMap(&(Hive->Storage[i].FreeDisplay[j].Display), NULL, 0);
  107. Hive->Storage[i].FreeDisplay[j].RealVectorSize = 0;
  108. }
  109. }
  110. }
  111. return;
  112. }
  113. NTSTATUS
  114. HvpAdjustBitmap(
  115. IN PHHIVE Hive,
  116. IN ULONG HiveLength,
  117. IN OUT PFREE_DISPLAY FreeDisplay
  118. )
  119. /*++
  120. Routine Description:
  121. When the length of the hive grows/shrinks, adjust the bitmap accordingly.
  122. - allocates a bitmap buffer large enough.
  123. - copies the relevant information from the old bitmap.
  124. Arguments:
  125. Hive - used for quota tracking.
  126. HiveLength - the new length of the hive.
  127. Bitmap - bitmap to operate on.
  128. Return Value:
  129. NTSTATUS code.
  130. --*/
  131. {
  132. ULONG VectorSize;
  133. ULONG NewBufferSize;
  134. ULONG OldBufferSize;
  135. PULONG Vector;
  136. PULONG OldVector;
  137. ULONG OldVectorSize;
  138. PRTL_BITMAP Bitmap;
  139. PAGED_CODE();
  140. Bitmap = &(FreeDisplay->Display);
  141. VectorSize = HiveLength / HBLOCK_SIZE; // Vector size == bits
  142. NewBufferSize = ROUND_UP_NOZERO( (VectorSize + 7) / 8,ROUND_INCREMENTS); // BufferSize == Bytes
  143. if( Bitmap->SizeOfBitMap == 0 ) {
  144. OldBufferSize = 0;
  145. } else {
  146. OldBufferSize = ROUND_UP_NOZERO( (Bitmap->SizeOfBitMap + 7) / 8, ROUND_INCREMENTS);
  147. }
  148. if( NewBufferSize <= FreeDisplay->RealVectorSize ) {
  149. //
  150. // We don't shrink the vector; next time we grow, we'll perform
  151. // the adjustments
  152. //
  153. //
  154. // Clear all the unused bits and return;
  155. //
  156. // we don't really need to do this as nobody will write in here
  157. // we'll drop it in the final implementation
  158. //
  159. OldVectorSize = Bitmap->SizeOfBitMap;
  160. //
  161. // set the new size
  162. //
  163. RtlInitializeBitMap(Bitmap,Bitmap->Buffer,VectorSize);
  164. if( OldVectorSize < VectorSize ) {
  165. RtlClearBits (Bitmap,OldVectorSize,VectorSize - OldVectorSize);
  166. }
  167. return STATUS_SUCCESS;
  168. }
  169. //
  170. // else, the bitmap has enlarged. Allocate a new buffer and copy the bits already set.
  171. //
  172. Vector = (PULONG)((Hive->Allocate)(NewBufferSize, TRUE,CM_FIND_LEAK_TAG39));
  173. if (Vector == NULL) {
  174. return STATUS_INSUFFICIENT_RESOURCES;
  175. }
  176. FreeDisplay->RealVectorSize = NewBufferSize;
  177. OldVector = Bitmap->Buffer;
  178. //CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"HvpAdjustBitmap: Old %lu :: %lu (%lx) New %lu :: %lu (%lx)\n",OldBufferSize,Bitmap->SizeOfBitMap,OldVector,NewBufferSize,VectorSize,Vector));
  179. RtlZeroMemory(Vector,NewBufferSize);
  180. RtlInitializeBitMap(Bitmap, Vector, VectorSize);
  181. if( OldVector != NULL ) {
  182. //
  183. // copy the already set bits
  184. //
  185. RtlCopyMemory (Vector,OldVector,OldBufferSize);
  186. //
  187. // Free the old vector
  188. //
  189. (Hive->Free)(OldVector, OldBufferSize);
  190. }
  191. return STATUS_SUCCESS;
  192. }
  193. VOID
  194. HvpAddFreeCellHint(
  195. PHHIVE Hive,
  196. HCELL_INDEX Cell,
  197. ULONG Index,
  198. HSTORAGE_TYPE Type
  199. )
  200. /*++
  201. Routine Description:
  202. Sets the corresponding bit in the bitmap
  203. Arguments:
  204. Hive - hive operating on
  205. Cell - free cell
  206. Index - index in FreeDisplay (based on the free cell size)
  207. Type - storage type (Stable or Volatile)
  208. Return Value:
  209. VOID
  210. --*/
  211. {
  212. ULONG BinIndex;
  213. PHMAP_ENTRY Me;
  214. PHBIN Bin;
  215. PAGED_CODE();
  216. Me = HvpGetCellMap(Hive, Cell);
  217. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  218. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  219. //
  220. // compute the bin index and for the begining of the bin
  221. //
  222. BinIndex = Bin->FileOffset / HBLOCK_SIZE;
  223. RtlSetBits (&(Hive->Storage[Type].FreeDisplay[Index].Display), BinIndex, Bin->Size / HBLOCK_SIZE);
  224. Hive->Storage[Type].FreeSummary |= (1 << Index);
  225. }
  226. VOID
  227. HvpRemoveFreeCellHint(
  228. PHHIVE Hive,
  229. HCELL_INDEX Cell,
  230. ULONG Index,
  231. HSTORAGE_TYPE Type
  232. )
  233. /*++
  234. Routine Description:
  235. Clears the corresponding bit in the bitmap
  236. Arguments:
  237. Hive - hive operating on
  238. Cell - free cell
  239. Index - index in FreeDisplay (based on the free cell size)
  240. Type - storage type (Stable or Volatile)
  241. Return Value:
  242. VOID
  243. --*/
  244. {
  245. ULONG BinIndex;
  246. ULONG TempIndex;
  247. PHMAP_ENTRY Me;
  248. PHBIN Bin;
  249. ULONG CellOffset;
  250. ULONG Size;
  251. PHCELL p;
  252. BOOLEAN CellFound = FALSE;
  253. PAGED_CODE();
  254. Me = HvpGetCellMap(Hive, Cell);
  255. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  256. Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
  257. CellOffset = Bin->FileOffset + sizeof(HBIN);
  258. #ifdef CM_MAP_NO_READ
  259. //
  260. // we ned to be protected against exception raised by the FS while faulting in data
  261. //
  262. try {
  263. #endif //CM_MAP_NO_READ
  264. //
  265. // There is a chance we can find a suitable free cell
  266. //
  267. p = (PHCELL)((PUCHAR)Bin + sizeof(HBIN));
  268. while (p < (PHCELL)((PUCHAR)Bin + Bin->Size)) {
  269. //
  270. // if free cell, check it out, add it to free list for hive
  271. //
  272. if (p->Size >= 0) {
  273. Size = (ULONG)p->Size;
  274. HvpComputeIndex(TempIndex, Size);
  275. if ((Index == TempIndex) && (CellOffset != (Cell&(~HCELL_TYPE_MASK)) )) {
  276. //
  277. // there is at least one free cell of this size (this one)
  278. // different than the one being delisted
  279. //
  280. CellFound = TRUE;
  281. break;
  282. }
  283. } else {
  284. //
  285. // used cell
  286. //
  287. Size = (ULONG)(p->Size * -1);
  288. }
  289. ASSERT( ((LONG)Size) >= 0);
  290. p = (PHCELL)((PUCHAR)p + Size);
  291. CellOffset += Size;
  292. }
  293. #ifdef CM_MAP_NO_READ
  294. } except (EXCEPTION_EXECUTE_HANDLER) {
  295. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpRemoveFreeCellHint: exception thrown ehile faulting in data, code:%08lx\n", GetExceptionCode()));
  296. //
  297. // better not use cells inthis range rather than leaving false hints
  298. //
  299. CellFound = FALSE;
  300. }
  301. #endif //CM_MAP_NO_READ
  302. if( CellFound == FALSE ) {
  303. //
  304. // no cell with this index was found
  305. // compute the bin index and for the begining of the bin
  306. //
  307. BinIndex = Bin->FileOffset / HBLOCK_SIZE;
  308. RtlClearBits (&(Hive->Storage[Type].FreeDisplay[Index].Display), BinIndex, Bin->Size / HBLOCK_SIZE);
  309. }
  310. if( RtlNumberOfSetBits(&(Hive->Storage[Type].FreeDisplay[Index].Display) ) != 0 ) {
  311. //
  312. // there are still some other free cells of this size
  313. //
  314. Hive->Storage[Type].FreeSummary |= (1 << Index);
  315. } else {
  316. //
  317. // entire bitmap is 0 (i.e. no other free cells of this size)
  318. //
  319. Hive->Storage[Type].FreeSummary &= (~(1 << Index));
  320. }
  321. }
  322. HCELL_INDEX
  323. HvpFindFreeCellInBin(
  324. PHHIVE Hive,
  325. ULONG Index,
  326. ULONG NewSize,
  327. HSTORAGE_TYPE Type,
  328. PHBIN Bin
  329. )
  330. /*++
  331. Routine Description:
  332. Lookup for a free cell with the size NewSize in this particular bin
  333. Arguments:
  334. Hive - target hive.
  335. Index - index in FreeDisplay (based on the free cell size)
  336. NewSize - desired size
  337. Type - storage type (Stable or Volatile)
  338. Bin - Bin in question
  339. Return Value:
  340. A free cellindex with a size bigger than NewSize, or HCELL_NIL
  341. --*/
  342. {
  343. ULONG BinIndex;
  344. ULONG CellOffset;
  345. PHCELL p;
  346. ULONG BinOffset;
  347. ULONG Size;
  348. HCELL_INDEX cellindex;
  349. ULONG FoundCellIndex;
  350. PAGED_CODE();
  351. BinOffset = Bin->FileOffset;
  352. BinIndex = BinOffset/HBLOCK_SIZE;
  353. if( RtlCheckBit(&(Hive->Storage[Type].FreeDisplay[Index].Display), BinIndex) == 0 ) {
  354. //
  355. // no hint for this bin
  356. //
  357. return HCELL_NIL;
  358. }
  359. CellOffset = sizeof(HBIN);
  360. #ifdef CM_MAP_NO_READ
  361. //
  362. // we ned to be protected against exception raised by the FS while faulting in data
  363. //
  364. try {
  365. #endif //CM_MAP_NO_READ
  366. //
  367. // There is a chance we can find a suitable free cell
  368. //
  369. p = (PHCELL)((PUCHAR)Bin + sizeof(HBIN));
  370. while (p < (PHCELL)((PUCHAR)Bin + Bin->Size)) {
  371. //
  372. // if free cell, check it out, add it to free list for hive
  373. //
  374. if (p->Size >= 0) {
  375. Size = (ULONG)p->Size;
  376. //
  377. // cell is free, and is not obviously corrupt, add to free list
  378. //
  379. CellOffset = (ULONG)((PUCHAR)p - (PUCHAR)Bin);
  380. cellindex = BinOffset + CellOffset + (Type*HCELL_TYPE_MASK);
  381. if (NewSize <= (ULONG)Size) {
  382. //
  383. // Found a big enough cell.
  384. //
  385. HvpComputeIndex(FoundCellIndex, Size);
  386. if( Index == FoundCellIndex ) {
  387. //
  388. // and enlisted at the same index (we want to avoid fragmentation if possible!)
  389. //
  390. if (! HvMarkCellDirty(Hive, cellindex)) {
  391. return HCELL_NIL;
  392. }
  393. HvpDelistFreeCell(Hive, cellindex, Type);
  394. ASSERT(p->Size > 0);
  395. ASSERT(NewSize <= (ULONG)p->Size);
  396. return cellindex;
  397. }
  398. }
  399. } else {
  400. //
  401. // used cell
  402. //
  403. Size = (ULONG)(p->Size * -1);
  404. }
  405. ASSERT( ((LONG)Size) >= 0);
  406. p = (PHCELL)((PUCHAR)p + Size);
  407. }
  408. #ifdef CM_MAP_NO_READ
  409. } except (EXCEPTION_EXECUTE_HANDLER) {
  410. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvpFindFreeCellInBin: exception thrown ehile faulting in data, code:%08lx\n", GetExceptionCode()));
  411. return HCELL_NIL;
  412. }
  413. #endif //CM_MAP_NO_READ
  414. //
  415. // no free cell matching this size on this bin ; We did all this work for nothing!
  416. //
  417. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"[HvpFindFreeCellInBin] (Offset,Size) = (%lx,%lx) ==> No Match\n",BinOffset,Bin->Size));
  418. return HCELL_NIL;
  419. }
  420. HCELL_INDEX
  421. HvpScanForFreeCellInViewWindow(
  422. PHHIVE Hive,
  423. ULONG Index,
  424. ULONG NewSize,
  425. HSTORAGE_TYPE Type,
  426. HCELL_INDEX FileOffsetStart
  427. )
  428. /*++
  429. Routine Description:
  430. Lookup for a free cell with the size NewSize in the CM_VIEW_SIZE window defined by
  431. Vicinity.
  432. If it doesn't find a free cell for the specifed index, tries with the
  433. Arguments:
  434. Hive - target hive.
  435. Index - index in FreeDisplay (based on the free cell size)
  436. NewSize - desired size
  437. Type - storage type (Stable or Volatile)
  438. Vicinity - defines the window; it is never HCELL_NIL !!!
  439. Return Value:
  440. A free cellindex with a size bigger than NewSize, or HCELL_NIL
  441. Note:
  442. Vicinity is a physical file offset at this point. we need to
  443. convert it to a logical one prior to accessing the map
  444. --*/
  445. {
  446. ULONG FileOffsetEnd;
  447. HCELL_INDEX Cell;
  448. PHMAP_ENTRY Me;
  449. PHBIN Bin;
  450. PFREE_HBIN FreeBin;
  451. ULONG BinFileOffset;
  452. ULONG BinSize;
  453. PAGED_CODE();
  454. FileOffsetEnd = FileOffsetStart + CM_VIEW_SIZE;
  455. FileOffsetEnd -= HBLOCK_SIZE;
  456. if( FileOffsetStart != 0 ) {
  457. FileOffsetStart -= HBLOCK_SIZE;
  458. }
  459. if( FileOffsetEnd > Hive->Storage[Type].Length ) {
  460. FileOffsetEnd = Hive->Storage[Type].Length;
  461. }
  462. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FREECELL,"\t[HvpScanForFreeCellInViewWindow] (Start,End) = (%lx,%lx) Size = %lx\n",FileOffsetStart,FileOffsetEnd,Hive->Storage[Type].Length));
  463. //
  464. // sanity ASSERT
  465. //
  466. ASSERT( FileOffsetStart < FileOffsetEnd );
  467. //
  468. // the caller already checked for this; remember, hints are for real!
  469. //
  470. ASSERT( !RtlAreBitsClear( &(Hive->Storage[Type].FreeDisplay[Index].Display),
  471. 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].Display),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. }